// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A // PARTICULAR PURPOSE. // // Copyright (c) Microsoft Corporation. All rights reserved #include "Private.h" #include "Globals.h" static const WCHAR RegInfo_Prefix_CLSID[] = L"CLSID\\"; static const WCHAR RegInfo_Key_InProSvr32[] = L"InProcServer32"; static const WCHAR RegInfo_Key_ThreadModel[] = L"ThreadingModel"; static const WCHAR TEXTSERVICE_DESC[] = L"Sample IME"; static const GUID SupportCategories[] = { GUID_TFCAT_TIP_KEYBOARD, GUID_TFCAT_DISPLAYATTRIBUTEPROVIDER, GUID_TFCAT_TIPCAP_UIELEMENTENABLED, GUID_TFCAT_TIPCAP_SECUREMODE, GUID_TFCAT_TIPCAP_COMLESS, GUID_TFCAT_TIPCAP_INPUTMODECOMPARTMENT, GUID_TFCAT_TIPCAP_IMMERSIVESUPPORT, GUID_TFCAT_TIPCAP_SYSTRAYSUPPORT, }; //+--------------------------------------------------------------------------- // // RegisterProfiles // //---------------------------------------------------------------------------- BOOL RegisterProfiles() { HRESULT hr = S_FALSE; ITfInputProcessorProfileMgr *pITfInputProcessorProfileMgr = nullptr; hr = CoCreateInstance(CLSID_TF_InputProcessorProfiles, NULL, CLSCTX_INPROC_SERVER, IID_ITfInputProcessorProfileMgr, (void**)&pITfInputProcessorProfileMgr); if (FAILED(hr)) { return FALSE; } WCHAR achIconFile[MAX_PATH] = {'\0'}; DWORD cchA = 0; cchA = GetModuleFileName(Global::dllInstanceHandle, achIconFile, MAX_PATH); cchA = cchA >= MAX_PATH ? (MAX_PATH - 1) : cchA; achIconFile[cchA] = '\0'; size_t lenOfDesc = 0; hr = StringCchLength(TEXTSERVICE_DESC, STRSAFE_MAX_CCH, &lenOfDesc); if (hr != S_OK) { goto Exit; } hr = pITfInputProcessorProfileMgr->RegisterProfile(Global::SampleIMECLSID, TEXTSERVICE_LANGID, Global::SampleIMEGuidProfile, TEXTSERVICE_DESC, static_cast(lenOfDesc), achIconFile, cchA, (UINT)TEXTSERVICE_ICON_INDEX, NULL, 0, TRUE, 0); if (FAILED(hr)) { goto Exit; } Exit: if (pITfInputProcessorProfileMgr) { pITfInputProcessorProfileMgr->Release(); } return (hr == S_OK); } //+--------------------------------------------------------------------------- // // UnregisterProfiles // //---------------------------------------------------------------------------- void UnregisterProfiles() { HRESULT hr = S_OK; ITfInputProcessorProfileMgr *pITfInputProcessorProfileMgr = nullptr; hr = CoCreateInstance(CLSID_TF_InputProcessorProfiles, NULL, CLSCTX_INPROC_SERVER, IID_ITfInputProcessorProfileMgr, (void**)&pITfInputProcessorProfileMgr); if (FAILED(hr)) { goto Exit; } hr = pITfInputProcessorProfileMgr->UnregisterProfile(Global::SampleIMECLSID, TEXTSERVICE_LANGID, Global::SampleIMEGuidProfile, 0); if (FAILED(hr)) { goto Exit; } Exit: if (pITfInputProcessorProfileMgr) { pITfInputProcessorProfileMgr->Release(); } return; } //+--------------------------------------------------------------------------- // // RegisterCategories // //---------------------------------------------------------------------------- BOOL RegisterCategories() { ITfCategoryMgr* pCategoryMgr = nullptr; HRESULT hr = S_OK; hr = CoCreateInstance(CLSID_TF_CategoryMgr, NULL, CLSCTX_INPROC_SERVER, IID_ITfCategoryMgr, (void**)&pCategoryMgr); if (FAILED(hr)) { return FALSE; } for each(GUID guid in SupportCategories) { hr = pCategoryMgr->RegisterCategory(Global::SampleIMECLSID, guid, Global::SampleIMECLSID); } pCategoryMgr->Release(); return (hr == S_OK); } //+--------------------------------------------------------------------------- // // UnregisterCategories // //---------------------------------------------------------------------------- void UnregisterCategories() { ITfCategoryMgr* pCategoryMgr = S_OK; HRESULT hr = S_OK; hr = CoCreateInstance(CLSID_TF_CategoryMgr, NULL, CLSCTX_INPROC_SERVER, IID_ITfCategoryMgr, (void**)&pCategoryMgr); if (FAILED(hr)) { return; } for each(GUID guid in SupportCategories) { pCategoryMgr->UnregisterCategory(Global::SampleIMECLSID, guid, Global::SampleIMECLSID); } pCategoryMgr->Release(); return; } //+--------------------------------------------------------------------------- // // RecurseDeleteKey // // RecurseDeleteKey is necessary because on NT RegDeleteKey doesn't work if the // specified key has subkeys //---------------------------------------------------------------------------- LONG RecurseDeleteKey(_In_ HKEY hParentKey, _In_ LPCTSTR lpszKey) { HKEY regKeyHandle = nullptr; LONG res = 0; FILETIME time; WCHAR stringBuffer[256] = {'\0'}; DWORD size = ARRAYSIZE(stringBuffer); if (RegOpenKey(hParentKey, lpszKey, ®KeyHandle) != ERROR_SUCCESS) { return ERROR_SUCCESS; } res = ERROR_SUCCESS; while (RegEnumKeyEx(regKeyHandle, 0, stringBuffer, &size, NULL, NULL, NULL, &time) == ERROR_SUCCESS) { stringBuffer[ARRAYSIZE(stringBuffer)-1] = '\0'; res = RecurseDeleteKey(regKeyHandle, stringBuffer); if (res != ERROR_SUCCESS) { break; } size = ARRAYSIZE(stringBuffer); } RegCloseKey(regKeyHandle); return res == ERROR_SUCCESS ? RegDeleteKey(hParentKey, lpszKey) : res; } //+--------------------------------------------------------------------------- // // RegisterServer // //---------------------------------------------------------------------------- BOOL RegisterServer() { DWORD copiedStringLen = 0; HKEY regKeyHandle = nullptr; HKEY regSubkeyHandle = nullptr; BOOL ret = FALSE; WCHAR achIMEKey[ARRAYSIZE(RegInfo_Prefix_CLSID) + CLSID_STRLEN] = {'\0'}; WCHAR achFileName[MAX_PATH] = {'\0'}; if (!CLSIDToString(Global::SampleIMECLSID, achIMEKey + ARRAYSIZE(RegInfo_Prefix_CLSID) - 1)) { return FALSE; } memcpy(achIMEKey, RegInfo_Prefix_CLSID, sizeof(RegInfo_Prefix_CLSID) - sizeof(WCHAR)); if (RegCreateKeyEx(HKEY_CLASSES_ROOT, achIMEKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, ®KeyHandle, &copiedStringLen) == ERROR_SUCCESS) { if (RegSetValueEx(regKeyHandle, NULL, 0, REG_SZ, (const BYTE *)TEXTSERVICE_DESC, (_countof(TEXTSERVICE_DESC))*sizeof(WCHAR)) != ERROR_SUCCESS) { goto Exit; } if (RegCreateKeyEx(regKeyHandle, RegInfo_Key_InProSvr32, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, ®SubkeyHandle, &copiedStringLen) == ERROR_SUCCESS) { copiedStringLen = GetModuleFileNameW(Global::dllInstanceHandle, achFileName, ARRAYSIZE(achFileName)); copiedStringLen = (copiedStringLen >= (MAX_PATH - 1)) ? MAX_PATH : (++copiedStringLen); if (RegSetValueEx(regSubkeyHandle, NULL, 0, REG_SZ, (const BYTE *)achFileName, (copiedStringLen)*sizeof(WCHAR)) != ERROR_SUCCESS) { goto Exit; } if (RegSetValueEx(regSubkeyHandle, RegInfo_Key_ThreadModel, 0, REG_SZ, (const BYTE *)TEXTSERVICE_MODEL, (_countof(TEXTSERVICE_MODEL)) * sizeof(WCHAR)) != ERROR_SUCCESS) { goto Exit; } ret = TRUE; } } Exit: if (regSubkeyHandle) { RegCloseKey(regSubkeyHandle); regSubkeyHandle = nullptr; } if (regKeyHandle) { RegCloseKey(regKeyHandle); regKeyHandle = nullptr; } return ret; } //+--------------------------------------------------------------------------- // // UnregisterServer // //---------------------------------------------------------------------------- void UnregisterServer() { WCHAR achIMEKey[ARRAYSIZE(RegInfo_Prefix_CLSID) + CLSID_STRLEN] = {'\0'}; if (!CLSIDToString(Global::SampleIMECLSID, achIMEKey + ARRAYSIZE(RegInfo_Prefix_CLSID) - 1)) { return; } memcpy(achIMEKey, RegInfo_Prefix_CLSID, sizeof(RegInfo_Prefix_CLSID) - sizeof(WCHAR)); RecurseDeleteKey(HKEY_CLASSES_ROOT, achIMEKey); }