Created
January 31, 2025 15:43
-
-
Save UNC1739/b77e095944df9061091684ea40ecd576 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <windows.h> | |
| #include <atlbase.h> | |
| #include <atlcom.h> | |
| #include <msctf.h> | |
| #include <strsafe.h> | |
| #include <psapi.h> | |
| #pragma comment(lib, "psapi.lib") | |
| #define TEXTSERVICE_DESC L"Universal Text Service" | |
| #define TEXTSERVICE_LANGID MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US) | |
| #define TEXTSERVICE_MODEL TEXT("Apartment")#define TEXTSERVICE_DESC L"Universal Text Service" | |
| #define TEXTSERVICE_LANGID MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US) | |
| #define TEXTSERVICE_MODEL TEXT("Apartment") | |
| class __declspec(uuid("e7ea138e-69f8-11d7-a6ea-00065b84435c")) CTextService; | |
| class CTextServiceModule : public CAtlDllModuleT<CTextServiceModule> {}; | |
| CTextServiceModule _AtlModule; | |
| class ATL_NO_VTABLE CTextService : | |
| public CComObjectRootEx<CComSingleThreadModel>, | |
| public CComCoClass<CTextService, &__uuidof(CTextService)>, | |
| public ITfTextInputProcessor | |
| { | |
| public: | |
| DECLARE_NOT_AGGREGATABLE(CTextService) | |
| BEGIN_COM_MAP(CTextService) | |
| COM_INTERFACE_ENTRY(ITfTextInputProcessor) | |
| END_COM_MAP() | |
| CTextService() : _pThreadMgr(nullptr), _tfClientId(TF_CLIENTID_NULL) { | |
| MessageBoxW(NULL, L"CTextService Constructor", L"Debug", MB_OK); | |
| } | |
| ~CTextService() { | |
| if (_pThreadMgr) { | |
| _pThreadMgr->Release(); | |
| } | |
| } | |
| STDMETHODIMP Activate(ITfThreadMgr* pThreadMgr, TfClientId tfClientId) { | |
| MessageBoxW(NULL, L"Activate called", L"Debug", MB_OK); | |
| if (_pThreadMgr) _pThreadMgr->Release(); | |
| _pThreadMgr = pThreadMgr; | |
| _tfClientId = tfClientId; | |
| if (_pThreadMgr) _pThreadMgr->AddRef(); | |
| return S_OK; | |
| } | |
| STDMETHODIMP Deactivate() { | |
| MessageBoxW(NULL, L"Deactivate called", L"Debug", MB_OK); | |
| if (_pThreadMgr) { | |
| _pThreadMgr->Release(); | |
| _pThreadMgr = nullptr; | |
| } | |
| _tfClientId = TF_CLIENTID_NULL; | |
| return S_OK; | |
| } | |
| private: | |
| ITfThreadMgr* _pThreadMgr; | |
| TfClientId _tfClientId; | |
| }; | |
| static BOOL RegisterTextService() { | |
| CComPtr<ITfCategoryMgr> pCategoryMgr; | |
| HRESULT hr = pCategoryMgr.CoCreateInstance(CLSID_TF_CategoryMgr, NULL, CLSCTX_INPROC_SERVER); | |
| if (SUCCEEDED(hr)) { | |
| static const GUID GUID_TFCAT_TIP_KEYBOARD_ACTUAL = | |
| { 0x25504FB4, 0x7BAB, 0x4BC1, {0x9C, 0x69, 0xCF, 0x81, 0x89, 0x0F, 0x0E, 0xF5} }; | |
| hr = pCategoryMgr->RegisterCategory( | |
| __uuidof(CTextService), | |
| GUID_TFCAT_TIP_KEYBOARD_ACTUAL, | |
| __uuidof(CTextService)); | |
| } | |
| CComPtr<ITfInputProcessorProfiles> pInputProcessProfiles; | |
| hr = pInputProcessProfiles.CoCreateInstance(CLSID_TF_InputProcessorProfiles, NULL, CLSCTX_INPROC_SERVER); | |
| if (FAILED(hr)) return FALSE; | |
| hr = pInputProcessProfiles->Register(__uuidof(CTextService)); | |
| if (FAILED(hr)) return FALSE; | |
| WCHAR achIconFile[MAX_PATH]; | |
| GetModuleFileNameW(ATL::_AtlBaseModule.GetModuleInstance(), achIconFile, ARRAYSIZE(achIconFile)); | |
| hr = pInputProcessProfiles->AddLanguageProfile( | |
| __uuidof(CTextService), | |
| TEXTSERVICE_LANGID, | |
| __uuidof(CTextService), | |
| TEXTSERVICE_DESC, | |
| (ULONG)wcslen(TEXTSERVICE_DESC), | |
| achIconFile, | |
| (ULONG)wcslen(achIconFile), | |
| 0); | |
| if (FAILED(hr)) return FALSE; | |
| CComPtr<ITfInputProcessorProfileMgr> pProfileMgr; | |
| if (SUCCEEDED(pInputProcessProfiles->QueryInterface(IID_ITfInputProcessorProfileMgr, (void**)&pProfileMgr))) { | |
| hr = pProfileMgr->ActivateProfile( | |
| TF_PROFILETYPE_INPUTPROCESSOR, | |
| TEXTSERVICE_LANGID, | |
| __uuidof(CTextService), | |
| __uuidof(CTextService), | |
| NULL, | |
| TF_IPPMF_FORPROCESS | TF_IPPMF_ENABLEPROFILE | TF_IPPMF_FORSESSION | |
| ); | |
| } | |
| return SUCCEEDED(hr); | |
| } | |
| static BOOL UnregisterTextService() { | |
| CComPtr<ITfInputProcessorProfiles> pInputProcessProfiles; | |
| HRESULT hr = pInputProcessProfiles.CoCreateInstance(CLSID_TF_InputProcessorProfiles, NULL, CLSCTX_INPROC_SERVER); | |
| if (SUCCEEDED(hr)) { | |
| hr = pInputProcessProfiles->Unregister(__uuidof(CTextService)); | |
| } | |
| return SUCCEEDED(hr); | |
| } | |
| extern "C" BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) { | |
| switch (dwReason) { | |
| case DLL_PROCESS_ATTACH: { | |
| WCHAR processName[MAX_PATH] = L"Unknown"; | |
| DWORD processId = GetCurrentProcessId(); | |
| HANDLE processHandle = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processId); | |
| if (processHandle != NULL) { | |
| GetModuleFileNameExW(processHandle, NULL, processName, MAX_PATH); | |
| CloseHandle(processHandle); | |
| } | |
| WCHAR msg[512]; | |
| StringCchPrintfW(msg, ARRAYSIZE(msg), | |
| L"DLL_PROCESS_ATTACH\nProcess: %s\nPID: %d", | |
| processName, processId); | |
| MessageBoxW(NULL, msg, L"DllMain Debug", MB_OK); | |
| break; | |
| } | |
| case DLL_PROCESS_DETACH: | |
| break; | |
| } | |
| return _AtlModule.DllMain(dwReason, lpReserved); | |
| } | |
| STDAPI DllCanUnloadNow(void) { | |
| return _AtlModule.DllCanUnloadNow(); | |
| } | |
| STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv) { | |
| return _AtlModule.DllGetClassObject(rclsid, riid, ppv); | |
| } | |
| STDAPI DllRegisterServer(void) { | |
| HRESULT hr = CoInitialize(NULL); | |
| if (FAILED(hr)) return hr; | |
| WCHAR szCLSID[50]; | |
| StringFromGUID2(__uuidof(CTextService), szCLSID, ARRAYSIZE(szCLSID)); | |
| WCHAR szSubkey[MAX_PATH]; | |
| StringCchPrintfW(szSubkey, ARRAYSIZE(szSubkey), L"CLSID\\%s", szCLSID); | |
| HKEY hKey; | |
| LONG lRet = RegCreateKeyExW(HKEY_CLASSES_ROOT, szSubkey, 0, NULL, | |
| REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, NULL); | |
| if (lRet != ERROR_SUCCESS) { | |
| CoUninitialize(); | |
| return E_FAIL; | |
| } | |
| lRet = RegSetValueExW(hKey, NULL, 0, REG_SZ, | |
| (BYTE*)TEXTSERVICE_DESC, (DWORD)(wcslen(TEXTSERVICE_DESC) + 1) * sizeof(WCHAR)); | |
| RegCloseKey(hKey); | |
| if (lRet != ERROR_SUCCESS) { | |
| CoUninitialize(); | |
| return E_FAIL; | |
| } | |
| StringCchPrintfW(szSubkey, ARRAYSIZE(szSubkey), L"CLSID\\%s\\InProcServer32", szCLSID); | |
| lRet = RegCreateKeyExW(HKEY_CLASSES_ROOT, szSubkey, 0, NULL, | |
| REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, NULL); | |
| if (lRet != ERROR_SUCCESS) { | |
| CoUninitialize(); | |
| return E_FAIL; | |
| } | |
| WCHAR szModule[MAX_PATH]; | |
| GetModuleFileNameW(ATL::_AtlBaseModule.GetModuleInstance(), szModule, ARRAYSIZE(szModule)); | |
| lRet = RegSetValueExW(hKey, NULL, 0, REG_SZ, | |
| (BYTE*)szModule, (DWORD)(wcslen(szModule) + 1) * sizeof(WCHAR)); | |
| if (lRet == ERROR_SUCCESS) { | |
| lRet = RegSetValueExW(hKey, L"ThreadingModel", 0, REG_SZ, | |
| (BYTE*)TEXTSERVICE_MODEL, (DWORD)(wcslen(TEXTSERVICE_MODEL) + 1) * sizeof(WCHAR)); | |
| } | |
| RegCloseKey(hKey); | |
| if (lRet != ERROR_SUCCESS) { | |
| CoUninitialize(); | |
| return E_FAIL; | |
| } | |
| BOOL bResult = RegisterTextService(); | |
| CoUninitialize(); | |
| return bResult ? S_OK : E_FAIL; | |
| } | |
| STDAPI DllUnregisterServer(void) { | |
| HRESULT hr = CoInitialize(NULL); | |
| if (SUCCEEDED(hr)) { | |
| UnregisterTextService(); | |
| WCHAR szCLSID[50]; | |
| StringFromGUID2(__uuidof(CTextService), szCLSID, ARRAYSIZE(szCLSID)); | |
| WCHAR szSubkey[MAX_PATH]; | |
| StringCchPrintfW(szSubkey, ARRAYSIZE(szSubkey), L"CLSID\\%s", szCLSID); | |
| RegDeleteTreeW(HKEY_CLASSES_ROOT, szSubkey); | |
| CoUninitialize(); | |
| } | |
| return S_OK; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment