Escape any spaces in lpszObjectName passed to HttpOpenRequest.
[wine] / dlls / imm32 / imekl.c
1 /*
2  *      IME Keyboard Layout
3  *
4  *      Copyright 2000 Hidenori Takeshima
5  */
6
7 #include "config.h"
8
9 #include <string.h>
10 #include "winbase.h"
11 #include "windef.h"
12 #include "wingdi.h"
13 #include "winuser.h"
14 #include "winerror.h"
15 #include "winreg.h"
16 #include "immddk.h"
17
18 #include "debugtools.h"
19 DEFAULT_DEBUG_CHANNEL(imm);
20
21 #include "imm_private.h"
22
23 static const char       IMM32_szRegKL[] =
24         "System\\CurrentControlSet\\Control\\keyboard layouts";
25 static const char       IMM32_szIME_File[] = "IME file";
26 static const char       IMM32_szLayout_File[] = "layout file";
27
28 static IMM32_IMEKL*     IMM32_pklFirst = NULL;
29
30
31 static LONG IMM32_RegOpenKey( HKL hkl, PHKEY phkRet )
32 {
33         CHAR    szRegPath[ sizeof(IMM32_szRegKL)+16 ];
34
35         wsprintfA( szRegPath, "%s\\%08x", IMM32_szRegKL, (unsigned)hkl );
36         return RegOpenKeyExA( HKEY_LOCAL_MACHINE, szRegPath,
37                               0, KEY_READ, phkRet );
38 }
39
40 static LONG IMM32_RegCreateKey( HKL hkl, PHKEY phkRet,
41                                 LPDWORD lpdwDisposition )
42 {
43         CHAR    szRegPath[ sizeof(IMM32_szRegKL)+16 ];
44
45         wsprintfA( szRegPath, "%s\\%08x", IMM32_szRegKL, (unsigned)hkl );
46         return RegCreateKeyExA( HKEY_LOCAL_MACHINE, szRegPath,
47                                 0, "REG_SZ",
48                                 REG_OPTION_NON_VOLATILE,
49                                 KEY_ALL_ACCESS, NULL,
50                                 phkRet, lpdwDisposition );
51 }
52
53 static DWORD IMM32_GetIMEFileName( HKL hkl, LPSTR lpBuf, INT nBufLen )
54 {
55         HKEY    hkey;
56         LONG    nError;
57         DWORD   dwType;
58         DWORD   cbData;
59         CHAR    szValueName[ sizeof(IMM32_szIME_File) ];
60
61         TRACE( "hkl = %08x\n", (unsigned)hkl );
62
63         nError = IMM32_RegOpenKey( hkl, &hkey );
64         if ( nError != ERROR_SUCCESS )
65         {
66                 SetLastError( nError );
67                 return 0;
68         }
69         memcpy( szValueName, IMM32_szIME_File, sizeof(IMM32_szIME_File) );
70
71         nError = RegQueryValueExA( hkey, szValueName, NULL,
72                                    &dwType, NULL, &cbData );
73         if ( nError == ERROR_SUCCESS && dwType != REG_SZ )
74                 nError = ERROR_FILE_NOT_FOUND; /* FIXME? */
75         if ( nError == ERROR_SUCCESS && lpBuf != NULL && nBufLen != 0 )
76         {
77                 if ( nBufLen < (INT)cbData )
78                         nError = ERROR_INSUFFICIENT_BUFFER;
79                 else
80                         nError = RegQueryValueExA( hkey, szValueName, NULL,
81                                                    &dwType, lpBuf, &cbData );
82         }
83
84         RegCloseKey( hkey );
85
86         if ( nError != ERROR_SUCCESS )
87         {
88                 SetLastError( nError );
89                 return 0;
90         }
91
92         return cbData;
93 }
94
95
96 static
97 BOOL IMM32_GetIMEHandlersA( HINSTANCE hInstIME,
98                             struct IMM32_IME_EXPORTED_HANDLERS* phandlers )
99 {
100         BOOL    fError;
101
102         #define FE(name)                                                \
103                 phandlers->p##name = (IMM32_p##name)                    \
104                         GetProcAddress(hInstIME,#name);                 \
105                 if ( phandlers->p##name == NULL ) fError = TRUE;
106         #define FE_(name)                                               \
107                 phandlers->p##name.A = (IMM32_p##name##A)               \
108                         GetProcAddress(hInstIME,#name);                 \
109                 if ( phandlers->p##name.A == NULL ) fError = TRUE;
110
111         fError = FALSE;
112
113         FE_(ImeInquire)
114         FE_(ImeConfigure)
115         FE_(ImeConversionList)
116         FE(ImeDestroy)
117         FE_(ImeEnumRegisterWord)
118         FE_(ImeGetRegisterWordStyle)
119         FE_(ImeEscape)
120         FE(ImeProcessKey)
121         FE_(ImeRegisterWord)
122         FE(ImeSelect)
123         FE(ImeSetActiveContext)
124         FE_(ImeSetCompositionString)
125         FE(ImeToAsciiEx)
126         FE_(ImeUnregisterWord)
127         FE(NotifyIME)
128
129         if ( fError )
130                 return FALSE;
131
132         FE_(ImeGetImeMenuItems)
133
134         #undef  FE
135         #undef  FE_
136
137         return TRUE;
138 }
139
140 static
141 BOOL IMM32_GetIMEHandlersW( HINSTANCE hInstIME,
142                             struct IMM32_IME_EXPORTED_HANDLERS* phandlers )
143 {
144         BOOL    fError;
145
146         #define FE(name)                                                \
147                 phandlers->p##name = (IMM32_p##name)                    \
148                         GetProcAddress(hInstIME,#name);                 \
149                 if ( phandlers->p##name == NULL ) fError = TRUE;
150         #define FE_(name)                                               \
151                 phandlers->p##name.W = (IMM32_p##name##W)               \
152                         GetProcAddress(hInstIME,#name);                 \
153                 if ( phandlers->p##name.W == NULL ) fError = TRUE;
154
155         fError = FALSE;
156
157         FE_(ImeInquire)
158         FE_(ImeConfigure)
159         FE_(ImeConversionList)
160         FE(ImeDestroy)
161         FE_(ImeEnumRegisterWord)
162         FE_(ImeGetRegisterWordStyle)
163         FE_(ImeEscape)
164         FE(ImeProcessKey)
165         FE_(ImeRegisterWord)
166         FE(ImeSelect)
167         FE(ImeSetActiveContext)
168         FE_(ImeSetCompositionString)
169         FE(ImeToAsciiEx)
170         FE_(ImeUnregisterWord)
171         FE(NotifyIME)
172
173         if ( fError )
174                 return FALSE;
175
176         FE_(ImeGetImeMenuItems)
177
178         #undef  FE
179         #undef  FE_
180
181         return TRUE;
182 }
183
184
185 static IMM32_IMEKL* IMM32_LoadIME( HKL hkl )
186 {
187         IMM32_IMEKL*    pkl = NULL;
188         BOOL    fInitialized = FALSE;
189         CHAR*   pszFileName = NULL;
190         DWORD   dwBufLen;
191         IMM32_pImeInquireA      pImeInquire;
192         IMM32_pImeDestroy       pImeDestroy = NULL;
193         CHAR    szUIClassName[ (IMM32_UICLASSNAME_MAX+1)*sizeof(WCHAR) ];
194
195         dwBufLen = IMM32_GetIMEFileName( hkl, NULL, 0 );
196         if ( dwBufLen == 0 )
197                 goto err;
198         pszFileName = (CHAR*)IMM32_HeapAlloc( 0, sizeof(CHAR)*(dwBufLen+1) );
199         if ( pszFileName == NULL )
200         {
201                 SetLastError( ERROR_OUTOFMEMORY );
202                 goto err;
203         }
204         if ( !IMM32_GetIMEFileName( hkl, pszFileName, dwBufLen + 1 ) )
205                 goto err;
206
207         pkl = (IMM32_IMEKL*)
208                 IMM32_HeapAlloc( HEAP_ZERO_MEMORY, sizeof(IMM32_IMEKL) );
209         if ( pkl == NULL )
210         {
211                 SetLastError( ERROR_OUTOFMEMORY );
212                 goto err;
213         }
214
215         pkl->pNext = NULL;
216         pkl->hkl = hkl;
217         pkl->hInstIME = LoadLibraryA( pszFileName );
218         if ( pkl->hInstIME == (HINSTANCE)NULL )
219                 goto err;
220
221         pImeInquire = (IMM32_pImeInquireA)GetProcAddress
222                                         ( pkl->hInstIME, "ImeInquire" );
223         pImeDestroy = (IMM32_pImeDestroy)GetProcAddress
224                                         ( pkl->hInstIME, "ImeDestroy" );
225         if ( pImeInquire == NULL || pImeDestroy == NULL )
226                 goto err;
227
228         if ( !pImeInquire( &(pkl->imeinfo), szUIClassName, NULL ) )
229         {
230                 SetLastError( ERROR_DLL_INIT_FAILED ); /* FIXME? */
231                 goto err;
232         }
233         fInitialized = TRUE;
234
235         /* FIXME: Is this correct??? */
236         if ( pkl->imeinfo.fdwProperty & IME_PROP_UNICODE )
237                 pkl->fUnicode = TRUE;
238         else
239                 pkl->fUnicode = FALSE;
240
241         if ( pkl->fUnicode )
242         {
243                 if ( !IMM32_GetIMEHandlersW( pkl->hInstIME, &pkl->handlers ) )
244                         goto err;
245                 memcpy( pkl->UIClassName.W, szUIClassName,
246                         IMM32_UICLASSNAME_MAX*sizeof(WCHAR) );
247                 TRACE( "UI class name(Unicode): %s\n",
248                         debugstr_w(pkl->UIClassName.W) );
249         }
250         else
251         {
252                 if ( !IMM32_GetIMEHandlersA( pkl->hInstIME, &pkl->handlers ) )
253                         goto err;
254                 memcpy( pkl->UIClassName.A, szUIClassName,
255                         IMM32_UICLASSNAME_MAX*sizeof(CHAR) );
256                 TRACE( "UI class name(ASCII): %s\n",
257                         debugstr_a(pkl->UIClassName.A) );
258         }
259
260         /* The IME is loaded successfully. */
261         pkl->pszIMEFileName = pszFileName; pszFileName = NULL;
262         return pkl;
263
264 err:
265         IMM32_HeapFree( pszFileName );
266         if ( pkl != NULL )
267         {
268                 if ( pkl->hInstIME != (HINSTANCE)NULL )
269                 {
270                         if ( fInitialized )
271                                 (void)pImeDestroy(0);
272                         FreeLibrary( pkl->hInstIME );
273                 }
274                 IMM32_HeapFree( pkl );
275         }
276
277         return NULL;
278 }
279
280
281 const IMM32_IMEKL* IMM32_GetIME( HKL hkl )
282 {
283         IMM32_IMEKL*    pkl;
284
285         IMM32_Lock();
286
287         pkl = IMM32_pklFirst;
288         while ( pkl != NULL )
289         {
290                 if ( pkl->hkl == hkl )
291                         goto end;
292                 pkl = pkl->pNext;
293         }
294
295         pkl = IMM32_LoadIME( hkl );
296         if ( pkl != NULL )
297         {
298                 pkl->pNext = IMM32_pklFirst;
299                 IMM32_pklFirst = pkl;
300         }
301
302 end:
303         IMM32_Unlock();
304
305         return pkl;
306 }
307
308 void IMM32_UnloadAllIMEs( void )
309 {
310         IMM32_IMEKL*    pkl;
311         IMM32_IMEKL*    pklNext;
312
313         IMM32_Lock();
314
315         pkl = IMM32_pklFirst;
316         while ( pkl != NULL )
317         {
318                 TRACE( "hkl = %08x\n", (unsigned)pkl->hkl );
319
320                 pklNext = pkl->pNext;
321                 (void)pkl->handlers.pImeDestroy(0);
322                 FreeLibrary( pkl->hInstIME );
323                 IMM32_HeapFree( pkl->pszIMEFileName );
324                 IMM32_HeapFree( pkl );
325                 pkl = pklNext;
326         }
327         IMM32_pklFirst = NULL;
328
329         IMM32_Unlock();
330 }
331
332
333
334 /***********************************************************************
335  *              ImmInstallIMEA (IMM32.@)
336  */
337 HKL WINAPI ImmInstallIMEA(
338         LPCSTR lpszIMEFileName, LPCSTR lpszLayoutText)
339 {
340         HKL     hkl;
341         DWORD   dwLCID;
342         DWORD   dwTryCount;
343         LONG    nError;
344         HKEY    hkey;
345         DWORD   dwDisposition;
346         DWORD   cbData;
347         CHAR    szValueName[ sizeof(IMM32_szIME_File) ];
348
349         TRACE("(%s, %s)\n",
350                 debugstr_a(lpszIMEFileName), debugstr_a(lpszLayoutText) );
351
352         dwLCID = (DWORD)GetThreadLocale();
353         dwTryCount = 0;
354
355         FIXME( "IMEs don't work correctly now since\n"
356                "wine/windows/input.c doesn't handle HKL correctly.\n" );
357
358         while ( 1 )
359         {
360                 hkl = (HKL)(((0xe000|dwTryCount)<<16) | (dwLCID));
361
362                 nError = IMM32_RegCreateKey( hkl, &hkey, &dwDisposition );
363                 if ( nError != ERROR_SUCCESS )
364                         break;
365
366                 memcpy( szValueName, IMM32_szIME_File,
367                         sizeof(IMM32_szIME_File) );
368
369                 nError = RegQueryValueExA( hkey, szValueName, NULL,
370                                            NULL, NULL, &cbData );
371                 if ( nError == ERROR_SUCCESS && cbData > 0 )
372                 {
373                         RegCloseKey( hkey );
374
375                         /* try to assign an other HKL. */
376                         dwTryCount ++;
377                         if ( dwTryCount >= 0x100 )
378                         {
379                                 nError = ERROR_ACCESS_DENIED; /* FIXME */
380                                 break;
381                         }
382                         continue;
383                 }
384
385                 nError = RegSetValueExA( hkey, IMM32_szIME_File, 0,
386                                          REG_SZ, lpszIMEFileName,
387                                          strlen(lpszIMEFileName)+1 );
388                 if ( nError == ERROR_SUCCESS )
389                         nError = RegSetValueExA( hkey, IMM32_szLayout_File, 0,
390                                                  REG_SZ, lpszLayoutText,
391                                                  strlen(lpszLayoutText)+1 );
392                 RegCloseKey( hkey );
393                 break;
394         }
395
396         if ( nError != ERROR_SUCCESS )
397         {
398                 SetLastError( nError );
399                 return (HKL)NULL;
400         }
401
402         return hkl;
403 }
404
405 /***********************************************************************
406  *              ImmInstallIMEW (IMM32.@)
407  */
408 HKL WINAPI ImmInstallIMEW(
409         LPCWSTR lpszIMEFileName, LPCWSTR lpszLayoutText)
410 {
411         LPSTR   lpszParam1;
412         LPSTR   lpszParam2;
413         HKL     hkl;
414
415         TRACE("(%s, %s)\n",
416                 debugstr_w(lpszIMEFileName), debugstr_w(lpszLayoutText) );
417
418         lpszParam1 = IMM32_strdupWtoA( lpszIMEFileName );
419         lpszParam2 = IMM32_strdupWtoA( lpszLayoutText );
420         if ( ( lpszParam1 == NULL ) || ( lpszParam2 == NULL ) )
421         {
422                 SetLastError( ERROR_OUTOFMEMORY );
423                 hkl = (HKL)NULL;
424         }
425         else
426         {
427                 hkl = ImmInstallIMEA( lpszParam1, lpszParam2 );
428         }
429         IMM32_HeapFree( lpszParam1 );
430         IMM32_HeapFree( lpszParam2 );
431
432         return hkl;
433 }
434
435
436 /***********************************************************************
437  *              ImmIsIME (IMM32.@)
438  */
439 BOOL WINAPI ImmIsIME(HKL hkl)
440 {
441         const IMM32_IMEKL*      pkl;
442
443         TRACE("(0x%08x)\n", hkl);
444
445         pkl = IMM32_GetIME( hkl );
446         if ( pkl == NULL )
447                 return FALSE;
448
449         return TRUE;
450 }
451
452
453 /***********************************************************************
454  *              ImmGetIMEFileNameA (IMM32.@)
455  */
456 UINT WINAPI ImmGetIMEFileNameA(HKL hkl, LPSTR lpszFileName, UINT uBufLen)
457 {
458         const IMM32_IMEKL*      pkl;
459         UINT                    uIMEFileNameLen;
460
461         TRACE("(%08x,%p,%u)\n",hkl,lpszFileName,uBufLen);
462
463         pkl = IMM32_GetIME( hkl );
464         if ( pkl == NULL )
465                 return 0;
466
467         uIMEFileNameLen = strlen(pkl->pszIMEFileName);
468         if ( uBufLen == 0 )
469                 return uIMEFileNameLen;
470         if ( uBufLen <= uIMEFileNameLen )
471         {
472                 SetLastError(ERROR_INSUFFICIENT_BUFFER);
473                 return 0;
474         }
475         memcpy( lpszFileName, pkl->pszIMEFileName,
476                 sizeof(CHAR)*(uIMEFileNameLen+1) );
477
478         return uIMEFileNameLen;
479 }
480
481 /***********************************************************************
482  *              ImmGetIMEFileNameW (IMM32.@)
483  */
484 UINT WINAPI ImmGetIMEFileNameW(HKL hkl, LPWSTR lpszFileName, UINT uBufLen)
485 {
486         const IMM32_IMEKL*      pkl;
487         UINT                    uIMEFileNameLen;
488
489         TRACE("(%08x,%p,%u)\n",hkl,lpszFileName,uBufLen);
490
491         pkl = IMM32_GetIME( hkl );
492         if ( pkl == NULL )
493                 return 0;
494
495         uIMEFileNameLen = IMM32_strlenAtoW(pkl->pszIMEFileName);
496         if ( uBufLen == 0 )
497                 return uIMEFileNameLen;
498         if ( uBufLen <= uIMEFileNameLen )
499         {
500                 SetLastError(ERROR_INSUFFICIENT_BUFFER);
501                 return 0;
502         }
503         IMM32_strncpyAtoW( lpszFileName, pkl->pszIMEFileName, uBufLen );
504
505         return uIMEFileNameLen;
506 }
507
508 /***********************************************************************
509  *              ImmGetProperty (IMM32.@)
510  */
511 DWORD WINAPI ImmGetProperty(HKL hkl, DWORD fdwIndex)
512 {
513         const IMM32_IMEKL*      pkl;
514         DWORD                   dwRet;
515
516         TRACE("(0x%08x, %ld)\n", hkl, fdwIndex);
517
518         pkl = IMM32_GetIME( hkl );
519         if ( pkl == NULL )
520                 return 0;
521
522         switch ( fdwIndex )
523         {
524         case IGP_GETIMEVERSION:
525                 dwRet = IMEVER_0400;
526                 break;
527         case IGP_PROPERTY:
528                 dwRet = pkl->imeinfo.fdwProperty;
529                 break;
530         case IGP_CONVERSION:
531                 dwRet = pkl->imeinfo.fdwConversionCaps;
532                 break;
533         case IGP_SENTENCE:
534                 dwRet = pkl->imeinfo.fdwSentenceCaps;
535                 break;
536         case IGP_UI:
537                 dwRet = pkl->imeinfo.fdwUICaps;
538                 break;
539         case IGP_SETCOMPSTR:
540                 dwRet = pkl->imeinfo.fdwSCSCaps;
541                 break;
542         case IGP_SELECT:
543                 dwRet = pkl->imeinfo.fdwSelectCaps;
544                 break;
545         default:
546                 FIXME("(0x%08x, %ld): invalid/unknown property.\n",
547                       hkl, fdwIndex);
548                 SetLastError( ERROR_INVALID_PARAMETER );
549                 dwRet = 0;
550         }
551
552         return dwRet;
553 }
554
555
556 /***********************************************************************
557  *              ImmEnumRegisterWordA (IMM32.@)
558  */
559 UINT WINAPI ImmEnumRegisterWordA(
560         HKL hkl, REGISTERWORDENUMPROCA lpfnEnumProc,
561         LPCSTR lpszReading, DWORD dwStyle,
562         LPCSTR lpszRegister, LPVOID lpData)
563 {
564         const IMM32_IMEKL*      pkl;
565
566         TRACE("(0x%08x, %p, %s, %ld, %s, %p)\n",
567                 hkl, lpfnEnumProc, 
568                 debugstr_a(lpszReading), dwStyle,
569                 debugstr_a(lpszRegister), lpData);
570
571         pkl = IMM32_GetIME( hkl );
572         if ( pkl == NULL )
573                 return 0;
574
575         if ( pkl->fUnicode )
576         {
577                 FIXME( "please implement UNICODE->ANSI\n" );
578                 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
579                 return 0;
580         }
581         else
582         {
583                 return pkl->handlers.pImeEnumRegisterWord.A
584                         ( lpfnEnumProc, lpszReading, dwStyle,
585                           lpszRegister, lpData );
586         }
587 }
588
589 /***********************************************************************
590  *              ImmEnumRegisterWordW (IMM32.@)
591  */
592 UINT WINAPI ImmEnumRegisterWordW(
593         HKL hkl, REGISTERWORDENUMPROCW lpfnEnumProc,
594         LPCWSTR lpszReading, DWORD dwStyle,
595         LPCWSTR lpszRegister, LPVOID lpData)
596 {
597         const IMM32_IMEKL*      pkl;
598
599         TRACE("(0x%08x, %p, %s, %ld, %s, %p): stub\n",
600                 hkl, lpfnEnumProc, 
601                 debugstr_w(lpszReading), dwStyle,
602                 debugstr_w(lpszRegister), lpData);
603
604         pkl = IMM32_GetIME( hkl );
605         if ( pkl == NULL )
606                 return 0;
607
608         if ( pkl->fUnicode )
609         {
610                 return pkl->handlers.pImeEnumRegisterWord.W
611                         ( lpfnEnumProc, lpszReading, dwStyle,
612                           lpszRegister, lpData );
613         }
614         else
615         {
616                 FIXME( "please implement ANSI->UNICODE\n" );
617                 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
618                 return 0;
619         }
620 }
621
622
623 /***********************************************************************
624  *              ImmGetRegisterWordStyleA (IMM32.@)
625  */
626 UINT WINAPI ImmGetRegisterWordStyleA(
627         HKL hkl, UINT nItem, LPSTYLEBUFA lpStyleBuf)
628 {
629         const IMM32_IMEKL*      pkl;
630
631         TRACE("(0x%08x, %d, %p)\n", hkl, nItem, lpStyleBuf);
632
633         pkl = IMM32_GetIME( hkl );
634         if ( pkl == NULL )
635                 return 0;
636
637         if ( pkl->fUnicode )
638         {
639                 FIXME( "please implement UNICODE->ANSI\n" );
640                 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
641                 return 0;
642         }
643         else
644         {
645                 return pkl->handlers.pImeGetRegisterWordStyle.A
646                         ( nItem, lpStyleBuf );
647         }
648 }
649
650 /***********************************************************************
651  *              ImmGetRegisterWordStyleW (IMM32.@)
652  */
653 UINT WINAPI ImmGetRegisterWordStyleW(
654         HKL hkl, UINT nItem, LPSTYLEBUFW lpStyleBuf)
655 {
656         const IMM32_IMEKL*      pkl;
657
658         TRACE("(0x%08x, %d, %p)\n", hkl, nItem, lpStyleBuf);
659
660         pkl = IMM32_GetIME( hkl );
661         if ( pkl == NULL )
662                 return 0;
663
664         if ( pkl->fUnicode )
665         {
666                 return pkl->handlers.pImeGetRegisterWordStyle.W
667                         ( nItem, lpStyleBuf );
668         }
669         else
670         {
671                 FIXME( "please implement ANSI->UNICODE\n" );
672                 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
673                 return 0;
674         }
675 }
676
677