xref: /reactos/dll/win32/imm32/compstr.c (revision 89846a29)
1 /*
2  * PROJECT:     ReactOS IMM32
3  * LICENSE:     LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
4  * PURPOSE:     Implementing composition strings of IMM32
5  * COPYRIGHT:   Copyright 1998 Patrik Stridvall
6  *              Copyright 2002, 2003, 2007 CodeWeavers, Aric Stewart
7  *              Copyright 2017 James Tabor <james.tabor@reactos.org>
8  *              Copyright 2018 Amine Khaldi <amine.khaldi@reactos.org>
9  *              Copyright 2020-2021 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
10  */
11 
12 #include "precomp.h"
13 
14 WINE_DEFAULT_DEBUG_CHANNEL(imm);
15 
16 BOOL APIENTRY
17 Imm32OpenICAndCS(HIMC hIMC, LPINPUTCONTEXT *ppIC, LPCOMPOSITIONSTRING *ppCS)
18 {
19     LPINPUTCONTEXT pIC;
20     LPCOMPOSITIONSTRING pCS;
21 
22     *ppIC = NULL;
23     *ppCS = NULL;
24 
25     pIC = ImmLockIMC(hIMC);
26     if (!pIC)
27         return FALSE;
28 
29     pCS = ImmLockIMCC(pIC->hCompStr);
30     if (!pCS)
31     {
32         ImmUnlockIMC(hIMC);
33         return FALSE;
34     }
35 
36     *ppIC = pIC;
37     *ppCS = pCS;
38     return TRUE;
39 }
40 
41 static inline LONG APIENTRY
42 Imm32CompStrAnsiToWide(LPCSTR psz, DWORD cb, LPWSTR lpBuf, DWORD dwBufLen, UINT uCodePage)
43 {
44     DWORD ret = MultiByteToWideChar(uCodePage, MB_PRECOMPOSED, psz, cb / sizeof(CHAR),
45                                     lpBuf, dwBufLen / sizeof(WCHAR));
46     if (lpBuf && (ret + 1) * sizeof(WCHAR) <= dwBufLen)
47         lpBuf[ret] = 0;
48     return ret * sizeof(WCHAR);
49 }
50 
51 static inline LONG APIENTRY
52 Imm32CompStrWideToAnsi(LPCWSTR psz, DWORD cb, LPSTR lpBuf, DWORD dwBufLen, UINT uCodePage)
53 {
54     DWORD ret = WideCharToMultiByte(uCodePage, 0, psz, cb / sizeof(WCHAR),
55                                     lpBuf, dwBufLen / sizeof(CHAR), NULL, NULL);
56     if (lpBuf && (ret + 1) * sizeof(CHAR) <= dwBufLen)
57         lpBuf[ret] = 0;
58     return ret * sizeof(CHAR);
59 }
60 
61 static INT APIENTRY
62 Imm32CompAttrWideToAnsi(const BYTE *src, INT src_len, LPCWSTR text,
63                         INT str_len, LPBYTE dst, INT dst_len, UINT uCodePage)
64 {
65     INT rc;
66     INT i, j = 0, k = 0, len;
67 
68     if (!src_len)
69         return 0;
70 
71     str_len /= sizeof(WCHAR);
72     rc = WideCharToMultiByte(uCodePage, 0, text, str_len, NULL, 0, NULL, NULL);
73 
74     if (dst_len)
75     {
76         if (dst_len > rc)
77             dst_len = rc;
78 
79         for (i = 0; i < str_len; ++i, ++k)
80         {
81             len = WideCharToMultiByte(uCodePage, 0, &text[i], 1, NULL, 0, NULL, NULL);
82             for (; len > 0; --len)
83             {
84                 dst[j++] = src[k];
85 
86                 if (dst_len <= j)
87                     goto end;
88             }
89         }
90 end:
91         rc = j;
92     }
93 
94     return rc * sizeof(BYTE);
95 }
96 
97 static INT APIENTRY
98 Imm32CompAttrAnsiToWide(const BYTE *src, INT src_len, LPCSTR text,
99                         INT str_len, LPBYTE dst, INT dst_len, UINT uCodePage)
100 {
101     INT rc;
102     INT i, j = 0;
103 
104     if (!src_len)
105         return 0;
106 
107     str_len /= sizeof(CHAR);
108     rc = MultiByteToWideChar(uCodePage, MB_PRECOMPOSED, text, str_len, NULL, 0);
109 
110     if (dst_len)
111     {
112         if (dst_len > rc)
113             dst_len = rc;
114 
115         for (i = 0; i < str_len; ++i)
116         {
117             if (IsDBCSLeadByteEx(uCodePage, text[i]) && text[i + 1])
118                 continue;
119 
120             dst[j++] = src[i];
121 
122             if (dst_len <= j)
123                 break;
124         }
125 
126         rc = j;
127     }
128 
129     return rc * sizeof(BYTE);
130 }
131 
132 static INT APIENTRY
133 Imm32CompClauseAnsiToWide(const DWORD *source, INT slen, LPCSTR text,
134                           LPDWORD target, INT tlen, UINT uCodePage)
135 {
136     INT rc, i;
137 
138     if (!slen)
139         return 0;
140 
141     if (tlen)
142     {
143         if (tlen > slen)
144             tlen = slen;
145 
146         tlen /= sizeof(DWORD);
147 
148         for (i = 0; i < tlen; ++i)
149         {
150             target[i] = MultiByteToWideChar(uCodePage, MB_PRECOMPOSED, text, source[i], NULL, 0);
151         }
152 
153         rc = sizeof(DWORD) * i;
154     }
155     else
156     {
157         rc = slen;
158     }
159 
160     return rc;
161 }
162 
163 static INT APIENTRY
164 Imm32CompClauseWideToAnsi(const DWORD *source, INT slen, LPCWSTR text,
165                           LPDWORD target, INT tlen, UINT uCodePage)
166 {
167     INT rc, i;
168 
169     if (!slen)
170         return 0;
171 
172     if (tlen)
173     {
174         if (tlen > slen)
175             tlen = slen;
176 
177         tlen /= sizeof(DWORD);
178 
179         for (i = 0; i < tlen; ++i)
180         {
181             target[i] = WideCharToMultiByte(uCodePage, 0, text, source[i], NULL, 0, NULL, NULL);
182         }
183 
184         rc = sizeof(DWORD) * i;
185     }
186     else
187     {
188         rc = slen;
189     }
190 
191     return rc;
192 }
193 
194 #define CS_StrA(pCS, Name)      ((LPCSTR)(pCS) + (pCS)->dw##Name##Offset)
195 #define CS_StrW(pCS, Name)      ((LPCWSTR)CS_StrA(pCS, Name))
196 #define CS_Attr(pCS, Name)      ((const BYTE *)CS_StrA(pCS, Name))
197 #define CS_Clause(pCS, Name)    ((const DWORD *)CS_StrA(pCS, Name))
198 #define CS_Size(pCS, Name)      ((pCS)->dw##Name##Len)
199 #define CS_SizeA(pCS, Name)     (CS_Size(pCS, Name) * sizeof(CHAR))
200 #define CS_SizeW(pCS, Name)     (CS_Size(pCS, Name) * sizeof(WCHAR))
201 
202 #define CS_DoStr(pCS, Name, AorW) do { \
203     if (dwBufLen == 0) { \
204         dwBufLen = CS_Size##AorW((pCS), Name); \
205     } else { \
206         if (dwBufLen > CS_Size##AorW((pCS), Name)) \
207             dwBufLen = CS_Size##AorW((pCS), Name); \
208         RtlCopyMemory(lpBuf, CS_Str##AorW((pCS), Name), dwBufLen); \
209     } \
210 } while (0)
211 
212 #define CS_DoStrA(pCS, Name) CS_DoStr(pCS, Name, A)
213 #define CS_DoStrW(pCS, Name) CS_DoStr(pCS, Name, W)
214 #define CS_DoAttr CS_DoStrA
215 #define CS_DoClause CS_DoStrA
216 
217 LONG APIENTRY
218 Imm32GetCompStrA(HIMC hIMC, const COMPOSITIONSTRING *pCS, DWORD dwIndex,
219                  LPVOID lpBuf, DWORD dwBufLen, BOOL bAnsiClient, UINT uCodePage)
220 {
221     if (bAnsiClient)
222     {
223         switch (dwIndex)
224         {
225             case GCS_COMPREADSTR:
226                 CS_DoStrA(pCS, CompReadStr);
227                 break;
228 
229             case GCS_COMPREADATTR:
230                 CS_DoAttr(pCS, CompReadAttr);
231                 break;
232 
233             case GCS_COMPREADCLAUSE:
234                 CS_DoClause(pCS, CompReadClause);
235                 break;
236 
237             case GCS_COMPSTR:
238                 CS_DoStrA(pCS, CompStr);
239                 break;
240 
241             case GCS_COMPATTR:
242                 CS_DoAttr(pCS, CompAttr);
243                 break;
244 
245             case GCS_COMPCLAUSE:
246                 CS_DoClause(pCS, CompClause);
247                 break;
248 
249             case GCS_CURSORPOS:
250                 dwBufLen = pCS->dwCursorPos;
251                 break;
252 
253             case GCS_DELTASTART:
254                 dwBufLen = pCS->dwDeltaStart;
255                 break;
256 
257             case GCS_RESULTREADSTR:
258                 CS_DoStrA(pCS, ResultReadStr);
259                 break;
260 
261             case GCS_RESULTREADCLAUSE:
262                 CS_DoClause(pCS, ResultReadClause);
263                 break;
264 
265             case GCS_RESULTSTR:
266                 CS_DoStrA(pCS, ResultStr);
267                 break;
268 
269             case GCS_RESULTCLAUSE:
270                 CS_DoClause(pCS, ResultClause);
271                 break;
272 
273             default:
274                 FIXME("TODO:\n");
275                 return IMM_ERROR_GENERAL;
276         }
277     }
278     else /* !bAnsiClient */
279     {
280         switch (dwIndex)
281         {
282             case GCS_COMPREADSTR:
283                 dwBufLen = Imm32CompStrWideToAnsi(CS_StrW(pCS, CompReadStr),
284                                                   CS_SizeW(pCS, CompReadStr),
285                                                   lpBuf, dwBufLen, uCodePage);
286                 break;
287 
288             case GCS_COMPREADATTR:
289                 dwBufLen = Imm32CompAttrWideToAnsi(CS_Attr(pCS, CompReadAttr),
290                                                    CS_Size(pCS, CompReadAttr),
291                                                    CS_StrW(pCS, CompStr),
292                                                    CS_SizeW(pCS, CompStr),
293                                                    lpBuf, dwBufLen, uCodePage);
294                 break;
295 
296             case GCS_COMPREADCLAUSE:
297                 dwBufLen = Imm32CompClauseWideToAnsi(CS_Clause(pCS, CompReadClause),
298                                                      CS_Size(pCS, CompReadClause),
299                                                      CS_StrW(pCS, CompStr),
300                                                      lpBuf, dwBufLen, uCodePage);
301                 break;
302 
303             case GCS_COMPSTR:
304                 dwBufLen = Imm32CompStrWideToAnsi(CS_StrW(pCS, CompStr),
305                                                   CS_SizeW(pCS, CompStr),
306                                                   lpBuf, dwBufLen, uCodePage);
307                 break;
308 
309             case GCS_COMPATTR:
310                 dwBufLen = Imm32CompAttrWideToAnsi(CS_Attr(pCS, CompAttr),
311                                                    CS_Size(pCS, CompAttr),
312                                                    CS_StrW(pCS, CompStr),
313                                                    CS_SizeW(pCS, CompStr),
314                                                    lpBuf, dwBufLen, uCodePage);
315                 break;
316 
317             case GCS_COMPCLAUSE:
318                 dwBufLen = Imm32CompClauseWideToAnsi(CS_Clause(pCS, CompClause),
319                                                      CS_Size(pCS, CompClause),
320                                                      CS_StrW(pCS, CompStr),
321                                                      lpBuf, dwBufLen, uCodePage);
322                 break;
323 
324             case GCS_CURSORPOS:
325                 dwBufLen = IchAnsiFromWide(pCS->dwCursorPos, CS_StrW(pCS, CompStr), uCodePage);
326                 break;
327 
328             case GCS_DELTASTART:
329                 dwBufLen = IchAnsiFromWide(pCS->dwDeltaStart, CS_StrW(pCS, CompStr), uCodePage);
330                 break;
331 
332             case GCS_RESULTREADSTR:
333                 dwBufLen = Imm32CompStrWideToAnsi(CS_StrW(pCS, ResultReadStr),
334                                                   CS_SizeW(pCS, ResultReadStr),
335                                                   lpBuf, dwBufLen, uCodePage);
336                 break;
337 
338             case GCS_RESULTREADCLAUSE:
339                 dwBufLen = Imm32CompClauseWideToAnsi(CS_Clause(pCS, ResultReadClause),
340                                                      CS_Size(pCS, ResultReadClause),
341                                                      CS_StrW(pCS, CompStr),
342                                                      lpBuf, dwBufLen, uCodePage);
343                 break;
344 
345             case GCS_RESULTSTR:
346                 dwBufLen = Imm32CompStrWideToAnsi(CS_StrW(pCS, ResultStr),
347                                                   CS_SizeW(pCS, ResultStr),
348                                                   lpBuf, dwBufLen, uCodePage);
349                 break;
350 
351             case GCS_RESULTCLAUSE:
352                 dwBufLen = Imm32CompClauseWideToAnsi(CS_Clause(pCS, ResultClause),
353                                                      CS_Size(pCS, ResultClause),
354                                                      CS_StrW(pCS, CompStr),
355                                                      lpBuf, dwBufLen, uCodePage);
356                 break;
357 
358             default:
359                 FIXME("TODO:\n");
360                 return IMM_ERROR_GENERAL;
361         }
362     }
363 
364     return dwBufLen;
365 }
366 
367 LONG APIENTRY
368 Imm32GetCompStrW(HIMC hIMC, const COMPOSITIONSTRING *pCS, DWORD dwIndex,
369                  LPVOID lpBuf, DWORD dwBufLen, BOOL bAnsiClient, UINT uCodePage)
370 {
371     if (bAnsiClient)
372     {
373         switch (dwIndex)
374         {
375             case GCS_COMPREADSTR:
376                 dwBufLen = Imm32CompStrAnsiToWide(CS_StrA(pCS, CompReadStr),
377                                                   CS_SizeA(pCS, CompReadStr),
378                                                   lpBuf, dwBufLen, uCodePage);
379                 break;
380 
381             case GCS_COMPREADATTR:
382                 dwBufLen = Imm32CompAttrAnsiToWide(CS_Attr(pCS, CompReadAttr),
383                                                    CS_Size(pCS, CompReadAttr),
384                                                    CS_StrA(pCS, CompStr), CS_SizeA(pCS, CompStr),
385                                                    lpBuf, dwBufLen, uCodePage);
386                 break;
387 
388             case GCS_COMPREADCLAUSE:
389                 dwBufLen = Imm32CompClauseAnsiToWide(CS_Clause(pCS, CompReadClause),
390                                                      CS_Size(pCS, CompReadClause),
391                                                      CS_StrA(pCS, CompStr),
392                                                      lpBuf, dwBufLen, uCodePage);
393                 break;
394 
395             case GCS_COMPSTR:
396                 dwBufLen = Imm32CompStrAnsiToWide(CS_StrA(pCS, CompStr),
397                                                   CS_SizeA(pCS, CompStr),
398                                                   lpBuf, dwBufLen, uCodePage);
399                 break;
400 
401             case GCS_COMPATTR:
402                 dwBufLen = Imm32CompAttrAnsiToWide(CS_Attr(pCS, CompAttr),
403                                                    CS_Size(pCS, CompAttr),
404                                                    CS_StrA(pCS, CompStr), CS_SizeA(pCS, CompStr),
405                                                    lpBuf, dwBufLen, uCodePage);
406                 break;
407 
408             case GCS_COMPCLAUSE:
409                 dwBufLen = Imm32CompClauseAnsiToWide(CS_Clause(pCS, CompClause),
410                                                      CS_Size(pCS, CompClause),
411                                                      CS_StrA(pCS, CompStr),
412                                                      lpBuf, dwBufLen, uCodePage);
413                 break;
414 
415             case GCS_CURSORPOS:
416                 dwBufLen = IchWideFromAnsi(pCS->dwCursorPos, CS_StrA(pCS, CompStr), uCodePage);
417                 break;
418 
419             case GCS_DELTASTART:
420                 dwBufLen = IchWideFromAnsi(pCS->dwDeltaStart, CS_StrA(pCS, CompStr), uCodePage);
421                 break;
422 
423             case GCS_RESULTREADSTR:
424                 dwBufLen = Imm32CompStrAnsiToWide(CS_StrA(pCS, ResultReadStr),
425                                                   CS_SizeA(pCS, ResultReadStr),
426                                                   lpBuf, dwBufLen, uCodePage);
427                 break;
428 
429             case GCS_RESULTREADCLAUSE:
430                 dwBufLen = Imm32CompClauseAnsiToWide(CS_Clause(pCS, ResultReadClause),
431                                                      CS_Size(pCS, ResultReadClause),
432                                                      CS_StrA(pCS, CompStr),
433                                                      lpBuf, dwBufLen, uCodePage);
434                 break;
435 
436             case GCS_RESULTSTR:
437                 dwBufLen = Imm32CompStrAnsiToWide(CS_StrA(pCS, ResultStr),
438                                                   CS_SizeA(pCS, ResultStr),
439                                                   lpBuf, dwBufLen, uCodePage);
440                 break;
441 
442             case GCS_RESULTCLAUSE:
443                 dwBufLen = Imm32CompClauseAnsiToWide(CS_Clause(pCS, ResultClause),
444                                                      CS_Size(pCS, ResultClause),
445                                                      CS_StrA(pCS, CompStr),
446                                                      lpBuf, dwBufLen, uCodePage);
447                 break;
448 
449             default:
450                 FIXME("TODO:\n");
451                 return IMM_ERROR_GENERAL;
452         }
453     }
454     else /* !bAnsiClient */
455     {
456         switch (dwIndex)
457         {
458             case GCS_COMPREADSTR:
459                 CS_DoStrW(pCS, CompReadStr);
460                 break;
461 
462             case GCS_COMPREADATTR:
463                 CS_DoAttr(pCS, CompReadAttr);
464                 break;
465 
466             case GCS_COMPREADCLAUSE:
467                 CS_DoClause(pCS, CompReadClause);
468                 break;
469 
470             case GCS_COMPSTR:
471                 CS_DoStrW(pCS, CompStr);
472                 break;
473 
474             case GCS_COMPATTR:
475                 CS_DoAttr(pCS, CompAttr);
476                 break;
477 
478             case GCS_COMPCLAUSE:
479                 CS_DoClause(pCS, CompClause);
480                 break;
481 
482             case GCS_CURSORPOS:
483                 dwBufLen = pCS->dwCursorPos;
484                 break;
485 
486             case GCS_DELTASTART:
487                 dwBufLen = pCS->dwDeltaStart;
488                 break;
489 
490             case GCS_RESULTREADSTR:
491                 CS_DoStrW(pCS, ResultReadStr);
492                 break;
493 
494             case GCS_RESULTREADCLAUSE:
495                 CS_DoClause(pCS, ResultReadClause);
496                 break;
497 
498             case GCS_RESULTSTR:
499                 CS_DoStrW(pCS, ResultStr);
500                 break;
501 
502             case GCS_RESULTCLAUSE:
503                 CS_DoClause(pCS, ResultClause);
504                 break;
505 
506             default:
507                 FIXME("TODO:\n");
508                 return IMM_ERROR_GENERAL;
509         }
510     }
511 
512     return dwBufLen;
513 }
514 
515 // Win: ImmSetCompositionStringWorker
516 BOOL APIENTRY
517 ImmSetCompositionStringAW(HIMC hIMC, DWORD dwIndex, LPVOID pComp, DWORD dwCompLen,
518                           LPVOID pRead, DWORD dwReadLen, BOOL bAnsiAPI)
519 {
520     BOOL ret = FALSE, bAnsiClient;
521     LPVOID pCompNew = NULL, pReadNew = NULL;
522     DWORD dwThreadId, cbCompNew = 0, cbReadNew = 0;
523     LPINPUTCONTEXT pIC;
524     LPCOMPOSITIONSTRING pCS;
525     HKL hKL;
526     PIMEDPI pImeDpi;
527     UINT uCodePage;
528     LPRECONVERTSTRING pRS;
529 
530     dwThreadId = (DWORD)NtUserQueryInputContext(hIMC, QIC_INPUTTHREADID);
531     if (dwThreadId != GetCurrentThreadId())
532         return FALSE;
533 
534     hKL = GetKeyboardLayout(dwThreadId);
535     pImeDpi = ImmLockImeDpi(hKL);
536     if (!pImeDpi)
537         return FALSE;
538 
539     uCodePage = pImeDpi->uCodePage;
540     bAnsiClient = !ImeDpi_IsUnicode(pImeDpi);
541 
542     switch (dwIndex)
543     {
544         case SCS_SETSTR: case SCS_CHANGEATTR: case SCS_CHANGECLAUSE:
545             break;
546 
547         case SCS_SETRECONVERTSTRING: case SCS_QUERYRECONVERTSTRING:
548             if (pImeDpi->ImeInfo.fdwSCSCaps & SCS_CAP_SETRECONVERTSTRING)
549                 break;
550             /* FALL THROUGH */
551         default:
552             ImmUnlockImeDpi(pImeDpi);
553             return FALSE;
554     }
555 
556     if (bAnsiAPI == bAnsiClient || (!pComp && !pRead))
557     {
558         ret = pImeDpi->ImeSetCompositionString(hIMC, dwIndex, pComp, dwCompLen,
559                                                pRead, dwReadLen);
560         ImmUnlockImeDpi(pImeDpi);
561         return ret;
562     }
563 
564     if (!Imm32OpenICAndCS(hIMC, &pIC, &pCS))
565     {
566         ImmUnlockImeDpi(pImeDpi);
567         return FALSE;
568     }
569 
570     /*
571      * This code is really too complicated. But I cannot simplify.
572      * It converts like (pComp, dwCompLen) --> (pCompNew, cbCompNew) and
573      * (pRead, dwReadLen) --> (pReadNew, cbReadNew).
574      * (1) Check bAnsiClient, (2) Get the size, (3) Allocate a buffer for conversion,
575      * (4) Store converted data into the buffer.
576      */
577     switch (dwIndex)
578     {
579         case SCS_SETSTR:
580             if (pComp)
581             {
582                 if (bAnsiClient)
583                 {
584                     cbCompNew = Imm32CompStrWideToAnsi(pComp, dwCompLen, NULL, 0, uCodePage);
585                     pCompNew = ImmLocalAlloc(0, cbCompNew);
586                     if (!pCompNew)
587                         goto Quit;
588 
589                     Imm32CompStrWideToAnsi(pComp, dwCompLen, pCompNew, cbCompNew, uCodePage);
590                 }
591                 else
592                 {
593                     cbCompNew = Imm32CompStrAnsiToWide(pComp, dwCompLen, NULL, 0, uCodePage);
594                     pCompNew = ImmLocalAlloc(0, cbCompNew);
595                     if (!pCompNew)
596                         goto Quit;
597 
598                     Imm32CompStrAnsiToWide(pComp, dwCompLen, pCompNew, cbCompNew, uCodePage);
599                 }
600             }
601 
602             if (pRead)
603             {
604                 if (bAnsiClient)
605                 {
606                     cbReadNew = Imm32CompStrWideToAnsi(pRead, dwReadLen, NULL, 0, uCodePage);
607                     pReadNew = ImmLocalAlloc(0, cbReadNew);
608                     if (!pReadNew)
609                         goto Quit;
610 
611                     Imm32CompStrWideToAnsi(pRead, dwReadLen, pReadNew, cbReadNew, uCodePage);
612                 }
613                 else
614                 {
615                     cbReadNew = Imm32CompStrAnsiToWide(pRead, dwReadLen, NULL, 0, uCodePage);
616                     pReadNew = ImmLocalAlloc(0, cbReadNew);
617                     if (!pReadNew)
618                         goto Quit;
619 
620                     Imm32CompStrAnsiToWide(pRead, dwReadLen, pReadNew, cbReadNew, uCodePage);
621                 }
622             }
623             break;
624 
625         case SCS_CHANGEATTR:
626             if (pComp)
627             {
628                 if (bAnsiClient)
629                 {
630                     cbCompNew = Imm32CompAttrWideToAnsi(pComp, dwCompLen,
631                                                         CS_StrW(pCS, CompStr),
632                                                         CS_SizeW(pCS, CompStr),
633                                                         NULL, 0, uCodePage);
634                     pCompNew = ImmLocalAlloc(0, cbCompNew);
635                     if (!pCompNew)
636                         goto Quit;
637 
638                     Imm32CompAttrWideToAnsi(pComp, dwCompLen,
639                                             CS_StrW(pCS, CompStr), CS_SizeW(pCS, CompStr),
640                                             pCompNew, cbCompNew, uCodePage);
641                 }
642                 else
643                 {
644                     cbCompNew = Imm32CompAttrAnsiToWide(pComp, dwCompLen,
645                                                         CS_StrA(pCS, CompStr),
646                                                         CS_SizeA(pCS, CompStr),
647                                                         NULL, 0, uCodePage);
648                     pCompNew = ImmLocalAlloc(0, cbCompNew);
649                     if (!pCompNew)
650                         goto Quit;
651 
652                     Imm32CompAttrAnsiToWide(pComp, dwCompLen,
653                                             CS_StrA(pCS, CompStr), CS_SizeA(pCS, CompStr),
654                                             pCompNew, cbCompNew, uCodePage);
655                 }
656             }
657 
658             if (pRead)
659             {
660                 if (bAnsiClient)
661                 {
662                     cbReadNew = Imm32CompAttrWideToAnsi(pRead, dwReadLen,
663                                                         CS_StrW(pCS, CompReadStr),
664                                                         CS_SizeW(pCS, CompReadStr),
665                                                         NULL, 0, uCodePage);
666                     pReadNew = ImmLocalAlloc(0, cbReadNew);
667                     if (!pReadNew)
668                         goto Quit;
669 
670                     Imm32CompAttrWideToAnsi(pRead, dwReadLen,
671                                             CS_StrW(pCS, CompReadStr), CS_SizeW(pCS, CompReadStr),
672                                             pReadNew, cbReadNew, uCodePage);
673                 }
674                 else
675                 {
676                     cbReadNew = Imm32CompAttrAnsiToWide(pRead, dwReadLen,
677                                                         CS_StrA(pCS, CompReadStr),
678                                                         CS_SizeA(pCS, CompReadStr),
679                                                         NULL, 0, uCodePage);
680                     pReadNew = ImmLocalAlloc(0, cbReadNew);
681                     if (!pReadNew)
682                         goto Quit;
683 
684                     Imm32CompAttrAnsiToWide(pRead, dwReadLen,
685                                             CS_StrA(pCS, CompReadStr), CS_SizeA(pCS, CompReadStr),
686                                             pReadNew, cbReadNew, uCodePage);
687                 }
688             }
689             break;
690 
691         case SCS_CHANGECLAUSE:
692             if (pComp)
693             {
694                 if (bAnsiClient)
695                 {
696                     cbCompNew = Imm32CompClauseWideToAnsi(pComp, dwCompLen, CS_StrW(pCS, CompStr),
697                                                           NULL, 0, uCodePage);
698                     pCompNew = ImmLocalAlloc(0, cbCompNew);
699                     if (!pCompNew)
700                         goto Quit;
701 
702                     Imm32CompClauseWideToAnsi(pComp, dwCompLen, CS_StrW(pCS, CompStr),
703                                               pCompNew, cbCompNew, uCodePage);
704                 }
705                 else
706                 {
707                     cbCompNew = Imm32CompClauseAnsiToWide(pComp, dwCompLen, CS_StrA(pCS, CompStr),
708                                                           NULL, 0, uCodePage);
709                     pCompNew = ImmLocalAlloc(0, cbCompNew);
710                     if (!pCompNew)
711                         goto Quit;
712 
713                     Imm32CompClauseAnsiToWide(pComp, dwCompLen, CS_StrA(pCS, CompStr),
714                                               pCompNew, cbCompNew, uCodePage);
715                 }
716             }
717 
718             if (pRead)
719             {
720                 if (bAnsiClient)
721                 {
722                     cbReadNew = Imm32CompClauseWideToAnsi(pRead, dwReadLen, CS_StrW(pCS, CompReadStr),
723                                                           NULL, 0, uCodePage);
724                     pReadNew = ImmLocalAlloc(0, cbReadNew);
725                     if (!pReadNew)
726                         goto Quit;
727 
728                     Imm32CompClauseWideToAnsi(pRead, dwReadLen,
729                                               CS_StrW(pCS, CompReadStr),
730                                               pReadNew, cbReadNew, uCodePage);
731                 }
732                 else
733                 {
734                     cbReadNew = Imm32CompClauseAnsiToWide(pRead, dwReadLen, CS_StrA(pCS, CompReadStr),
735                                                           NULL, 0, uCodePage);
736                     pReadNew = ImmLocalAlloc(0, cbReadNew);
737                     if (!pReadNew)
738                         goto Quit;
739 
740                     Imm32CompClauseAnsiToWide(pRead, dwReadLen, CS_StrA(pCS, CompReadStr),
741                                               pReadNew, cbReadNew, uCodePage);
742                 }
743             }
744             break;
745 
746         case SCS_SETRECONVERTSTRING: case SCS_QUERYRECONVERTSTRING:
747         {
748             if (pComp)
749             {
750                 if (bAnsiClient)
751                 {
752                     cbCompNew = Imm32ReconvertAnsiFromWide(NULL, pComp, uCodePage);
753                     pCompNew = ImmLocalAlloc(0, cbCompNew);
754                     if (!pCompNew)
755                         goto Quit;
756 
757                     pRS = pCompNew;
758                     pRS->dwSize = cbCompNew;
759                     pRS->dwVersion = 0;
760                     Imm32ReconvertAnsiFromWide(pRS, pComp, uCodePage);
761                 }
762                 else
763                 {
764                     cbCompNew = Imm32ReconvertWideFromAnsi(NULL, pComp, uCodePage);
765                     pCompNew = ImmLocalAlloc(0, cbCompNew);
766                     if (!pCompNew)
767                         goto Quit;
768 
769                     pRS = pCompNew;
770                     pRS->dwSize = cbCompNew;
771                     pRS->dwVersion = 0;
772                     Imm32ReconvertWideFromAnsi(pRS, pComp, uCodePage);
773                 }
774             }
775 
776             if (pRead)
777             {
778                 if (bAnsiClient)
779                 {
780                     cbReadNew = Imm32ReconvertAnsiFromWide(NULL, pRead, uCodePage);
781                     pReadNew = ImmLocalAlloc(0, cbReadNew);
782                     if (!pReadNew)
783                         goto Quit;
784 
785                     pRS = pReadNew;
786                     pRS->dwSize = cbReadNew;
787                     pRS->dwVersion = 0;
788                     Imm32ReconvertAnsiFromWide(pRS, pRead, uCodePage);
789                 }
790                 else
791                 {
792                     cbReadNew = Imm32ReconvertWideFromAnsi(NULL, pRead, uCodePage);
793                     pReadNew = ImmLocalAlloc(0, cbReadNew);
794                     if (!pReadNew)
795                         goto Quit;
796 
797                     pRS = pReadNew;
798                     pRS->dwSize = cbReadNew;
799                     pRS->dwVersion = 0;
800                     Imm32ReconvertWideFromAnsi(pRS, pRead, uCodePage);
801                 }
802             }
803             break;
804         }
805     }
806 
807     ImmUnlockIMCC(pIC->hCompStr);
808     pCS = NULL;
809     ImmUnlockIMC(hIMC);
810     pIC = NULL;
811 
812     ret = pImeDpi->ImeSetCompositionString(hIMC, dwIndex, pCompNew, cbCompNew,
813                                            pReadNew, cbReadNew);
814 
815     if (dwIndex == SCS_QUERYRECONVERTSTRING)
816     {
817         if (pComp)
818         {
819             if (bAnsiClient)
820                 ret = Imm32ReconvertWideFromAnsi(pComp, pCompNew, uCodePage);
821             else
822                 ret = Imm32ReconvertAnsiFromWide(pComp, pCompNew, uCodePage);
823         }
824 
825         if (pRead)
826         {
827             if (bAnsiClient)
828                 ret = Imm32ReconvertWideFromAnsi(pRead, pReadNew, uCodePage);
829             else
830                 ret = Imm32ReconvertAnsiFromWide(pRead, pReadNew, uCodePage);
831         }
832     }
833 
834 Quit:
835     if (pCS)
836         ImmUnlockIMCC(pIC->hCompStr);
837     if (pIC)
838         ImmUnlockIMC(hIMC);
839     ImmLocalFree(pCompNew);
840     ImmLocalFree(pReadNew);
841     ImmUnlockImeDpi(pImeDpi);
842     return ret;
843 }
844 
845 /***********************************************************************
846  *		ImmGetCompositionStringA (IMM32.@)
847  */
848 LONG WINAPI ImmGetCompositionStringA(HIMC hIMC, DWORD dwIndex, LPVOID lpBuf, DWORD dwBufLen)
849 {
850     LONG ret = 0;
851     LPINPUTCONTEXT pIC;
852     PCLIENTIMC pClientImc;
853     LPCOMPOSITIONSTRING pCS;
854     BOOL bAnsiClient;
855     UINT uCodePage;
856 
857     TRACE("(%p, %lu, %p, %lu)\n", hIMC, dwIndex, lpBuf, dwBufLen);
858 
859     if (dwBufLen && !lpBuf)
860         return 0;
861 
862     pClientImc = ImmLockClientImc(hIMC);
863     if (!pClientImc)
864         return 0;
865 
866     bAnsiClient = !(pClientImc->dwFlags & CLIENTIMC_WIDE);
867     uCodePage = pClientImc->uCodePage;
868     ImmUnlockClientImc(pClientImc);
869 
870     pIC = ImmLockIMC(hIMC);
871     if (!pIC)
872         return 0;
873 
874     pCS = ImmLockIMCC(pIC->hCompStr);
875     if (!pCS)
876     {
877         ImmUnlockIMC(hIMC);
878         return 0;
879     }
880 
881     ret = Imm32GetCompStrA(hIMC, pCS, dwIndex, lpBuf, dwBufLen, bAnsiClient, uCodePage);
882     ImmUnlockIMCC(pIC->hCompStr);
883     ImmUnlockIMC(hIMC);
884     return ret;
885 }
886 
887 /***********************************************************************
888  *		ImmGetCompositionStringW (IMM32.@)
889  */
890 LONG WINAPI ImmGetCompositionStringW(HIMC hIMC, DWORD dwIndex, LPVOID lpBuf, DWORD dwBufLen)
891 {
892     LONG ret = 0;
893     LPINPUTCONTEXT pIC;
894     PCLIENTIMC pClientImc;
895     LPCOMPOSITIONSTRING pCS;
896     BOOL bAnsiClient;
897     UINT uCodePage;
898 
899     TRACE("(%p, %lu, %p, %lu)\n", hIMC, dwIndex, lpBuf, dwBufLen);
900 
901     if (dwBufLen && !lpBuf)
902         return 0;
903 
904     pClientImc = ImmLockClientImc(hIMC);
905     if (!pClientImc)
906         return 0;
907 
908     bAnsiClient = !(pClientImc->dwFlags & CLIENTIMC_WIDE);
909     uCodePage = pClientImc->uCodePage;
910     ImmUnlockClientImc(pClientImc);
911 
912     pIC = ImmLockIMC(hIMC);
913     if (!pIC)
914         return 0;
915 
916     pCS = ImmLockIMCC(pIC->hCompStr);
917     if (!pCS)
918     {
919         ImmUnlockIMC(hIMC);
920         return 0;
921     }
922 
923     ret = Imm32GetCompStrW(hIMC, pCS, dwIndex, lpBuf, dwBufLen, bAnsiClient, uCodePage);
924     ImmUnlockIMCC(pIC->hCompStr);
925     ImmUnlockIMC(hIMC);
926     return ret;
927 }
928 
929 /***********************************************************************
930  *		ImmSetCompositionStringA (IMM32.@)
931  */
932 BOOL WINAPI
933 ImmSetCompositionStringA(HIMC hIMC, DWORD dwIndex, LPVOID lpComp, DWORD dwCompLen,
934                          LPVOID lpRead, DWORD dwReadLen)
935 {
936     TRACE("(%p, %lu, %p, %lu, %p, %lu)\n",
937           hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen);
938     return ImmSetCompositionStringAW(hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen, TRUE);
939 }
940 
941 /***********************************************************************
942  *		ImmSetCompositionStringW (IMM32.@)
943  */
944 BOOL WINAPI
945 ImmSetCompositionStringW(HIMC hIMC, DWORD dwIndex, LPVOID lpComp, DWORD dwCompLen,
946                          LPVOID lpRead, DWORD dwReadLen)
947 {
948     TRACE("(%p, %lu, %p, %lu, %p, %lu)\n",
949           hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen);
950     return ImmSetCompositionStringAW(hIMC, dwIndex, lpComp, dwCompLen, lpRead, dwReadLen, FALSE);
951 }
952