1// Headless self-test for the TIP — validates the parts that can be checked without a live GUI: 2// 1) the correction table (confirms the UTF-8 wide literals encoded correctly), and 3// 2) the full COM lifecycle of WCTip.dll (class factory, instance creation, QueryInterface across 4// the multiple-inherited interfaces, and balanced ref-counts) WITHOUT registering the TIP into 5// the system input stack. The actual in-place ITfRange edit still needs a live TSF app to test. 6#include <windows.h> 7#include <msctf.h> 8#include <stdio.h> 9#include "Correct.h" 10 11#include <initguid.h> 12DEFINE_GUID(CLSID_WCTextService, 0x6b2d4f8a, 0x1c3e, 0x4a7b, 0x9f, 0x21, 0x3d, 0x5e, 0x8c, 0x7a, 0x4b, 0x12); 13 14typedef HRESULT (STDAPICALLTYPE *PFN_GCO)(REFCLSID, REFIID, void**); 15typedef HRESULT (STDAPICALLTYPE *PFN_CAN)(); 16 17static int g_fail = 0; 18static void check(bool ok, const char* msg) { printf("[%s] %s\n", ok ? "OK " : "FAIL", msg); if (!ok) g_fail++; } 19 20int main() 21{ 22 // 1) brain table — verifies the Cyrillic wide literals survived /utf-8 compilation 23 check(wctip::CorrectWord(L"превет") == L"привет", "CorrectWord: prevet -> privet"); 24 check(wctip::CorrectWord(L"СаБаКа") == L"собака", "CorrectWord: case-insensitive -> sobaka"); 25 check(wctip::CorrectWord(L"малако") == L"молоко", "CorrectWord: malako -> moloko"); 26 check(wctip::CorrectWord(L"привет").empty(), "CorrectWord: leaves a correct word unchanged"); 27 check(wctip::IsSep(L' ') && !wctip::IsSep(L'я'), "IsSep: space yes, letter no"); 28 29 // 2) COM lifecycle, no system registration 30 CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); 31 HMODULE h = LoadLibraryW(L"bin\\WCTip.dll"); 32 check(h != NULL, "LoadLibrary bin\\WCTip.dll"); 33 if (h) 34 { 35 PFN_GCO pGCO = (PFN_GCO)GetProcAddress(h, "DllGetClassObject"); 36 PFN_CAN pCan = (PFN_CAN)GetProcAddress(h, "DllCanUnloadNow"); 37 check(pGCO && pCan, "exports DllGetClassObject + DllCanUnloadNow resolved"); 38 if (pGCO && pCan) 39 { 40 IClassFactory* pcf = NULL; 41 HRESULT hr = pGCO(CLSID_WCTextService, IID_IClassFactory, (void**)&pcf); 42 check(SUCCEEDED(hr) && pcf, "DllGetClassObject -> IClassFactory"); 43 if (pcf) 44 { 45 void* pTip = NULL; 46 hr = pcf->CreateInstance(NULL, IID_ITfTextInputProcessorEx, &pTip); 47 check(SUCCEEDED(hr) && pTip, "CreateInstance -> ITfTextInputProcessorEx"); 48 if (pTip) 49 { 50 ITfTextInputProcessorEx* tip = (ITfTextInputProcessorEx*)pTip; 51 ITfKeyEventSink* ks = NULL; 52 hr = tip->QueryInterface(IID_ITfKeyEventSink, (void**)&ks); 53 check(SUCCEEDED(hr) && ks, "QI -> ITfKeyEventSink (multiple inheritance)"); 54 ITfTextInputProcessor* base = NULL; 55 hr = tip->QueryInterface(IID_ITfTextInputProcessor, (void**)&base); 56 check(SUCCEEDED(hr) && base, "QI -> ITfTextInputProcessor"); 57 if (ks) ks->Release(); 58 if (base) base->Release(); 59 tip->Release(); 60 } 61 pcf->Release(); 62 } 63 check(pCan() == S_OK, "DllCanUnloadNow == S_OK (ref-counts balanced)"); 64 } 65 FreeLibrary(h); 66 } 67 CoUninitialize(); 68 printf(g_fail == 0 ? "SELFTEST_OK\n" : "SELFTEST_FAILED count=%d\n", g_fail); 69 return g_fail; 70}