1 /*
2 * PROJECT: ReactOS msctf.dll
3 * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
4 * PURPOSE: Text Framework Services
5 * COPYRIGHT: Copyright 2023 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
6 */
7
8 #include <stdlib.h>
9
10 #define WIN32_LEAN_AND_MEAN
11 #define WIN32_NO_STATUS
12 #define COBJMACROS
13 #define INITGUID
14 #define _EXTYPES_H
15
16 #include <windows.h>
17 #include <sddl.h>
18 #include <imm.h>
19 #include <cguid.h>
20 #include <tchar.h>
21 #include <msctf.h>
22 #include <ctffunc.h>
23 #include <shlwapi.h>
24 #include <strsafe.h>
25
26 #include <cicarray.h>
27 #include <cicreg.h>
28 #include <cicmutex.h>
29 #include <cicfmap.h>
30
31 #include "mlng.h"
32
33 #include <wine/debug.h>
34
35 WINE_DEFAULT_DEBUG_CHANNEL(msctf);
36
37 BOOL gf_CRT_INIT = FALSE;
38 BOOL g_fDllProcessDetached = FALSE;
39 CRITICAL_SECTION g_cs;
40 CRITICAL_SECTION g_csInDllMain;
41 CRITICAL_SECTION g_csDelayLoad;
42 HINSTANCE g_hInst = NULL;
43 BOOL g_bOnWow64 = FALSE;
44 UINT g_uACP = CP_ACP; // Active Code Page
45 DWORD g_dwOSInfo = 0; // See cicGetOSInfo
46 HKL g_hklDefault = NULL;
47 DWORD g_dwTLSIndex = (DWORD)-1;
48 BOOL gfSharedMemory = FALSE;
49 LONG g_cRefDll = -1;
50 BOOL g_fCUAS = FALSE;
51 TCHAR g_szCUASImeFile[16] = { 0 };
52
53 // Messages
54 UINT g_msgPrivate = 0;
55 UINT g_msgSetFocus = 0;
56 UINT g_msgThreadTerminate = 0;
57 UINT g_msgThreadItemChange = 0;
58 UINT g_msgLBarModal = 0;
59 UINT g_msgRpcSendReceive = 0;
60 UINT g_msgThreadMarshal = 0;
61 UINT g_msgCheckThreadInputIdel = 0;
62 UINT g_msgStubCleanUp = 0;
63 UINT g_msgShowFloating = 0;
64 UINT g_msgLBUpdate = 0;
65 UINT g_msgNuiMgrDirtyUpdate = 0;
66
67 // Unique names
68 BOOL g_fUserSidString = FALSE;
69 TCHAR g_szUserSidString[MAX_PATH] = { 0 };
70 TCHAR g_szUserUnique[MAX_PATH] = { 0 };
71 TCHAR g_szAsmListCache[MAX_PATH] = { 0 };
72 TCHAR g_szTimListCache[MAX_PATH] = { 0 };
73 TCHAR g_szLayoutsCache[MAX_PATH] = { 0 };
74
75 // Mutexes
76 CicMutex g_mutexLBES;
77 CicMutex g_mutexCompart;
78 CicMutex g_mutexAsm;
79 CicMutex g_mutexLayouts;
80 CicMutex g_mutexTMD;
81
82 // File mapping
83 CicFileMappingStatic g_SharedMemory;
84
85 // Hot-Keys
86 UINT g_uLangHotKeyModifiers = 0;
87 UINT g_uLangHotKeyVKey = 0;
88 UINT g_uLangHotKeyVKey2 = 0;
89 UINT g_uKeyTipHotKeyModifiers = 0;
90 UINT g_uKeyTipHotKeyVKey = 0;
91 UINT g_uKeyTipHotKeyVKey2 = 0;
92
93 /**
94 * @implemented
95 */
GetUserSIDString(void)96 LPTSTR GetUserSIDString(void)
97 {
98 HANDLE hToken = NULL;
99 OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken);
100 if (!hToken)
101 return NULL;
102
103 DWORD dwLengthNeeded = 0;
104 GetTokenInformation(hToken, TokenUser, NULL, 0, &dwLengthNeeded);
105 PTOKEN_USER pTokenUser = (PTOKEN_USER)cicMemAllocClear(dwLengthNeeded);
106 if (!pTokenUser)
107 {
108 CloseHandle(hToken);
109 return NULL;
110 }
111
112 LPTSTR StringSid = NULL;
113 if (!GetTokenInformation(hToken, TokenUser, pTokenUser, dwLengthNeeded, &dwLengthNeeded) ||
114 !ConvertSidToStringSid(pTokenUser->User.Sid, &StringSid))
115 {
116 if (StringSid)
117 {
118 LocalFree(StringSid);
119 StringSid = NULL;
120 }
121 }
122
123 cicMemFree(pTokenUser);
124 CloseHandle(hToken);
125 return StringSid;
126 }
127
128 /**
129 * @implemented
130 */
InitUserSidString(void)131 BOOL InitUserSidString(void)
132 {
133 if (g_fUserSidString)
134 return TRUE;
135
136 LPTSTR pszUserSID = GetUserSIDString();
137 if (!pszUserSID)
138 return FALSE;
139
140 StringCchCopy(g_szUserSidString, _countof(g_szUserSidString), pszUserSID);
141 g_fUserSidString = TRUE;
142 LocalFree(pszUserSID);
143 return TRUE;
144 }
145
146 /**
147 * @implemented
148 */
InitUniqueString(void)149 BOOL InitUniqueString(void)
150 {
151 g_szUserUnique[0] = TEXT('\0');
152
153 DWORD dwThreadId = GetCurrentThreadId();
154 HDESK hDesk = GetThreadDesktop(dwThreadId);
155
156 DWORD nLengthNeeded;
157 TCHAR szName[MAX_PATH];
158 if (hDesk && GetUserObjectInformation(hDesk, UOI_NAME, szName, _countof(szName), &nLengthNeeded))
159 StringCchCat(g_szUserUnique, _countof(g_szUserUnique), szName);
160
161 if (!InitUserSidString())
162 return FALSE;
163
164 StringCchCat(g_szUserUnique, _countof(g_szUserUnique), g_szUserSidString);
165 return TRUE;
166 }
167
168 void
GetDesktopUniqueName(_In_ LPCTSTR pszName,_Out_ LPTSTR pszBuff,_In_ UINT cchBuff)169 GetDesktopUniqueName(
170 _In_ LPCTSTR pszName,
171 _Out_ LPTSTR pszBuff,
172 _In_ UINT cchBuff)
173 {
174 StringCchCopy(pszBuff, cchBuff, pszName);
175 StringCchCat(pszBuff, cchBuff, g_szUserUnique);
176 }
177
StringFromGUID2A(REFGUID rguid,LPSTR pszGUID,INT cchGUID)178 BOOL StringFromGUID2A(REFGUID rguid, LPSTR pszGUID, INT cchGUID)
179 {
180 pszGUID[0] = ANSI_NULL;
181
182 WCHAR szWide[40];
183 szWide[0] = UNICODE_NULL;
184 BOOL ret = StringFromGUID2(rguid, szWide, _countof(szWide));
185 ::WideCharToMultiByte(CP_ACP, 0, szWide, -1, pszGUID, cchGUID, NULL, NULL);
186 return ret;
187 }
188
189 #ifdef UNICODE
190 #define StringFromGUID2T StringFromGUID2
191 #define debugstr_t debugstr_w
192 #else
193 #define StringFromGUID2T StringFromGUID2A
194 #define debugstr_t debugstr_a
195 #endif
196
FullPathExec(LPCTSTR pszExeFile,LPCTSTR pszCmdLine,UINT nCmdShow,BOOL bSysWinDir)197 BOOL FullPathExec(LPCTSTR pszExeFile, LPCTSTR pszCmdLine, UINT nCmdShow, BOOL bSysWinDir)
198 {
199 STARTUPINFO si;
200 PROCESS_INFORMATION pi;
201 CicSystemModulePath ModPath;
202 TCHAR szCommandLine[2 * MAX_PATH];
203
204 ModPath.Init(pszExeFile, bSysWinDir);
205 if (!ModPath.m_cchPath)
206 {
207 ERR("%s\n", debugstr_t(pszExeFile));
208 return FALSE;
209 }
210
211 StringCchCopy(szCommandLine, _countof(szCommandLine), pszCmdLine);
212
213 ZeroMemory(&si, sizeof(si));
214 si.cb = sizeof(si);
215 si.wShowWindow = nCmdShow;
216 si.dwFlags = STARTF_USESHOWWINDOW;
217 if (!CreateProcess(ModPath.m_szPath, szCommandLine, NULL, NULL, FALSE,
218 NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi))
219 {
220 ERR("%s, %s\n", debugstr_t(ModPath.m_szPath), debugstr_t(szCommandLine));
221 return FALSE;
222 }
223
224 CloseHandle(pi.hProcess);
225 CloseHandle(pi.hThread);
226 return TRUE;
227 }
228
229 static inline BOOL
RunCPLSetting(LPCTSTR pszCmdLine)230 RunCPLSetting(LPCTSTR pszCmdLine)
231 {
232 if (!pszCmdLine)
233 return FALSE;
234
235 return FullPathExec(TEXT("rundll32.exe"), pszCmdLine, SW_SHOWMINNOACTIVE, FALSE);
236 }
237
238 /***********************************************************************
239 * TF_RegisterLangBarAddIn (MSCTF.@)
240 *
241 * @implemented
242 */
243 EXTERN_C HRESULT WINAPI
TF_RegisterLangBarAddIn(_In_ REFGUID rguid,_In_ LPCWSTR pszFilePath,_In_ DWORD dwFlags)244 TF_RegisterLangBarAddIn(
245 _In_ REFGUID rguid,
246 _In_ LPCWSTR pszFilePath,
247 _In_ DWORD dwFlags)
248 {
249 TRACE("(%s, %s, 0x%lX)\n", debugstr_guid(&rguid), debugstr_w(pszFilePath), dwFlags);
250
251 if (!pszFilePath || IsEqualGUID(rguid, GUID_NULL))
252 {
253 ERR("E_INVALIDARG\n");
254 return E_INVALIDARG;
255 }
256
257 TCHAR szBuff[MAX_PATH], szGUID[40];
258 StringCchCopy(szBuff, _countof(szBuff), TEXT("SOFTWARE\\Microsoft\\CTF\\LangBarAddIn\\"));
259 StringFromGUID2T(rguid, szGUID, _countof(szGUID));
260 StringCchCat(szBuff, _countof(szBuff), szGUID);
261
262 CicRegKey regKey;
263 HKEY hBaseKey = ((dwFlags & 1) ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER);
264 LSTATUS error = regKey.Create(hBaseKey, szBuff);
265 if (error == ERROR_SUCCESS)
266 {
267 error = regKey.SetSzW(L"FilePath", pszFilePath);
268 if (error == ERROR_SUCCESS)
269 error = regKey.SetDword(TEXT("Enable"), !!(dwFlags & 4));
270 }
271
272 return ((error == ERROR_SUCCESS) ? S_OK : E_FAIL);
273 }
274
275 /***********************************************************************
276 * TF_UnregisterLangBarAddIn (MSCTF.@)
277 *
278 * @implemented
279 */
280 EXTERN_C HRESULT WINAPI
TF_UnregisterLangBarAddIn(_In_ REFGUID rguid,_In_ DWORD dwFlags)281 TF_UnregisterLangBarAddIn(
282 _In_ REFGUID rguid,
283 _In_ DWORD dwFlags)
284 {
285 TRACE("(%s, 0x%lX)\n", debugstr_guid(&rguid), dwFlags);
286
287 if (IsEqualGUID(rguid, GUID_NULL))
288 {
289 ERR("E_INVALIDARG\n");
290 return E_INVALIDARG;
291 }
292
293 TCHAR szSubKey[MAX_PATH];
294 StringCchCopy(szSubKey, _countof(szSubKey), TEXT("SOFTWARE\\Microsoft\\CTF\\LangBarAddIn\\"));
295
296 CicRegKey regKey;
297 HKEY hBaseKey = ((dwFlags & 1) ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER);
298 LSTATUS error = regKey.Open(hBaseKey, szSubKey, KEY_ALL_ACCESS);
299 HRESULT hr = E_FAIL;
300 if (error == ERROR_SUCCESS)
301 {
302 TCHAR szGUID[40];
303 StringFromGUID2T(rguid, szGUID, _countof(szGUID));
304 regKey.RecurseDeleteKey(szGUID);
305 hr = S_OK;
306 }
307
308 return hr;
309 }
310
311 /***********************************************************************
312 * TF_RunInputCPL (MSCTF.@)
313 *
314 * @implemented
315 */
316 EXTERN_C HRESULT WINAPI
TF_RunInputCPL(VOID)317 TF_RunInputCPL(VOID)
318 {
319 CicSystemModulePath ModPath;
320 TCHAR szCmdLine[2 * MAX_PATH];
321
322 TRACE("()\n");
323
324 // NOTE: We don't support Win95/98/Me
325 if (g_dwOSInfo & CIC_OSINFO_XPPLUS)
326 ModPath.Init(TEXT("input.dll"), FALSE);
327 else
328 ModPath.Init(TEXT("input.cpl"), FALSE);
329
330 if (!ModPath.m_cchPath)
331 return E_FAIL;
332
333 StringCchPrintf(szCmdLine, _countof(szCmdLine),
334 TEXT("rundll32.exe shell32.dll,Control_RunDLL %s"), ModPath.m_szPath);
335 if (!RunCPLSetting(szCmdLine))
336 return E_FAIL;
337
338 return S_OK;
339 }
340
341 /***********************************************************************
342 * TF_IsCtfmonRunning (MSCTF.@)
343 *
344 * @implemented
345 */
346 EXTERN_C BOOL WINAPI
TF_IsCtfmonRunning(VOID)347 TF_IsCtfmonRunning(VOID)
348 {
349 TCHAR szName[MAX_PATH];
350 GetDesktopUniqueName(TEXT("CtfmonInstMutex"), szName, _countof(szName));
351
352 HANDLE hMutex = ::OpenMutex(MUTEX_ALL_ACCESS, FALSE, szName);
353 if (!hMutex)
354 return FALSE;
355
356 ::CloseHandle(hMutex);
357 return TRUE;
358 }
359
360 /**
361 * @implemented
362 */
InitLangChangeHotKey(VOID)363 BOOL InitLangChangeHotKey(VOID)
364 {
365 CicRegKey regKey;
366 TCHAR szLanguage[2], szLayout[2];
367 LSTATUS error;
368
369 szLanguage[0] = szLayout[0] = TEXT('3');
370 szLanguage[1] = szLayout[1] = TEXT('\0');
371
372 error = regKey.Open(HKEY_CURRENT_USER, TEXT("Keyboard Layout\\Toggle"));
373 if (error == ERROR_SUCCESS)
374 {
375 error = regKey.QuerySz(TEXT("Language Hotkey"), szLanguage, _countof(szLanguage));
376 if (error != ERROR_SUCCESS)
377 {
378 if (g_dwOSInfo & CIC_OSINFO_NT)
379 {
380 error = regKey.QuerySz(TEXT("Hotkey"), szLanguage, _countof(szLanguage));
381 if (error != ERROR_SUCCESS)
382 szLanguage[0] = TEXT('1');
383 }
384 else
385 {
386 error = regKey.QuerySz(NULL, szLanguage, _countof(szLanguage));
387 if (error != ERROR_SUCCESS)
388 szLanguage[0] = TEXT('1');
389 }
390
391 if (PRIMARYLANGID(GetSystemDefaultLCID()) == LANG_CHINESE)
392 szLanguage[0] = TEXT('1');
393 }
394
395 error = regKey.QuerySz(TEXT("Layout Hotkey"), szLayout, _countof(szLayout));
396 if (error != ERROR_SUCCESS)
397 {
398 szLayout[0] = TEXT('1');
399 if (szLanguage[0] != TEXT('2'))
400 szLayout[0] = TEXT('2');
401 if (GetSystemMetrics(SM_MIDEASTENABLED))
402 szLayout[0] = TEXT('3');
403 }
404
405 szLanguage[1] = TEXT('\0');
406 szLayout[1] = TEXT('\0');
407 }
408
409 if (szLanguage[0] == szLayout[0])
410 {
411 if (szLanguage[0] == TEXT('1'))
412 szLayout[0] = TEXT('2');
413 else if (szLanguage[0] == TEXT('2'))
414 szLayout[0] = TEXT('1');
415 else
416 szLayout[0] = TEXT('3');
417 }
418
419 ::EnterCriticalSection(&g_csInDllMain);
420
421 switch (szLanguage[0])
422 {
423 case TEXT('2'):
424 g_uLangHotKeyModifiers = MOD_SHIFT | MOD_CONTROL;
425 g_uLangHotKeyVKey2 = VK_CONTROL;
426 g_uLangHotKeyVKey = VK_SHIFT;
427 break;
428
429 case TEXT('3'):
430 g_uLangHotKeyVKey = 0;
431 g_uLangHotKeyModifiers = 0;
432 g_uLangHotKeyVKey2 = 0;
433 break;
434
435 case TEXT('4'):
436 g_uLangHotKeyVKey = VK_NUMPAD0;
437 g_uLangHotKeyModifiers = 0;
438 g_uLangHotKeyVKey2 = 0;
439 break;
440
441 case TEXT('1'):
442 default:
443 g_uLangHotKeyModifiers = MOD_SHIFT | MOD_ALT;
444 g_uLangHotKeyVKey2 = VK_MENU;
445 g_uLangHotKeyVKey = VK_SHIFT;
446 break;
447 }
448
449 switch (szLayout[0])
450 {
451 case TEXT('2'):
452 g_uKeyTipHotKeyModifiers = MOD_SHIFT | MOD_CONTROL;
453 g_uKeyTipHotKeyVKey = VK_SHIFT;
454 g_uKeyTipHotKeyVKey2 = VK_CONTROL;
455 break;
456
457 case TEXT('3'):
458 g_uKeyTipHotKeyModifiers = 0;
459 g_uKeyTipHotKeyVKey = 0;
460 g_uKeyTipHotKeyVKey2 = 0;
461 break;
462
463 case TEXT('4'):
464 g_uKeyTipHotKeyModifiers = 0;
465 g_uKeyTipHotKeyVKey = VK_OEM_3;
466 g_uKeyTipHotKeyVKey2 = 0;
467 break;
468
469 case TEXT('1'):
470 default:
471 g_uKeyTipHotKeyModifiers = 0x40 | MOD_SHIFT;
472 g_uKeyTipHotKeyVKey = VK_SHIFT;
473 g_uKeyTipHotKeyVKey2 = VK_MENU;
474 break;
475 }
476
477 ::LeaveCriticalSection(&g_csInDllMain);
478
479 TRACE("HotKey: %c, %c\n", szLanguage[0], szLayout[0]);
480 return TRUE;
481 }
482
483 /**
484 * @unimplemented
485 */
CheckAnchorStores(VOID)486 VOID CheckAnchorStores(VOID)
487 {
488 //FIXME
489 }
490
InitCUASFlag(VOID)491 VOID InitCUASFlag(VOID)
492 {
493 CicRegKey regKey1;
494 LSTATUS error;
495
496 error = regKey1.Open(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Microsoft\\CTF\\SystemShared\\"));
497 if (error == ERROR_SUCCESS)
498 {
499 DWORD dwValue;
500 error = regKey1.QueryDword(TEXT("CUAS"), &dwValue);
501 if (error == ERROR_SUCCESS)
502 g_fCUAS = !!dwValue;
503 }
504
505 g_szCUASImeFile[0] = TEXT('\0');
506
507 if (!g_fCUAS)
508 return;
509
510 TCHAR szImeFile[16];
511 CicRegKey regKey2;
512 error = regKey2.Open(HKEY_LOCAL_MACHINE,
513 TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\IMM"));
514 if (error == ERROR_SUCCESS)
515 {
516 error = regKey2.QuerySz(TEXT("IME File"), szImeFile, _countof(szImeFile));
517 if (error == ERROR_SUCCESS)
518 {
519 g_szCUASImeFile[_countof(g_szCUASImeFile) - 1] = TEXT('\0'); // Avoid buffer overrun
520 StringCchCopy(g_szCUASImeFile, _countof(g_szCUASImeFile), szImeFile);
521 }
522 }
523 }
524
TFUninitLib(VOID)525 EXTERN_C VOID TFUninitLib(VOID)
526 {
527 // Do nothing
528 }
529
530 /**
531 * @unimplemented
532 */
ProcessAttach(HINSTANCE hinstDLL)533 BOOL ProcessAttach(HINSTANCE hinstDLL) // FIXME: Call me from DllMain
534 {
535 gf_CRT_INIT = TRUE;
536
537 ::InitializeCriticalSectionAndSpinCount(&g_cs, 0);
538 ::InitializeCriticalSectionAndSpinCount(&g_csInDllMain, 0);
539 ::InitializeCriticalSectionAndSpinCount(&g_csDelayLoad, 0);
540
541 g_bOnWow64 = cicIsWow64();
542 g_hInst = hinstDLL;
543 g_hklDefault = ::GetKeyboardLayout(0);
544 g_dwTLSIndex = ::TlsAlloc();
545 if (g_dwTLSIndex == (DWORD)-1)
546 return FALSE;
547
548 g_msgPrivate = ::RegisterWindowMessageA("MSUIM.Msg.Private");
549 g_msgSetFocus = ::RegisterWindowMessageA("MSUIM.Msg.SetFocus");
550 g_msgThreadTerminate = ::RegisterWindowMessageA("MSUIM.Msg.ThreadTerminate");
551 g_msgThreadItemChange = ::RegisterWindowMessageA("MSUIM.Msg.ThreadItemChange");
552 g_msgLBarModal = ::RegisterWindowMessageA("MSUIM.Msg.LangBarModal");
553 g_msgRpcSendReceive = ::RegisterWindowMessageA("MSUIM.Msg.RpcSendReceive");
554 g_msgThreadMarshal = ::RegisterWindowMessageA("MSUIM.Msg.ThreadMarshal");
555 g_msgCheckThreadInputIdel = ::RegisterWindowMessageA("MSUIM.Msg.CheckThreadInputIdel");
556 g_msgStubCleanUp = ::RegisterWindowMessageA("MSUIM.Msg.StubCleanUp");
557 g_msgShowFloating = ::RegisterWindowMessageA("MSUIM.Msg.ShowFloating");
558 g_msgLBUpdate = ::RegisterWindowMessageA("MSUIM.Msg.LBUpdate");
559 g_msgNuiMgrDirtyUpdate = ::RegisterWindowMessageA("MSUIM.Msg.MuiMgrDirtyUpdate");
560 if (!g_msgPrivate ||
561 !g_msgSetFocus ||
562 !g_msgThreadTerminate ||
563 !g_msgThreadItemChange ||
564 !g_msgLBarModal ||
565 !g_msgRpcSendReceive ||
566 !g_msgThreadMarshal ||
567 !g_msgCheckThreadInputIdel ||
568 !g_msgStubCleanUp ||
569 !g_msgShowFloating ||
570 !g_msgLBUpdate ||
571 !g_msgNuiMgrDirtyUpdate)
572 {
573 return FALSE;
574 }
575
576 cicGetOSInfo(&g_uACP, &g_dwOSInfo);
577 TRACE("cicGetOSInfo: %u, 0x%lX\n", g_uACP, g_dwOSInfo);
578
579 InitUniqueString();
580
581 //FIXME
582
583 gfSharedMemory = TRUE;
584
585 //FIXME
586
587 InitCUASFlag();
588
589 //FIXME
590
591 GetDesktopUniqueName(TEXT("CTF.AsmListCache.FMP"), g_szAsmListCache, _countof(g_szAsmListCache));
592 GetDesktopUniqueName(TEXT("CTF.TimListCache.FMP"), g_szTimListCache, _countof(g_szTimListCache));
593 GetDesktopUniqueName(TEXT("CTF.LayoutsCache.FMP"), g_szLayoutsCache, _countof(g_szLayoutsCache));
594
595 //FIXME
596
597 InitLangChangeHotKey();
598
599 //FIXME
600
601 CheckAnchorStores();
602
603 return TRUE;
604 }
605
606 /**
607 * @unimplemented
608 */
ProcessDetach(HINSTANCE hinstDLL)609 VOID ProcessDetach(HINSTANCE hinstDLL) // FIXME: Call me from DllMain
610 {
611 if (!gf_CRT_INIT)
612 {
613 g_fDllProcessDetached = TRUE;
614 return;
615 }
616
617 if (gfSharedMemory)
618 {
619 if (g_cRefDll != -1 )
620 TFUninitLib();
621 //FIXME
622 }
623
624 UninitINAT();
625
626 //FIXME
627
628 //TF_UninitThreadSystem();
629
630 //FIXME
631
632 if (g_dwTLSIndex != (DWORD)-1)
633 {
634 ::TlsFree(g_dwTLSIndex);
635 g_dwTLSIndex = (DWORD)-1;
636 }
637
638 //FIXME
639
640 if (gfSharedMemory)
641 {
642 g_mutexLBES.Uninit();
643 g_mutexCompart.Uninit();
644 g_mutexAsm.Uninit();
645 //FIXME
646 g_mutexLayouts.Uninit();
647 g_mutexTMD.Uninit();
648 //FIXME
649 g_SharedMemory.Close();
650 }
651
652 g_SharedMemory.Finalize();
653
654 ::DeleteCriticalSection(&g_cs);
655 ::DeleteCriticalSection(&g_csInDllMain);
656 ::DeleteCriticalSection(&g_csDelayLoad);
657
658 g_fDllProcessDetached = TRUE;
659 }
660