1 /* 2 * Unit tests for ITfInputProcessor 3 * 4 * Copyright 2009 Aric Stewart, CodeWeavers 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 19 */ 20 21 #include <stdio.h> 22 23 #define COBJMACROS 24 #define CONST_VTABLE 25 #include "wine/test.h" 26 #include "winuser.h" 27 #include "initguid.h" 28 #include "shlwapi.h" 29 #include "shlguid.h" 30 #include "comcat.h" 31 #include "msctf.h" 32 #include "olectl.h" 33 34 static ITfInputProcessorProfiles* g_ipp; 35 static LANGID gLangid; 36 static ITfCategoryMgr * g_cm = NULL; 37 static ITfThreadMgr* g_tm = NULL; 38 static ITfDocumentMgr *g_dm = NULL; 39 static TfClientId cid = 0; 40 static TfClientId tid = 0; 41 42 static ITextStoreACPSink *ACPSink; 43 44 #define SINK_UNEXPECTED 0 45 #define SINK_EXPECTED 1 46 #define SINK_FIRED 2 47 #define SINK_IGNORE 3 48 #define SINK_OPTIONAL 4 49 #define SINK_SAVE 5 50 51 #define SINK_ACTION_MASK 0xff 52 #define SINK_OPTION_MASK 0xff00 53 #define SINK_EXPECTED_COUNT_MASK 0xff0000 54 55 #define SINK_OPTION_TODO 0x0100 56 57 #define FOCUS_IGNORE (ITfDocumentMgr*)0xffffffff 58 #define FOCUS_SAVE (ITfDocumentMgr*)0xfffffffe 59 60 static BOOL test_ShouldActivate = FALSE; 61 static BOOL test_ShouldDeactivate = FALSE; 62 63 static DWORD tmSinkCookie; 64 static DWORD tmSinkRefCount; 65 static DWORD dmSinkCookie; 66 static DWORD documentStatus; 67 static DWORD key_trace_sink_cookie; 68 static ITfDocumentMgr *test_CurrentFocus = NULL; 69 static ITfDocumentMgr *test_PrevFocus = NULL; 70 static ITfDocumentMgr *test_LastCurrentFocus = FOCUS_SAVE; 71 static ITfDocumentMgr *test_FirstPrevFocus = FOCUS_SAVE; 72 static INT test_OnSetFocus = SINK_UNEXPECTED; 73 static INT test_OnInitDocumentMgr = SINK_UNEXPECTED; 74 static INT test_OnPushContext = SINK_UNEXPECTED; 75 static INT test_OnPopContext = SINK_UNEXPECTED; 76 static INT test_KEV_OnSetFocus = SINK_UNEXPECTED; 77 static INT test_ACP_AdviseSink = SINK_UNEXPECTED; 78 static INT test_ACP_UnadviseSink = SINK_UNEXPECTED; 79 static INT test_ACP_GetStatus = SINK_UNEXPECTED; 80 static INT test_ACP_RequestLock = SINK_UNEXPECTED; 81 static INT test_ACP_GetEndACP = SINK_UNEXPECTED; 82 static INT test_ACP_GetSelection = SINK_UNEXPECTED; 83 static INT test_DoEditSession = SINK_UNEXPECTED; 84 static INT test_ACP_InsertTextAtSelection = SINK_UNEXPECTED; 85 static INT test_ACP_SetSelection = SINK_UNEXPECTED; 86 static INT test_OnEndEdit = SINK_UNEXPECTED; 87 88 89 static inline int expected_count(int *sink) 90 { 91 return (*sink & SINK_EXPECTED_COUNT_MASK)>>16; 92 } 93 94 static inline void _sink_fire_ok(INT *sink, const CHAR* name) 95 { 96 int count; 97 int todo = *sink & SINK_OPTION_TODO; 98 int action = *sink & SINK_ACTION_MASK; 99 100 if (winetest_interactive) 101 winetest_trace("firing %s\n",name); 102 103 switch (action) 104 { 105 case SINK_OPTIONAL: 106 case SINK_EXPECTED: 107 count = expected_count(sink); 108 if (count > 1) 109 { 110 count --; 111 *sink = (*sink & ~SINK_EXPECTED_COUNT_MASK) + (count << 16); 112 return; 113 } 114 break; 115 case SINK_IGNORE: 116 winetest_trace("Ignoring %s\n",name); 117 return; 118 case SINK_SAVE: 119 count = expected_count(sink) + 1; 120 *sink = (*sink & ~SINK_EXPECTED_COUNT_MASK) + (count << 16); 121 return; 122 default: 123 todo_wine_if (todo) 124 winetest_ok(0, "Unexpected %s sink\n",name); 125 } 126 *sink = SINK_FIRED; 127 } 128 129 #define sink_fire_ok(a,b) (winetest_set_location(__FILE__,__LINE__), 0) ? 0 : _sink_fire_ok(a,b) 130 131 static inline void _sink_check_ok(INT *sink, const CHAR* name) 132 { 133 int action = *sink & SINK_ACTION_MASK; 134 int todo = *sink & SINK_OPTION_TODO; 135 int count = expected_count(sink); 136 137 switch (action) 138 { 139 case SINK_OPTIONAL: 140 if (winetest_interactive) 141 winetest_trace("optional sink %s not fired\n",name); 142 case SINK_FIRED: 143 break; 144 case SINK_IGNORE: 145 return; 146 case SINK_SAVE: 147 if (count == 0 && winetest_interactive) 148 winetest_trace("optional sink %s not fired\n",name); 149 break; 150 default: 151 todo_wine_if (todo) 152 winetest_ok(0, "%s not fired as expected, in state %x\n",name,*sink); 153 } 154 *sink = SINK_UNEXPECTED; 155 } 156 157 #define sink_check_ok(a,b) (winetest_set_location(__FILE__,__LINE__), 0) ? 0 : _sink_check_ok(a,b) 158 159 static inline void _sink_check_saved(INT *sink, ITfDocumentMgr *PrevFocus, ITfDocumentMgr *CurrentFocus, const CHAR* name) 160 { 161 int count = expected_count(sink); 162 _sink_check_ok(sink, name); 163 if (PrevFocus != FOCUS_IGNORE && count != 0) 164 winetest_ok(PrevFocus == test_FirstPrevFocus, "%s expected prev focus %p got %p\n", name, PrevFocus, test_FirstPrevFocus); 165 if (CurrentFocus != FOCUS_IGNORE && count != 0) 166 winetest_ok(CurrentFocus == test_LastCurrentFocus, "%s expected current focus %p got %p\n", name, CurrentFocus, test_LastCurrentFocus); 167 test_FirstPrevFocus = FOCUS_SAVE; 168 test_LastCurrentFocus = FOCUS_SAVE; 169 } 170 171 #define sink_check_saved(s,p,c,n) (winetest_set_location(__FILE__,__LINE__), 0) ? 0 : _sink_check_saved(s,p,c,n) 172 173 /********************************************************************** 174 * ITextStoreACP 175 **********************************************************************/ 176 typedef struct tagTextStoreACP 177 { 178 ITextStoreACP ITextStoreACP_iface; 179 LONG refCount; 180 181 } TextStoreACP; 182 183 static inline TextStoreACP *impl_from_ITextStoreACP(ITextStoreACP *iface) 184 { 185 return CONTAINING_RECORD(iface, TextStoreACP, ITextStoreACP_iface); 186 } 187 188 static void TextStoreACP_Destructor(TextStoreACP *This) 189 { 190 HeapFree(GetProcessHeap(),0,This); 191 } 192 193 static HRESULT WINAPI TextStoreACP_QueryInterface(ITextStoreACP *iface, REFIID iid, LPVOID *ppvOut) 194 { 195 *ppvOut = NULL; 196 197 if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_ITextStoreACP)) 198 { 199 *ppvOut = iface; 200 } 201 202 if (*ppvOut) 203 { 204 ITextStoreACP_AddRef(iface); 205 return S_OK; 206 } 207 208 return E_NOINTERFACE; 209 } 210 211 static ULONG WINAPI TextStoreACP_AddRef(ITextStoreACP *iface) 212 { 213 TextStoreACP *This = impl_from_ITextStoreACP(iface); 214 return InterlockedIncrement(&This->refCount); 215 } 216 217 static ULONG WINAPI TextStoreACP_Release(ITextStoreACP *iface) 218 { 219 TextStoreACP *This = impl_from_ITextStoreACP(iface); 220 ULONG ret; 221 222 ret = InterlockedDecrement(&This->refCount); 223 if (ret == 0) 224 TextStoreACP_Destructor(This); 225 return ret; 226 } 227 228 static HRESULT WINAPI TextStoreACP_AdviseSink(ITextStoreACP *iface, 229 REFIID riid, IUnknown *punk, DWORD dwMask) 230 { 231 ITextStoreACPServices *services; 232 HRESULT hr; 233 234 sink_fire_ok(&test_ACP_AdviseSink,"TextStoreACP_AdviseSink"); 235 236 if(ACPSink) 237 return S_OK; 238 239 hr = IUnknown_QueryInterface(punk, &IID_ITextStoreACPSink, (void**)&ACPSink); 240 ok(SUCCEEDED(hr),"Unable to QueryInterface on sink\n"); 241 242 hr = ITextStoreACPSink_QueryInterface(ACPSink, &IID_ITextStoreACPServices, (void**)&services); 243 ok(hr == S_OK, "got 0x%08x\n", hr); 244 ITextStoreACPServices_Release(services); 245 246 return S_OK; 247 } 248 249 static HRESULT WINAPI TextStoreACP_UnadviseSink(ITextStoreACP *iface, 250 IUnknown *punk) 251 { 252 sink_fire_ok(&test_ACP_UnadviseSink,"TextStoreACP_UnadviseSink"); 253 return S_OK; 254 } 255 256 static HRESULT WINAPI TextStoreACP_RequestLock(ITextStoreACP *iface, 257 DWORD dwLockFlags, HRESULT *phrSession) 258 { 259 sink_fire_ok(&test_ACP_RequestLock,"TextStoreACP_RequestLock"); 260 *phrSession = ITextStoreACPSink_OnLockGranted(ACPSink, dwLockFlags); 261 return S_OK; 262 } 263 static HRESULT WINAPI TextStoreACP_GetStatus(ITextStoreACP *iface, 264 TS_STATUS *pdcs) 265 { 266 sink_fire_ok(&test_ACP_GetStatus,"TextStoreACP_GetStatus"); 267 pdcs->dwDynamicFlags = documentStatus; 268 return S_OK; 269 } 270 static HRESULT WINAPI TextStoreACP_QueryInsert(ITextStoreACP *iface, 271 LONG acpTestStart, LONG acpTestEnd, ULONG cch, LONG *pacpResultStart, 272 LONG *pacpResultEnd) 273 { 274 trace("\n"); 275 return S_OK; 276 } 277 static HRESULT WINAPI TextStoreACP_GetSelection(ITextStoreACP *iface, 278 ULONG ulIndex, ULONG ulCount, TS_SELECTION_ACP *pSelection, ULONG *pcFetched) 279 { 280 sink_fire_ok(&test_ACP_GetSelection,"TextStoreACP_GetSelection"); 281 282 pSelection->acpStart = 10; 283 pSelection->acpEnd = 20; 284 pSelection->style.fInterimChar = 0; 285 pSelection->style.ase = TS_AE_NONE; 286 *pcFetched = 1; 287 288 return S_OK; 289 } 290 static HRESULT WINAPI TextStoreACP_SetSelection(ITextStoreACP *iface, 291 ULONG ulCount, const TS_SELECTION_ACP *pSelection) 292 { 293 sink_fire_ok(&test_ACP_SetSelection,"TextStoreACP_SetSelection"); 294 return S_OK; 295 } 296 static HRESULT WINAPI TextStoreACP_GetText(ITextStoreACP *iface, 297 LONG acpStart, LONG acpEnd, WCHAR *pchPlain, ULONG cchPlainReq, 298 ULONG *pcchPlainRet, TS_RUNINFO *prgRunInfo, ULONG cRunInfoReq, 299 ULONG *pcRunInfoRet, LONG *pacpNext) 300 { 301 trace("\n"); 302 return S_OK; 303 } 304 static HRESULT WINAPI TextStoreACP_SetText(ITextStoreACP *iface, 305 DWORD dwFlags, LONG acpStart, LONG acpEnd, const WCHAR *pchText, 306 ULONG cch, TS_TEXTCHANGE *pChange) 307 { 308 trace("\n"); 309 return S_OK; 310 } 311 static HRESULT WINAPI TextStoreACP_GetFormattedText(ITextStoreACP *iface, 312 LONG acpStart, LONG acpEnd, IDataObject **ppDataObject) 313 { 314 trace("\n"); 315 return S_OK; 316 } 317 static HRESULT WINAPI TextStoreACP_GetEmbedded(ITextStoreACP *iface, 318 LONG acpPos, REFGUID rguidService, REFIID riid, IUnknown **ppunk) 319 { 320 trace("\n"); 321 return S_OK; 322 } 323 static HRESULT WINAPI TextStoreACP_QueryInsertEmbedded(ITextStoreACP *iface, 324 const GUID *pguidService, const FORMATETC *pFormatEtc, BOOL *pfInsertable) 325 { 326 trace("\n"); 327 return S_OK; 328 } 329 static HRESULT WINAPI TextStoreACP_InsertEmbedded(ITextStoreACP *iface, 330 DWORD dwFlags, LONG acpStart, LONG acpEnd, IDataObject *pDataObject, 331 TS_TEXTCHANGE *pChange) 332 { 333 trace("\n"); 334 return S_OK; 335 } 336 static HRESULT WINAPI TextStoreACP_InsertTextAtSelection(ITextStoreACP *iface, 337 DWORD dwFlags, const WCHAR *pchText, ULONG cch, LONG *pacpStart, 338 LONG *pacpEnd, TS_TEXTCHANGE *pChange) 339 { 340 sink_fire_ok(&test_ACP_InsertTextAtSelection,"TextStoreACP_InsertTextAtSelection"); 341 return S_OK; 342 } 343 static HRESULT WINAPI TextStoreACP_InsertEmbeddedAtSelection(ITextStoreACP *iface, 344 DWORD dwFlags, IDataObject *pDataObject, LONG *pacpStart, LONG *pacpEnd, 345 TS_TEXTCHANGE *pChange) 346 { 347 trace("\n"); 348 return S_OK; 349 } 350 static HRESULT WINAPI TextStoreACP_RequestSupportedAttrs(ITextStoreACP *iface, 351 DWORD dwFlags, ULONG cFilterAttrs, const TS_ATTRID *paFilterAttrs) 352 { 353 trace("\n"); 354 return S_OK; 355 } 356 static HRESULT WINAPI TextStoreACP_RequestAttrsAtPosition(ITextStoreACP *iface, 357 LONG acpPos, ULONG cFilterAttrs, const TS_ATTRID *paFilterAttrs, 358 DWORD dwFlags) 359 { 360 trace("\n"); 361 return S_OK; 362 } 363 static HRESULT WINAPI TextStoreACP_RequestAttrsTransitioningAtPosition(ITextStoreACP *iface, 364 LONG acpPos, ULONG cFilterAttrs, const TS_ATTRID *paFilterAttrs, 365 DWORD dwFlags) 366 { 367 trace("\n"); 368 return S_OK; 369 } 370 static HRESULT WINAPI TextStoreACP_FindNextAttrTransition(ITextStoreACP *iface, 371 LONG acpStart, LONG acpHalt, ULONG cFilterAttrs, const TS_ATTRID *paFilterAttrs, 372 DWORD dwFlags, LONG *pacpNext, BOOL *pfFound, LONG *plFoundOffset) 373 { 374 trace("\n"); 375 return S_OK; 376 } 377 static HRESULT WINAPI TextStoreACP_RetrieveRequestedAttrs(ITextStoreACP *iface, 378 ULONG ulCount, TS_ATTRVAL *paAttrVals, ULONG *pcFetched) 379 { 380 trace("\n"); 381 return S_OK; 382 } 383 static HRESULT WINAPI TextStoreACP_GetEndACP(ITextStoreACP *iface, 384 LONG *pacp) 385 { 386 sink_fire_ok(&test_ACP_GetEndACP,"TextStoreACP_GetEndACP"); 387 return S_OK; 388 } 389 static HRESULT WINAPI TextStoreACP_GetActiveView(ITextStoreACP *iface, 390 TsViewCookie *pvcView) 391 { 392 trace("\n"); 393 return S_OK; 394 } 395 static HRESULT WINAPI TextStoreACP_GetACPFromPoint(ITextStoreACP *iface, 396 TsViewCookie vcView, const POINT *ptScreen, DWORD dwFlags, 397 LONG *pacp) 398 { 399 trace("\n"); 400 return S_OK; 401 } 402 static HRESULT WINAPI TextStoreACP_GetTextExt(ITextStoreACP *iface, 403 TsViewCookie vcView, LONG acpStart, LONG acpEnd, RECT *prc, 404 BOOL *pfClipped) 405 { 406 trace("\n"); 407 return S_OK; 408 } 409 static HRESULT WINAPI TextStoreACP_GetScreenExt(ITextStoreACP *iface, 410 TsViewCookie vcView, RECT *prc) 411 { 412 trace("\n"); 413 return S_OK; 414 } 415 static HRESULT WINAPI TextStoreACP_GetWnd(ITextStoreACP *iface, 416 TsViewCookie vcView, HWND *phwnd) 417 { 418 trace("\n"); 419 return S_OK; 420 } 421 422 static const ITextStoreACPVtbl TextStoreACP_TextStoreACPVtbl = 423 { 424 TextStoreACP_QueryInterface, 425 TextStoreACP_AddRef, 426 TextStoreACP_Release, 427 428 TextStoreACP_AdviseSink, 429 TextStoreACP_UnadviseSink, 430 TextStoreACP_RequestLock, 431 TextStoreACP_GetStatus, 432 TextStoreACP_QueryInsert, 433 TextStoreACP_GetSelection, 434 TextStoreACP_SetSelection, 435 TextStoreACP_GetText, 436 TextStoreACP_SetText, 437 TextStoreACP_GetFormattedText, 438 TextStoreACP_GetEmbedded, 439 TextStoreACP_QueryInsertEmbedded, 440 TextStoreACP_InsertEmbedded, 441 TextStoreACP_InsertTextAtSelection, 442 TextStoreACP_InsertEmbeddedAtSelection, 443 TextStoreACP_RequestSupportedAttrs, 444 TextStoreACP_RequestAttrsAtPosition, 445 TextStoreACP_RequestAttrsTransitioningAtPosition, 446 TextStoreACP_FindNextAttrTransition, 447 TextStoreACP_RetrieveRequestedAttrs, 448 TextStoreACP_GetEndACP, 449 TextStoreACP_GetActiveView, 450 TextStoreACP_GetACPFromPoint, 451 TextStoreACP_GetTextExt, 452 TextStoreACP_GetScreenExt, 453 TextStoreACP_GetWnd 454 }; 455 456 static HRESULT TextStoreACP_Constructor(IUnknown **ppOut) 457 { 458 TextStoreACP *This; 459 460 This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(TextStoreACP)); 461 if (This == NULL) 462 return E_OUTOFMEMORY; 463 464 This->ITextStoreACP_iface.lpVtbl = &TextStoreACP_TextStoreACPVtbl; 465 This->refCount = 1; 466 467 *ppOut = (IUnknown*)&This->ITextStoreACP_iface; 468 return S_OK; 469 } 470 471 /********************************************************************** 472 * ITfThreadMgrEventSink 473 **********************************************************************/ 474 typedef struct tagThreadMgrEventSink 475 { 476 ITfThreadMgrEventSink ITfThreadMgrEventSink_iface; 477 LONG refCount; 478 } ThreadMgrEventSink; 479 480 static inline ThreadMgrEventSink *impl_from_ITfThreadMgrEventSink(ITfThreadMgrEventSink *iface) 481 { 482 return CONTAINING_RECORD(iface, ThreadMgrEventSink, ITfThreadMgrEventSink_iface); 483 } 484 485 static void ThreadMgrEventSink_Destructor(ThreadMgrEventSink *This) 486 { 487 HeapFree(GetProcessHeap(),0,This); 488 } 489 490 static HRESULT WINAPI ThreadMgrEventSink_QueryInterface(ITfThreadMgrEventSink *iface, REFIID iid, LPVOID *ppvOut) 491 { 492 *ppvOut = NULL; 493 494 if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_ITfThreadMgrEventSink)) 495 { 496 *ppvOut = iface; 497 } 498 499 if (*ppvOut) 500 { 501 ITfThreadMgrEventSink_AddRef(iface); 502 return S_OK; 503 } 504 505 return E_NOINTERFACE; 506 } 507 508 static ULONG WINAPI ThreadMgrEventSink_AddRef(ITfThreadMgrEventSink *iface) 509 { 510 ThreadMgrEventSink *This = impl_from_ITfThreadMgrEventSink(iface); 511 ok (tmSinkRefCount == This->refCount,"ThreadMgrEventSink refcount off %i vs %i\n",This->refCount,tmSinkRefCount); 512 return InterlockedIncrement(&This->refCount); 513 } 514 515 static ULONG WINAPI ThreadMgrEventSink_Release(ITfThreadMgrEventSink *iface) 516 { 517 ThreadMgrEventSink *This = impl_from_ITfThreadMgrEventSink(iface); 518 ULONG ret; 519 520 ok (tmSinkRefCount == This->refCount,"ThreadMgrEventSink refcount off %i vs %i\n",This->refCount,tmSinkRefCount); 521 ret = InterlockedDecrement(&This->refCount); 522 if (ret == 0) 523 ThreadMgrEventSink_Destructor(This); 524 return ret; 525 } 526 527 static HRESULT WINAPI ThreadMgrEventSink_OnInitDocumentMgr(ITfThreadMgrEventSink *iface, 528 ITfDocumentMgr *pdim) 529 { 530 sink_fire_ok(&test_OnInitDocumentMgr,"ThreadMgrEventSink_OnInitDocumentMgr"); 531 return S_OK; 532 } 533 534 static HRESULT WINAPI ThreadMgrEventSink_OnUninitDocumentMgr(ITfThreadMgrEventSink *iface, 535 ITfDocumentMgr *pdim) 536 { 537 trace("\n"); 538 return S_OK; 539 } 540 541 static HRESULT WINAPI ThreadMgrEventSink_OnSetFocus(ITfThreadMgrEventSink *iface, 542 ITfDocumentMgr *pdimFocus, ITfDocumentMgr *pdimPrevFocus) 543 { 544 sink_fire_ok(&test_OnSetFocus,"ThreadMgrEventSink_OnSetFocus"); 545 if (test_CurrentFocus == FOCUS_SAVE) 546 test_LastCurrentFocus = pdimFocus; 547 else if (test_CurrentFocus != FOCUS_IGNORE) 548 ok(pdimFocus == test_CurrentFocus,"Sink reports wrong focus\n"); 549 if (test_PrevFocus == FOCUS_SAVE) 550 { 551 if (test_FirstPrevFocus == FOCUS_SAVE) 552 test_FirstPrevFocus = pdimPrevFocus; 553 } 554 else if (test_PrevFocus != FOCUS_IGNORE) 555 ok(pdimPrevFocus == test_PrevFocus,"Sink reports wrong previous focus\n"); 556 return S_OK; 557 } 558 559 static HRESULT WINAPI ThreadMgrEventSink_OnPushContext(ITfThreadMgrEventSink *iface, 560 ITfContext *pic) 561 { 562 HRESULT hr; 563 ITfDocumentMgr *docmgr; 564 ITfContext *test; 565 566 hr = ITfContext_GetDocumentMgr(pic,&docmgr); 567 ok(SUCCEEDED(hr),"GetDocumentMgr failed\n"); 568 test = (ITfContext*)0xdeadbeef; 569 hr = ITfDocumentMgr_GetTop(docmgr,&test); 570 ok(SUCCEEDED(hr),"GetTop failed\n"); 571 ITfDocumentMgr_Release(docmgr); 572 ok(test == pic, "Wrong context is on top\n"); 573 if (test) 574 ITfContext_Release(test); 575 576 sink_fire_ok(&test_OnPushContext,"ThreadMgrEventSink_OnPushContext"); 577 return S_OK; 578 } 579 580 static HRESULT WINAPI ThreadMgrEventSink_OnPopContext(ITfThreadMgrEventSink *iface, 581 ITfContext *pic) 582 { 583 HRESULT hr; 584 ITfDocumentMgr *docmgr; 585 ITfContext *test; 586 587 hr = ITfContext_GetDocumentMgr(pic,&docmgr); 588 ok(SUCCEEDED(hr),"GetDocumentMgr failed\n"); 589 ITfDocumentMgr_Release(docmgr); 590 test = (ITfContext*)0xdeadbeef; 591 hr = ITfDocumentMgr_GetTop(docmgr,&test); 592 ok(SUCCEEDED(hr),"GetTop failed\n"); 593 ok(test == pic, "Wrong context is on top\n"); 594 if (test) 595 ITfContext_Release(test); 596 597 sink_fire_ok(&test_OnPopContext,"ThreadMgrEventSink_OnPopContext"); 598 return S_OK; 599 } 600 601 static const ITfThreadMgrEventSinkVtbl ThreadMgrEventSink_ThreadMgrEventSinkVtbl = 602 { 603 ThreadMgrEventSink_QueryInterface, 604 ThreadMgrEventSink_AddRef, 605 ThreadMgrEventSink_Release, 606 607 ThreadMgrEventSink_OnInitDocumentMgr, 608 ThreadMgrEventSink_OnUninitDocumentMgr, 609 ThreadMgrEventSink_OnSetFocus, 610 ThreadMgrEventSink_OnPushContext, 611 ThreadMgrEventSink_OnPopContext 612 }; 613 614 static HRESULT ThreadMgrEventSink_Constructor(IUnknown **ppOut) 615 { 616 ThreadMgrEventSink *This; 617 618 This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(ThreadMgrEventSink)); 619 if (This == NULL) 620 return E_OUTOFMEMORY; 621 622 This->ITfThreadMgrEventSink_iface.lpVtbl = &ThreadMgrEventSink_ThreadMgrEventSinkVtbl; 623 This->refCount = 1; 624 625 *ppOut = (IUnknown*)&This->ITfThreadMgrEventSink_iface; 626 return S_OK; 627 } 628 629 static HRESULT WINAPI TfKeyTraceEventSink_QueryInterface(ITfKeyTraceEventSink *iface, REFIID riid, void **ppv) 630 { 631 if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_ITfKeyTraceEventSink, riid)) { 632 *ppv = iface; 633 return S_OK; 634 } 635 636 *ppv = NULL; 637 return E_NOINTERFACE; 638 } 639 640 static ULONG WINAPI TfKeyTraceEventSink_AddRef(ITfKeyTraceEventSink *iface) 641 { 642 return 2; 643 } 644 645 static ULONG WINAPI TfKeyTraceEventSink_Release(ITfKeyTraceEventSink *iface) 646 { 647 return 1; 648 } 649 650 static HRESULT WINAPI TfKeyTraceEventSink_OnKeyTraceDown(ITfKeyTraceEventSink *iface, 651 WPARAM wparam, LPARAM lparam) 652 { 653 ok(0, "unexpected call\n"); 654 return E_NOTIMPL; 655 } 656 657 static HRESULT WINAPI TfKeyTraceEventSink_OnKeyTraceUp(ITfKeyTraceEventSink *iface, 658 WPARAM wparam, LPARAM lparam) 659 { 660 ok(0, "unexpected call\n"); 661 return E_NOTIMPL; 662 } 663 664 static const ITfKeyTraceEventSinkVtbl TfKeyTraceEventSinkVtbl = { 665 TfKeyTraceEventSink_QueryInterface, 666 TfKeyTraceEventSink_AddRef, 667 TfKeyTraceEventSink_Release, 668 TfKeyTraceEventSink_OnKeyTraceDown, 669 TfKeyTraceEventSink_OnKeyTraceUp 670 }; 671 672 static ITfKeyTraceEventSink TfKeyTraceEventSink = { &TfKeyTraceEventSinkVtbl }; 673 674 static HRESULT WINAPI TfTransitoryExtensionSink_QueryInterface(ITfTransitoryExtensionSink *iface, REFIID riid, void **ppv) 675 { 676 if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_ITfTransitoryExtensionSink, riid)) { 677 *ppv = iface; 678 return S_OK; 679 } 680 681 *ppv = NULL; 682 return E_NOINTERFACE; 683 } 684 685 static ULONG WINAPI TfTransitoryExtensionSink_AddRef(ITfTransitoryExtensionSink *iface) 686 { 687 return 2; 688 } 689 690 static ULONG WINAPI TfTransitoryExtensionSink_Release(ITfTransitoryExtensionSink *iface) 691 { 692 return 1; 693 } 694 695 static HRESULT WINAPI TfTransitoryExtensionSink_OnTransitoryExtensionUpdated(ITfTransitoryExtensionSink *iface, ITfContext *pic, 696 TfEditCookie ecReadOnly, ITfRange *pResultRange, ITfRange *pCompositionRange, BOOL *pfDeleteResultRange) 697 { 698 ok(0, "unexpected call\n"); 699 return E_NOTIMPL; 700 } 701 702 static const ITfTransitoryExtensionSinkVtbl TfTransitoryExtensionSinkVtbl = { 703 TfTransitoryExtensionSink_QueryInterface, 704 TfTransitoryExtensionSink_AddRef, 705 TfTransitoryExtensionSink_Release, 706 TfTransitoryExtensionSink_OnTransitoryExtensionUpdated 707 }; 708 709 static ITfTransitoryExtensionSink TfTransitoryExtensionSink = { &TfTransitoryExtensionSinkVtbl }; 710 711 /******************************************************************************************** 712 * Stub text service for testing 713 ********************************************************************************************/ 714 715 static LONG TS_refCount; 716 static IClassFactory *cf; 717 static DWORD regid; 718 719 typedef HRESULT (*LPFNCONSTRUCTOR)(IUnknown *pUnkOuter, IUnknown **ppvOut); 720 721 typedef struct tagClassFactory 722 { 723 IClassFactory IClassFactory_iface; 724 LONG ref; 725 LPFNCONSTRUCTOR ctor; 726 } ClassFactory; 727 728 static inline ClassFactory *impl_from_IClassFactory(IClassFactory *iface) 729 { 730 return CONTAINING_RECORD(iface, ClassFactory, IClassFactory_iface); 731 } 732 733 typedef struct tagTextService 734 { 735 ITfTextInputProcessor ITfTextInputProcessor_iface; 736 LONG refCount; 737 } TextService; 738 739 static inline TextService *impl_from_ITfTextInputProcessor(ITfTextInputProcessor *iface) 740 { 741 return CONTAINING_RECORD(iface, TextService, ITfTextInputProcessor_iface); 742 } 743 744 static void ClassFactory_Destructor(ClassFactory *This) 745 { 746 HeapFree(GetProcessHeap(),0,This); 747 TS_refCount--; 748 } 749 750 static HRESULT WINAPI ClassFactory_QueryInterface(IClassFactory *iface, REFIID riid, LPVOID *ppvOut) 751 { 752 *ppvOut = NULL; 753 if (IsEqualIID(riid, &IID_IClassFactory) || IsEqualIID(riid, &IID_IUnknown)) 754 { 755 IClassFactory_AddRef(iface); 756 *ppvOut = iface; 757 return S_OK; 758 } 759 760 return E_NOINTERFACE; 761 } 762 763 static ULONG WINAPI ClassFactory_AddRef(IClassFactory *iface) 764 { 765 ClassFactory *This = impl_from_IClassFactory(iface); 766 return InterlockedIncrement(&This->ref); 767 } 768 769 static ULONG WINAPI ClassFactory_Release(IClassFactory *iface) 770 { 771 ClassFactory *This = impl_from_IClassFactory(iface); 772 ULONG ret = InterlockedDecrement(&This->ref); 773 774 if (ret == 0) 775 ClassFactory_Destructor(This); 776 return ret; 777 } 778 779 static HRESULT WINAPI ClassFactory_CreateInstance(IClassFactory *iface, IUnknown *punkOuter, REFIID iid, LPVOID *ppvOut) 780 { 781 ClassFactory *This = impl_from_IClassFactory(iface); 782 HRESULT ret; 783 IUnknown *obj; 784 785 ret = This->ctor(punkOuter, &obj); 786 if (FAILED(ret)) 787 return ret; 788 ret = IUnknown_QueryInterface(obj, iid, ppvOut); 789 IUnknown_Release(obj); 790 return ret; 791 } 792 793 static HRESULT WINAPI ClassFactory_LockServer(IClassFactory *iface, BOOL fLock) 794 { 795 if(fLock) 796 InterlockedIncrement(&TS_refCount); 797 else 798 InterlockedDecrement(&TS_refCount); 799 800 return S_OK; 801 } 802 803 static const IClassFactoryVtbl ClassFactoryVtbl = { 804 /* IUnknown */ 805 ClassFactory_QueryInterface, 806 ClassFactory_AddRef, 807 ClassFactory_Release, 808 809 /* IClassFactory*/ 810 ClassFactory_CreateInstance, 811 ClassFactory_LockServer 812 }; 813 814 static HRESULT ClassFactory_Constructor(LPFNCONSTRUCTOR ctor, LPVOID *ppvOut) 815 { 816 ClassFactory *This = HeapAlloc(GetProcessHeap(),0,sizeof(ClassFactory)); 817 This->IClassFactory_iface.lpVtbl = &ClassFactoryVtbl; 818 This->ref = 1; 819 This->ctor = ctor; 820 *ppvOut = &This->IClassFactory_iface; 821 TS_refCount++; 822 return S_OK; 823 } 824 825 static void TextService_Destructor(TextService *This) 826 { 827 HeapFree(GetProcessHeap(),0,This); 828 } 829 830 static HRESULT WINAPI TextService_QueryInterface(ITfTextInputProcessor *iface, REFIID iid, LPVOID *ppvOut) 831 { 832 *ppvOut = NULL; 833 834 if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_ITfTextInputProcessor)) 835 { 836 *ppvOut = iface; 837 } 838 839 if (*ppvOut) 840 { 841 ITfTextInputProcessor_AddRef(iface); 842 return S_OK; 843 } 844 845 return E_NOINTERFACE; 846 } 847 848 static ULONG WINAPI TextService_AddRef(ITfTextInputProcessor *iface) 849 { 850 TextService *This = impl_from_ITfTextInputProcessor(iface); 851 return InterlockedIncrement(&This->refCount); 852 } 853 854 static ULONG WINAPI TextService_Release(ITfTextInputProcessor *iface) 855 { 856 TextService *This = impl_from_ITfTextInputProcessor(iface); 857 ULONG ret; 858 859 ret = InterlockedDecrement(&This->refCount); 860 if (ret == 0) 861 TextService_Destructor(This); 862 return ret; 863 } 864 865 static HRESULT WINAPI TextService_Activate(ITfTextInputProcessor *iface, 866 ITfThreadMgr *ptim, TfClientId id) 867 { 868 trace("TextService_Activate\n"); 869 ok(test_ShouldActivate,"Activation came unexpectedly\n"); 870 tid = id; 871 return S_OK; 872 } 873 874 static HRESULT WINAPI TextService_Deactivate(ITfTextInputProcessor *iface) 875 { 876 trace("TextService_Deactivate\n"); 877 ok(test_ShouldDeactivate,"Deactivation came unexpectedly\n"); 878 return S_OK; 879 } 880 881 static const ITfTextInputProcessorVtbl TextService_TextInputProcessorVtbl= 882 { 883 TextService_QueryInterface, 884 TextService_AddRef, 885 TextService_Release, 886 887 TextService_Activate, 888 TextService_Deactivate 889 }; 890 891 static HRESULT TextService_Constructor(IUnknown *pUnkOuter, IUnknown **ppOut) 892 { 893 TextService *This; 894 if (pUnkOuter) 895 return CLASS_E_NOAGGREGATION; 896 897 This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(TextService)); 898 if (This == NULL) 899 return E_OUTOFMEMORY; 900 901 This->ITfTextInputProcessor_iface.lpVtbl = &TextService_TextInputProcessorVtbl; 902 This->refCount = 1; 903 904 *ppOut = (IUnknown*)&This->ITfTextInputProcessor_iface; 905 return S_OK; 906 } 907 908 static HRESULT RegisterTextService(REFCLSID rclsid) 909 { 910 ClassFactory_Constructor( TextService_Constructor ,(LPVOID*)&cf); 911 return CoRegisterClassObject(rclsid, (IUnknown*) cf, CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, ®id); 912 } 913 914 static HRESULT UnregisterTextService(void) 915 { 916 return CoRevokeClassObject(regid); 917 } 918 919 /* 920 * The tests 921 */ 922 923 DEFINE_GUID(CLSID_FakeService, 0xEDE1A7AD,0x66DE,0x47E0,0xB6,0x20,0x3E,0x92,0xF8,0x24,0x6B,0xF3); 924 DEFINE_GUID(CLSID_TF_InputProcessorProfiles, 0x33c53a50,0xf456,0x4884,0xb0,0x49,0x85,0xfd,0x64,0x3e,0xcf,0xed); 925 DEFINE_GUID(CLSID_TF_CategoryMgr, 0xA4B544A1,0x438D,0x4B41,0x93,0x25,0x86,0x95,0x23,0xE2,0xD6,0xC7); 926 DEFINE_GUID(GUID_TFCAT_TIP_KEYBOARD, 0x34745c63,0xb2f0,0x4784,0x8b,0x67,0x5e,0x12,0xc8,0x70,0x1a,0x31); 927 DEFINE_GUID(GUID_TFCAT_TIP_SPEECH, 0xB5A73CD1,0x8355,0x426B,0xA1,0x61,0x25,0x98,0x08,0xF2,0x6B,0x14); 928 DEFINE_GUID(GUID_TFCAT_TIP_HANDWRITING, 0x246ecb87,0xc2f2,0x4abe,0x90,0x5b,0xc8,0xb3,0x8a,0xdd,0x2c,0x43); 929 DEFINE_GUID (GUID_TFCAT_DISPLAYATTRIBUTEPROVIDER, 0x046B8C80,0x1647,0x40F7,0x9B,0x21,0xB9,0x3B,0x81,0xAA,0xBC,0x1B); 930 DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0); 931 DEFINE_GUID(CLSID_TF_ThreadMgr, 0x529a9e6b,0x6587,0x4f23,0xab,0x9e,0x9c,0x7d,0x68,0x3e,0x3c,0x50); 932 DEFINE_GUID(CLSID_PreservedKey, 0xA0ED8E55,0xCD3B,0x4274,0xB2,0x95,0xF6,0xC9,0xBA,0x2B,0x84,0x72); 933 DEFINE_GUID(GUID_COMPARTMENT_KEYBOARD_DISABLED, 0x71a5b253,0x1951,0x466b,0x9f,0xbc,0x9c,0x88,0x08,0xfa,0x84,0xf2); 934 DEFINE_GUID(GUID_COMPARTMENT_KEYBOARD_OPENCLOSE, 0x58273aad,0x01bb,0x4164,0x95,0xc6,0x75,0x5b,0xa0,0xb5,0x16,0x2d); 935 DEFINE_GUID(GUID_COMPARTMENT_HANDWRITING_OPENCLOSE, 0xf9ae2c6b,0x1866,0x4361,0xaf,0x72,0x7a,0xa3,0x09,0x48,0x89,0x0e); 936 DEFINE_GUID(GUID_COMPARTMENT_SPEECH_DISABLED, 0x56c5c607,0x0703,0x4e59,0x8e,0x52,0xcb,0xc8,0x4e,0x8b,0xbe,0x35); 937 DEFINE_GUID(GUID_COMPARTMENT_SPEECH_OPENCLOSE, 0x544d6a63,0xe2e8,0x4752,0xbb,0xd1,0x00,0x09,0x60,0xbc,0xa0,0x83); 938 DEFINE_GUID(GUID_COMPARTMENT_SPEECH_GLOBALSTATE, 0x2a54fe8e,0x0d08,0x460c,0xa7,0x5d,0x87,0x03,0x5f,0xf4,0x36,0xc5); 939 DEFINE_GUID(GUID_COMPARTMENT_PERSISTMENUENABLED, 0x575f3783,0x70c8,0x47c8,0xae,0x5d,0x91,0xa0,0x1a,0x1f,0x75,0x92); 940 DEFINE_GUID(GUID_COMPARTMENT_EMPTYCONTEXT, 0xd7487dbf,0x804e,0x41c5,0x89,0x4d,0xad,0x96,0xfd,0x4e,0xea,0x13); 941 DEFINE_GUID(GUID_COMPARTMENT_TIPUISTATUS, 0x148ca3ec,0x0366,0x401c,0x8d,0x75,0xed,0x97,0x8d,0x85,0xfb,0xc9); 942 943 static HRESULT initialize(void) 944 { 945 HRESULT hr; 946 HKEY hkey; 947 948 CoInitialize(NULL); 949 950 if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\CTF\\TIP", 0, 951 KEY_READ|KEY_WRITE, &hkey) != ERROR_SUCCESS) 952 { 953 skip("Not enough permission to register input processor\n"); 954 return E_FAIL; 955 } 956 RegCloseKey(hkey); 957 958 hr = CoCreateInstance (&CLSID_TF_InputProcessorProfiles, NULL, 959 CLSCTX_INPROC_SERVER, &IID_ITfInputProcessorProfiles, (void**)&g_ipp); 960 if (SUCCEEDED(hr)) 961 hr = CoCreateInstance (&CLSID_TF_CategoryMgr, NULL, 962 CLSCTX_INPROC_SERVER, &IID_ITfCategoryMgr, (void**)&g_cm); 963 if (SUCCEEDED(hr)) 964 hr = CoCreateInstance (&CLSID_TF_ThreadMgr, NULL, 965 CLSCTX_INPROC_SERVER, &IID_ITfThreadMgr, (void**)&g_tm); 966 return hr; 967 } 968 969 static void cleanup(void) 970 { 971 if (g_ipp) 972 ITfInputProcessorProfiles_Release(g_ipp); 973 if (g_cm) 974 ITfCategoryMgr_Release(g_cm); 975 if (g_tm) 976 ITfThreadMgr_Release(g_tm); 977 CoUninitialize(); 978 } 979 980 static void test_Register(void) 981 { 982 HRESULT hr; 983 984 static const WCHAR szDesc[] = {'F','a','k','e',' ','W','i','n','e',' ','S','e','r','v','i','c','e',0}; 985 static const WCHAR szFile[] = {'F','a','k','e',' ','W','i','n','e',' ','S','e','r','v','i','c','e',' ','F','i','l','e',0}; 986 987 hr = ITfInputProcessorProfiles_GetCurrentLanguage(g_ipp,&gLangid); 988 ok(SUCCEEDED(hr),"Unable to get current language id\n"); 989 trace("Current Language %x\n",gLangid); 990 991 hr = RegisterTextService(&CLSID_FakeService); 992 ok(SUCCEEDED(hr),"Unable to register COM for TextService\n"); 993 hr = ITfInputProcessorProfiles_Register(g_ipp, &CLSID_FakeService); 994 ok(SUCCEEDED(hr),"Unable to register text service(%x)\n",hr); 995 hr = ITfInputProcessorProfiles_AddLanguageProfile(g_ipp, &CLSID_FakeService, gLangid, 996 &CLSID_FakeService, szDesc, ARRAY_SIZE(szDesc), szFile, ARRAY_SIZE(szFile), 1); 997 ok(SUCCEEDED(hr),"Unable to add Language Profile (%x)\n",hr); 998 } 999 1000 static void test_Unregister(void) 1001 { 1002 HRESULT hr; 1003 hr = ITfInputProcessorProfiles_Unregister(g_ipp, &CLSID_FakeService); 1004 ok(SUCCEEDED(hr),"Unable to unregister text service(%x)\n",hr); 1005 UnregisterTextService(); 1006 } 1007 1008 static void test_EnumInputProcessorInfo(void) 1009 { 1010 IEnumGUID *ppEnum; 1011 BOOL found = FALSE; 1012 1013 if (SUCCEEDED(ITfInputProcessorProfiles_EnumInputProcessorInfo(g_ipp, &ppEnum))) 1014 { 1015 ULONG fetched; 1016 GUID g; 1017 while (IEnumGUID_Next(ppEnum, 1, &g, &fetched) == S_OK) 1018 { 1019 if(IsEqualGUID(&g,&CLSID_FakeService)) 1020 found = TRUE; 1021 } 1022 IEnumGUID_Release(ppEnum); 1023 } 1024 ok(found,"Did not find registered text service\n"); 1025 } 1026 1027 static void test_EnumLanguageProfiles(void) 1028 { 1029 BOOL found = FALSE; 1030 IEnumTfLanguageProfiles *ppEnum; 1031 HRESULT hr; 1032 1033 hr = ITfInputProcessorProfiles_EnumLanguageProfiles(g_ipp, gLangid, NULL); 1034 ok(hr == E_INVALIDARG, "EnumLanguageProfiles failed: %x\n", hr); 1035 1036 if (SUCCEEDED(ITfInputProcessorProfiles_EnumLanguageProfiles(g_ipp,gLangid,&ppEnum))) 1037 { 1038 TF_LANGUAGEPROFILE profile; 1039 while (IEnumTfLanguageProfiles_Next(ppEnum,1,&profile,NULL)==S_OK) 1040 { 1041 if (IsEqualGUID(&profile.clsid,&CLSID_FakeService)) 1042 { 1043 found = TRUE; 1044 ok(profile.langid == gLangid, "LangId Incorrect\n"); 1045 ok(IsEqualGUID(&profile.catid,&GUID_TFCAT_TIP_KEYBOARD) || 1046 broken(IsEqualGUID(&profile.catid,&GUID_NULL) /* Win8 */), "CatId Incorrect\n"); 1047 ok(IsEqualGUID(&profile.guidProfile,&CLSID_FakeService), "guidProfile Incorrect\n"); 1048 } 1049 } 1050 IEnumTfLanguageProfiles_Release(ppEnum); 1051 } 1052 ok(found,"Registered text service not found\n"); 1053 } 1054 1055 static void test_RegisterCategory(void) 1056 { 1057 HRESULT hr; 1058 hr = ITfCategoryMgr_RegisterCategory(g_cm, &CLSID_FakeService, &GUID_TFCAT_TIP_KEYBOARD, &CLSID_FakeService); 1059 ok(SUCCEEDED(hr),"ITfCategoryMgr_RegisterCategory failed\n"); 1060 hr = ITfCategoryMgr_RegisterCategory(g_cm, &CLSID_FakeService, &GUID_TFCAT_DISPLAYATTRIBUTEPROVIDER, &CLSID_FakeService); 1061 ok(SUCCEEDED(hr),"ITfCategoryMgr_RegisterCategory failed\n"); 1062 } 1063 1064 static void test_UnregisterCategory(void) 1065 { 1066 HRESULT hr; 1067 hr = ITfCategoryMgr_UnregisterCategory(g_cm, &CLSID_FakeService, &GUID_TFCAT_TIP_KEYBOARD, &CLSID_FakeService); 1068 ok(SUCCEEDED(hr),"ITfCategoryMgr_UnregisterCategory failed\n"); 1069 hr = ITfCategoryMgr_UnregisterCategory(g_cm, &CLSID_FakeService, &GUID_TFCAT_DISPLAYATTRIBUTEPROVIDER, &CLSID_FakeService); 1070 ok(SUCCEEDED(hr),"ITfCategoryMgr_UnregisterCategory failed\n"); 1071 } 1072 1073 static void test_FindClosestCategory(void) 1074 { 1075 GUID output; 1076 HRESULT hr; 1077 const GUID *list[3] = {&GUID_TFCAT_TIP_SPEECH, &GUID_TFCAT_TIP_KEYBOARD, &GUID_TFCAT_TIP_HANDWRITING}; 1078 1079 hr = ITfCategoryMgr_FindClosestCategory(g_cm, &CLSID_FakeService, &output, NULL, 0); 1080 ok(SUCCEEDED(hr),"ITfCategoryMgr_FindClosestCategory failed (%x)\n",hr); 1081 ok(IsEqualGUID(&output,&GUID_TFCAT_DISPLAYATTRIBUTEPROVIDER),"Wrong GUID\n"); 1082 1083 hr = ITfCategoryMgr_FindClosestCategory(g_cm, &CLSID_FakeService, &output, list, 1); 1084 ok(SUCCEEDED(hr),"ITfCategoryMgr_FindClosestCategory failed (%x)\n",hr); 1085 ok(IsEqualGUID(&output,&GUID_NULL),"Wrong GUID\n"); 1086 1087 hr = ITfCategoryMgr_FindClosestCategory(g_cm, &CLSID_FakeService, &output, list, 3); 1088 ok(SUCCEEDED(hr),"ITfCategoryMgr_FindClosestCategory failed (%x)\n",hr); 1089 ok(IsEqualGUID(&output,&GUID_TFCAT_TIP_KEYBOARD),"Wrong GUID\n"); 1090 } 1091 1092 static void test_Enable(void) 1093 { 1094 HRESULT hr; 1095 BOOL enabled = FALSE; 1096 1097 hr = ITfInputProcessorProfiles_EnableLanguageProfile(g_ipp,&CLSID_FakeService, gLangid, &CLSID_FakeService, TRUE); 1098 ok(SUCCEEDED(hr),"Failed to enable text service\n"); 1099 hr = ITfInputProcessorProfiles_IsEnabledLanguageProfile(g_ipp,&CLSID_FakeService, gLangid, &CLSID_FakeService, &enabled); 1100 ok(SUCCEEDED(hr),"Failed to get enabled state\n"); 1101 ok(enabled == TRUE,"enabled state incorrect\n"); 1102 } 1103 1104 static void test_Disable(void) 1105 { 1106 HRESULT hr; 1107 1108 trace("Disabling\n"); 1109 hr = ITfInputProcessorProfiles_EnableLanguageProfile(g_ipp,&CLSID_FakeService, gLangid, &CLSID_FakeService, FALSE); 1110 ok(SUCCEEDED(hr),"Failed to disable text service\n"); 1111 } 1112 1113 static void test_ThreadMgrAdviseSinks(void) 1114 { 1115 ITfSource *source = NULL; 1116 HRESULT hr; 1117 IUnknown *sink; 1118 1119 hr = ITfThreadMgr_QueryInterface(g_tm, &IID_ITfSource, (LPVOID*)&source); 1120 ok(SUCCEEDED(hr),"Failed to get IID_ITfSource for ThreadMgr\n"); 1121 if (!source) 1122 return; 1123 1124 hr = ThreadMgrEventSink_Constructor(&sink); 1125 ok(hr == S_OK, "got %08x\n", hr); 1126 if(FAILED(hr)) return; 1127 1128 tmSinkRefCount = 1; 1129 tmSinkCookie = 0; 1130 hr = ITfSource_AdviseSink(source,&IID_ITfThreadMgrEventSink, sink, &tmSinkCookie); 1131 ok(hr == S_OK, "Failed to Advise Sink\n"); 1132 ok(tmSinkCookie!=0,"Failed to get sink cookie\n"); 1133 1134 /* Advising the sink adds a ref, Releasing here lets the object be deleted 1135 when unadvised */ 1136 tmSinkRefCount = 2; 1137 IUnknown_Release(sink); 1138 1139 hr = ITfSource_AdviseSink(source, &IID_ITfKeyTraceEventSink, (IUnknown*)&TfKeyTraceEventSink, 1140 &key_trace_sink_cookie); 1141 ok(hr == S_OK, "Failed to Advise Sink\n"); 1142 1143 ITfSource_Release(source); 1144 } 1145 1146 static void test_ThreadMgrUnadviseSinks(void) 1147 { 1148 ITfSource *source = NULL; 1149 HRESULT hr; 1150 1151 hr = ITfThreadMgr_QueryInterface(g_tm, &IID_ITfSource, (LPVOID*)&source); 1152 ok(SUCCEEDED(hr),"Failed to get IID_ITfSource for ThreadMgr\n"); 1153 if (!source) 1154 return; 1155 1156 tmSinkRefCount = 1; 1157 hr = ITfSource_UnadviseSink(source, tmSinkCookie); 1158 ok(hr == S_OK, "Failed to unadvise Sink\n"); 1159 1160 hr = ITfSource_UnadviseSink(source, key_trace_sink_cookie); 1161 ok(hr == S_OK, "Failed to unadvise Sink\n"); 1162 1163 ITfSource_Release(source); 1164 } 1165 1166 static void test_DocumentMgrAdviseSinks(void) 1167 { 1168 ITfSource *source; 1169 HRESULT hr; 1170 1171 hr = ITfDocumentMgr_QueryInterface(g_dm, &IID_ITfSource, (void**)&source); 1172 ok(hr == S_OK,"Failed to get IID_ITfSource for DocumentMgr\n"); 1173 1174 dmSinkCookie = 0; 1175 hr = ITfSource_AdviseSink(source, &IID_ITfTransitoryExtensionSink, (IUnknown*)&TfTransitoryExtensionSink, &dmSinkCookie); 1176 ok(hr == S_OK,"Failed to Advise Sink\n"); 1177 1178 ITfSource_Release(source); 1179 } 1180 1181 static void test_DocumentMgrUnadviseSinks(void) 1182 { 1183 ITfSource *source = NULL; 1184 HRESULT hr; 1185 1186 hr = ITfDocumentMgr_QueryInterface(g_dm, &IID_ITfSource, (void**)&source); 1187 ok(hr == S_OK,"Failed to get IID_ITfSource for DocumentMgr\n"); 1188 1189 hr = ITfSource_UnadviseSink(source, dmSinkCookie); 1190 ok(hr == S_OK,"Failed to unadvise Sink\n"); 1191 ITfSource_Release(source); 1192 } 1193 1194 /********************************************************************** 1195 * ITfKeyEventSink 1196 **********************************************************************/ 1197 typedef struct tagKeyEventSink 1198 { 1199 ITfKeyEventSink ITfKeyEventSink_iface; 1200 LONG refCount; 1201 } KeyEventSink; 1202 1203 static inline KeyEventSink *impl_from_ITfKeyEventSink(ITfKeyEventSink *iface) 1204 { 1205 return CONTAINING_RECORD(iface, KeyEventSink, ITfKeyEventSink_iface); 1206 } 1207 1208 static void KeyEventSink_Destructor(KeyEventSink *This) 1209 { 1210 HeapFree(GetProcessHeap(),0,This); 1211 } 1212 1213 static HRESULT WINAPI KeyEventSink_QueryInterface(ITfKeyEventSink *iface, REFIID iid, LPVOID *ppvOut) 1214 { 1215 *ppvOut = NULL; 1216 1217 if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_ITfKeyEventSink)) 1218 { 1219 *ppvOut = iface; 1220 } 1221 1222 if (*ppvOut) 1223 { 1224 ITfKeyEventSink_AddRef(iface); 1225 return S_OK; 1226 } 1227 1228 return E_NOINTERFACE; 1229 } 1230 1231 static ULONG WINAPI KeyEventSink_AddRef(ITfKeyEventSink *iface) 1232 { 1233 KeyEventSink *This = impl_from_ITfKeyEventSink(iface); 1234 return InterlockedIncrement(&This->refCount); 1235 } 1236 1237 static ULONG WINAPI KeyEventSink_Release(ITfKeyEventSink *iface) 1238 { 1239 KeyEventSink *This = impl_from_ITfKeyEventSink(iface); 1240 ULONG ret; 1241 1242 ret = InterlockedDecrement(&This->refCount); 1243 if (ret == 0) 1244 KeyEventSink_Destructor(This); 1245 return ret; 1246 } 1247 1248 static HRESULT WINAPI KeyEventSink_OnSetFocus(ITfKeyEventSink *iface, 1249 BOOL fForeground) 1250 { 1251 sink_fire_ok(&test_KEV_OnSetFocus,"KeyEventSink_OnSetFocus"); 1252 return S_OK; 1253 } 1254 1255 static HRESULT WINAPI KeyEventSink_OnTestKeyDown(ITfKeyEventSink *iface, 1256 ITfContext *pic, WPARAM wParam, LPARAM lParam, BOOL *pfEaten) 1257 { 1258 trace("\n"); 1259 return S_OK; 1260 } 1261 1262 static HRESULT WINAPI KeyEventSink_OnTestKeyUp(ITfKeyEventSink *iface, 1263 ITfContext *pic, WPARAM wParam, LPARAM lParam, BOOL *pfEaten) 1264 { 1265 trace("\n"); 1266 return S_OK; 1267 } 1268 1269 static HRESULT WINAPI KeyEventSink_OnKeyDown(ITfKeyEventSink *iface, 1270 ITfContext *pic, WPARAM wParam, LPARAM lParam, BOOL *pfEaten) 1271 { 1272 trace("\n"); 1273 return S_OK; 1274 } 1275 1276 static HRESULT WINAPI KeyEventSink_OnKeyUp(ITfKeyEventSink *iface, 1277 ITfContext *pic, WPARAM wParam, LPARAM lParam, BOOL *pfEaten) 1278 { 1279 trace("\n"); 1280 return S_OK; 1281 } 1282 1283 static HRESULT WINAPI KeyEventSink_OnPreservedKey(ITfKeyEventSink *iface, 1284 ITfContext *pic, REFGUID rguid, BOOL *pfEaten) 1285 { 1286 trace("\n"); 1287 return S_OK; 1288 } 1289 1290 static const ITfKeyEventSinkVtbl KeyEventSink_KeyEventSinkVtbl = 1291 { 1292 KeyEventSink_QueryInterface, 1293 KeyEventSink_AddRef, 1294 KeyEventSink_Release, 1295 1296 KeyEventSink_OnSetFocus, 1297 KeyEventSink_OnTestKeyDown, 1298 KeyEventSink_OnTestKeyUp, 1299 KeyEventSink_OnKeyDown, 1300 KeyEventSink_OnKeyUp, 1301 KeyEventSink_OnPreservedKey 1302 }; 1303 1304 static HRESULT KeyEventSink_Constructor(ITfKeyEventSink **ppOut) 1305 { 1306 KeyEventSink *This; 1307 1308 This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(KeyEventSink)); 1309 if (This == NULL) 1310 return E_OUTOFMEMORY; 1311 1312 This->ITfKeyEventSink_iface.lpVtbl = &KeyEventSink_KeyEventSinkVtbl; 1313 This->refCount = 1; 1314 1315 *ppOut = &This->ITfKeyEventSink_iface; 1316 return S_OK; 1317 } 1318 1319 1320 static void test_KeystrokeMgr(void) 1321 { 1322 ITfKeystrokeMgr *keymgr= NULL; 1323 HRESULT hr; 1324 TF_PRESERVEDKEY tfpk; 1325 BOOL preserved; 1326 ITfKeyEventSink *sink = NULL; 1327 1328 KeyEventSink_Constructor(&sink); 1329 1330 hr = ITfThreadMgr_QueryInterface(g_tm, &IID_ITfKeystrokeMgr, (LPVOID*)&keymgr); 1331 ok(SUCCEEDED(hr),"Failed to get IID_ITfKeystrokeMgr for ThreadMgr\n"); 1332 1333 tfpk.uVKey = 'A'; 1334 tfpk.uModifiers = TF_MOD_SHIFT; 1335 1336 test_KEV_OnSetFocus = SINK_EXPECTED; 1337 hr = ITfKeystrokeMgr_AdviseKeyEventSink(keymgr,tid,sink,TRUE); 1338 ok(SUCCEEDED(hr),"ITfKeystrokeMgr_AdviseKeyEventSink failed\n"); 1339 sink_check_ok(&test_KEV_OnSetFocus,"KeyEventSink_OnSetFocus"); 1340 hr = ITfKeystrokeMgr_AdviseKeyEventSink(keymgr,tid,sink,TRUE); 1341 ok(hr == CONNECT_E_ADVISELIMIT,"Wrong return, expected CONNECT_E_ADVISELIMIT\n"); 1342 hr = ITfKeystrokeMgr_AdviseKeyEventSink(keymgr,cid,sink,TRUE); 1343 ok(hr == E_INVALIDARG,"Wrong return, expected E_INVALIDARG\n"); 1344 1345 hr =ITfKeystrokeMgr_PreserveKey(keymgr, 0, &CLSID_PreservedKey, &tfpk, NULL, 0); 1346 ok(hr==E_INVALIDARG,"ITfKeystrokeMgr_PreserveKey improperly succeeded\n"); 1347 1348 hr =ITfKeystrokeMgr_PreserveKey(keymgr, tid, &CLSID_PreservedKey, &tfpk, NULL, 0); 1349 ok(SUCCEEDED(hr),"ITfKeystrokeMgr_PreserveKey failed\n"); 1350 1351 hr =ITfKeystrokeMgr_PreserveKey(keymgr, tid, &CLSID_PreservedKey, &tfpk, NULL, 0); 1352 ok(hr == TF_E_ALREADY_EXISTS,"ITfKeystrokeMgr_PreserveKey improperly succeeded\n"); 1353 1354 preserved = FALSE; 1355 hr = ITfKeystrokeMgr_IsPreservedKey(keymgr, &CLSID_PreservedKey, &tfpk, &preserved); 1356 ok(hr == S_OK, "ITfKeystrokeMgr_IsPreservedKey failed\n"); 1357 if (hr == S_OK) ok(preserved == TRUE,"misreporting preserved key\n"); 1358 1359 hr = ITfKeystrokeMgr_UnpreserveKey(keymgr, &CLSID_PreservedKey,&tfpk); 1360 ok(SUCCEEDED(hr),"ITfKeystrokeMgr_UnpreserveKey failed\n"); 1361 1362 hr = ITfKeystrokeMgr_IsPreservedKey(keymgr, &CLSID_PreservedKey, &tfpk, &preserved); 1363 ok(hr == S_FALSE, "ITfKeystrokeMgr_IsPreservedKey failed\n"); 1364 if (hr == S_FALSE) ok(preserved == FALSE,"misreporting preserved key\n"); 1365 1366 hr = ITfKeystrokeMgr_UnpreserveKey(keymgr, &CLSID_PreservedKey,&tfpk); 1367 ok(hr==CONNECT_E_NOCONNECTION,"ITfKeystrokeMgr_UnpreserveKey improperly succeeded\n"); 1368 1369 hr = ITfKeystrokeMgr_UnadviseKeyEventSink(keymgr,tid); 1370 ok(SUCCEEDED(hr),"ITfKeystrokeMgr_UnadviseKeyEventSink failed\n"); 1371 1372 ITfKeystrokeMgr_Release(keymgr); 1373 ITfKeyEventSink_Release(sink); 1374 } 1375 1376 static void test_Activate(void) 1377 { 1378 HRESULT hr; 1379 1380 test_ShouldActivate = TRUE; /* Win7 */ 1381 hr = ITfInputProcessorProfiles_ActivateLanguageProfile(g_ipp,&CLSID_FakeService,gLangid,&CLSID_FakeService); 1382 ok(SUCCEEDED(hr),"Failed to Activate text service\n"); 1383 test_ShouldActivate = FALSE; 1384 } 1385 1386 1387 static void test_EnumContexts(ITfDocumentMgr *dm, ITfContext *search) 1388 { 1389 HRESULT hr; 1390 IEnumTfContexts* pEnum; 1391 BOOL found = FALSE; 1392 1393 hr = ITfDocumentMgr_EnumContexts(dm,&pEnum); 1394 ok(SUCCEEDED(hr),"EnumContexts failed\n"); 1395 if (SUCCEEDED(hr)) 1396 { 1397 ULONG fetched; 1398 ITfContext *cxt; 1399 while (IEnumTfContexts_Next(pEnum, 1, &cxt, &fetched) == S_OK) 1400 { 1401 if (!search) 1402 found = TRUE; 1403 else if (search == cxt) 1404 found = TRUE; 1405 ITfContext_Release(cxt); 1406 } 1407 IEnumTfContexts_Release(pEnum); 1408 } 1409 if (search) 1410 ok(found,"Did not find proper ITfContext\n"); 1411 else 1412 ok(!found,"Found an ITfContext we should should not have\n"); 1413 } 1414 1415 static void test_EnumDocumentMgr(ITfThreadMgr *tm, ITfDocumentMgr *search, ITfDocumentMgr *absent) 1416 { 1417 HRESULT hr; 1418 IEnumTfDocumentMgrs* pEnum; 1419 BOOL found = FALSE; 1420 BOOL notfound = TRUE; 1421 1422 hr = ITfThreadMgr_EnumDocumentMgrs(tm,&pEnum); 1423 ok(SUCCEEDED(hr),"EnumDocumentMgrs failed\n"); 1424 if (SUCCEEDED(hr)) 1425 { 1426 ULONG fetched; 1427 ITfDocumentMgr *dm; 1428 while (IEnumTfDocumentMgrs_Next(pEnum, 1, &dm, &fetched) == S_OK) 1429 { 1430 if (!search) 1431 found = TRUE; 1432 else if (search == dm) 1433 found = TRUE; 1434 if (absent && dm == absent) 1435 notfound = FALSE; 1436 ITfDocumentMgr_Release(dm); 1437 } 1438 IEnumTfDocumentMgrs_Release(pEnum); 1439 } 1440 if (search) 1441 ok(found,"Did not find proper ITfDocumentMgr\n"); 1442 else 1443 ok(!found,"Found an ITfDocumentMgr we should should not have\n"); 1444 if (absent) 1445 ok(notfound,"Found an ITfDocumentMgr we believe should be absent\n"); 1446 } 1447 1448 static inline int check_context_refcount(ITfContext *iface) 1449 { 1450 ITfContext_AddRef(iface); 1451 return ITfContext_Release(iface); 1452 } 1453 1454 1455 /********************************************************************** 1456 * ITfTextEditSink 1457 **********************************************************************/ 1458 typedef struct tagTextEditSink 1459 { 1460 ITfTextEditSink ITfTextEditSink_iface; 1461 LONG refCount; 1462 } TextEditSink; 1463 1464 static inline TextEditSink *impl_from_ITfTextEditSink(ITfTextEditSink *iface) 1465 { 1466 return CONTAINING_RECORD(iface, TextEditSink, ITfTextEditSink_iface); 1467 } 1468 1469 static void TextEditSink_Destructor(TextEditSink *This) 1470 { 1471 HeapFree(GetProcessHeap(),0,This); 1472 } 1473 1474 static HRESULT WINAPI TextEditSink_QueryInterface(ITfTextEditSink *iface, REFIID iid, LPVOID *ppvOut) 1475 { 1476 *ppvOut = NULL; 1477 1478 if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_ITfTextEditSink)) 1479 { 1480 *ppvOut = iface; 1481 } 1482 1483 if (*ppvOut) 1484 { 1485 ITfTextEditSink_AddRef(iface); 1486 return S_OK; 1487 } 1488 1489 return E_NOINTERFACE; 1490 } 1491 1492 static ULONG WINAPI TextEditSink_AddRef(ITfTextEditSink *iface) 1493 { 1494 TextEditSink *This = impl_from_ITfTextEditSink(iface); 1495 return InterlockedIncrement(&This->refCount); 1496 } 1497 1498 static ULONG WINAPI TextEditSink_Release(ITfTextEditSink *iface) 1499 { 1500 TextEditSink *This = impl_from_ITfTextEditSink(iface); 1501 ULONG ret; 1502 1503 ret = InterlockedDecrement(&This->refCount); 1504 if (ret == 0) 1505 TextEditSink_Destructor(This); 1506 return ret; 1507 } 1508 1509 static HRESULT WINAPI TextEditSink_OnEndEdit(ITfTextEditSink *iface, 1510 ITfContext *pic, TfEditCookie ecReadOnly, ITfEditRecord *pEditRecord) 1511 { 1512 sink_fire_ok(&test_OnEndEdit,"TextEditSink_OnEndEdit"); 1513 return S_OK; 1514 } 1515 1516 static const ITfTextEditSinkVtbl TextEditSink_TextEditSinkVtbl = 1517 { 1518 TextEditSink_QueryInterface, 1519 TextEditSink_AddRef, 1520 TextEditSink_Release, 1521 1522 TextEditSink_OnEndEdit 1523 }; 1524 1525 static HRESULT TextEditSink_Constructor(ITfTextEditSink **ppOut) 1526 { 1527 TextEditSink *This; 1528 1529 *ppOut = NULL; 1530 This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(TextEditSink)); 1531 if (This == NULL) 1532 return E_OUTOFMEMORY; 1533 1534 This->ITfTextEditSink_iface.lpVtbl = &TextEditSink_TextEditSinkVtbl; 1535 This->refCount = 1; 1536 1537 *ppOut = &This->ITfTextEditSink_iface; 1538 return S_OK; 1539 } 1540 1541 static void test_startSession(void) 1542 { 1543 HRESULT hr; 1544 DWORD cnt; 1545 DWORD editCookie; 1546 ITfDocumentMgr *dmtest; 1547 ITfContext *cxt,*cxt2,*cxt3,*cxtTest; 1548 ITextStoreACP *ts = NULL; 1549 TfClientId cid2 = 0; 1550 ITfThreadMgrEx *tmex; 1551 1552 hr = ITfThreadMgr_Deactivate(g_tm); 1553 ok(hr == E_UNEXPECTED,"Deactivate should have failed with E_UNEXPECTED\n"); 1554 1555 test_ShouldActivate = TRUE; 1556 hr = ITfThreadMgr_Activate(g_tm,&cid); 1557 ok(SUCCEEDED(hr),"Failed to Activate\n"); 1558 ok(cid != tid,"TextService id mistakenly matches Client id\n"); 1559 1560 test_ShouldActivate = FALSE; 1561 hr = ITfThreadMgr_Activate(g_tm,&cid2); 1562 ok(SUCCEEDED(hr),"Failed to Activate\n"); 1563 ok(cid == cid2, "Second activate client ID does not match\n"); 1564 1565 hr = ITfThreadMgr_QueryInterface(g_tm, &IID_ITfThreadMgrEx, (void **)&tmex); 1566 if (hr == S_OK) 1567 { 1568 hr = ITfThreadMgrEx_ActivateEx(tmex, &cid2, 0); 1569 ok(SUCCEEDED(hr), "Failed to Activate\n"); 1570 ok(cid == cid2, "ActivateEx client ID does not match\n"); 1571 1572 ITfThreadMgrEx_Release(tmex); 1573 } 1574 else 1575 win_skip("ITfThreadMgrEx is not supported\n"); 1576 1577 hr = ITfThreadMgr_Deactivate(g_tm); 1578 ok(SUCCEEDED(hr), "Failed to Deactivate\n"); 1579 hr = ITfThreadMgr_Deactivate(g_tm); 1580 ok(SUCCEEDED(hr), "Failed to Deactivate\n"); 1581 1582 test_EnumDocumentMgr(g_tm,NULL,NULL); 1583 1584 hr = ITfThreadMgr_CreateDocumentMgr(g_tm,&g_dm); 1585 ok(SUCCEEDED(hr),"CreateDocumentMgr failed\n"); 1586 1587 test_EnumDocumentMgr(g_tm,g_dm,NULL); 1588 1589 hr = ITfThreadMgr_CreateDocumentMgr(g_tm,&dmtest); 1590 ok(SUCCEEDED(hr),"CreateDocumentMgr failed\n"); 1591 1592 test_EnumDocumentMgr(g_tm,dmtest,NULL); 1593 1594 ITfDocumentMgr_Release(dmtest); 1595 test_EnumDocumentMgr(g_tm,g_dm,dmtest); 1596 1597 hr = ITfThreadMgr_GetFocus(g_tm,&dmtest); 1598 ok(SUCCEEDED(hr),"GetFocus Failed\n"); 1599 ok(dmtest == NULL,"Initial focus not null\n"); 1600 1601 test_CurrentFocus = g_dm; 1602 test_PrevFocus = NULL; 1603 test_OnSetFocus = SINK_OPTIONAL; /* Doesn't always fire on Win7 */ 1604 hr = ITfThreadMgr_SetFocus(g_tm,g_dm); 1605 ok(SUCCEEDED(hr),"SetFocus Failed\n"); 1606 sink_check_ok(&test_OnSetFocus,"OnSetFocus"); 1607 1608 hr = ITfThreadMgr_GetFocus(g_tm,&dmtest); 1609 ok(SUCCEEDED(hr),"GetFocus Failed\n"); 1610 ok(g_dm == dmtest,"Expected DocumentMgr not focused\n"); 1611 1612 ITfDocumentMgr_Release(g_dm); 1613 1614 hr = ITfThreadMgr_GetFocus(g_tm,&dmtest); 1615 ok(SUCCEEDED(hr),"GetFocus Failed\n"); 1616 ok(g_dm == dmtest,"Expected DocumentMgr not focused\n"); 1617 ITfDocumentMgr_Release(dmtest); 1618 1619 hr = TextStoreACP_Constructor((IUnknown**)&ts); 1620 ok(SUCCEEDED(hr),"Constructor Failed\n"); 1621 if (FAILED(hr)) return; 1622 1623 hr = ITfDocumentMgr_CreateContext(g_dm, cid, 0, (IUnknown*)ts, &cxt, &editCookie); 1624 ok(SUCCEEDED(hr),"CreateContext Failed\n"); 1625 1626 hr = ITfDocumentMgr_CreateContext(g_dm, cid, 0, NULL, &cxt2, &editCookie); 1627 ok(SUCCEEDED(hr),"CreateContext Failed\n"); 1628 1629 hr = ITfDocumentMgr_CreateContext(g_dm, cid, 0, NULL, &cxt3, &editCookie); 1630 ok(SUCCEEDED(hr),"CreateContext Failed\n"); 1631 1632 test_EnumContexts(g_dm, NULL); 1633 1634 hr = ITfContext_GetDocumentMgr(cxt,&dmtest); 1635 ok(hr == S_OK, "ITfContext_GetDocumentMgr failed with %x\n",hr); 1636 ok(dmtest == g_dm, "Wrong documentmgr\n"); 1637 ITfDocumentMgr_Release(dmtest); 1638 1639 cnt = check_context_refcount(cxt); 1640 test_OnPushContext = SINK_EXPECTED; 1641 test_ACP_AdviseSink = SINK_EXPECTED; 1642 test_OnInitDocumentMgr = SINK_EXPECTED; 1643 hr = ITfDocumentMgr_Push(g_dm, cxt); 1644 ok(SUCCEEDED(hr),"Push Failed\n"); 1645 ok(check_context_refcount(cxt) > cnt, "Ref count did not increase\n"); 1646 sink_check_ok(&test_OnPushContext,"OnPushContext"); 1647 sink_check_ok(&test_OnInitDocumentMgr,"OnInitDocumentMgr"); 1648 sink_check_ok(&test_ACP_AdviseSink,"TextStoreACP_AdviseSink"); 1649 1650 test_EnumContexts(g_dm, cxt); 1651 1652 hr = ITfDocumentMgr_GetTop(g_dm, &cxtTest); 1653 ok(SUCCEEDED(hr),"GetTop Failed\n"); 1654 ok(cxtTest == cxt, "Wrong context on top\n"); 1655 ok(check_context_refcount(cxt) > cnt, "Ref count did not increase\n"); 1656 cnt = ITfContext_Release(cxtTest); 1657 1658 hr = ITfDocumentMgr_GetBase(g_dm, &cxtTest); 1659 ok(SUCCEEDED(hr),"GetBase Failed\n"); 1660 ok(cxtTest == cxt, "Wrong context on Base\n"); 1661 ok(check_context_refcount(cxt) > cnt, "Ref count did not increase\n"); 1662 ITfContext_Release(cxtTest); 1663 1664 check_context_refcount(cxt2); 1665 test_OnPushContext = SINK_EXPECTED; 1666 hr = ITfDocumentMgr_Push(g_dm, cxt2); 1667 ok(SUCCEEDED(hr),"Push Failed\n"); 1668 sink_check_ok(&test_OnPushContext,"OnPushContext"); 1669 1670 cnt = check_context_refcount(cxt2); 1671 hr = ITfDocumentMgr_GetTop(g_dm, &cxtTest); 1672 ok(SUCCEEDED(hr),"GetTop Failed\n"); 1673 ok(cxtTest == cxt2, "Wrong context on top\n"); 1674 ok(check_context_refcount(cxt2) > cnt, "Ref count did not increase\n"); 1675 ITfContext_Release(cxtTest); 1676 1677 cnt = check_context_refcount(cxt); 1678 hr = ITfDocumentMgr_GetBase(g_dm, &cxtTest); 1679 ok(SUCCEEDED(hr),"GetBase Failed\n"); 1680 ok(cxtTest == cxt, "Wrong context on Base\n"); 1681 ok(check_context_refcount(cxt) > cnt, "Ref count did not increase\n"); 1682 ITfContext_Release(cxtTest); 1683 1684 cnt = check_context_refcount(cxt3); 1685 hr = ITfDocumentMgr_Push(g_dm, cxt3); 1686 ok(FAILED(hr),"Push Succeeded\n"); 1687 ok(check_context_refcount(cxt3) == cnt, "Ref changed\n"); 1688 1689 cnt = check_context_refcount(cxt2); 1690 hr = ITfDocumentMgr_GetTop(g_dm, &cxtTest); 1691 ok(SUCCEEDED(hr),"GetTop Failed\n"); 1692 ok(cxtTest == cxt2, "Wrong context on top\n"); 1693 ok(check_context_refcount(cxt2) > cnt, "Ref count did not increase\n"); 1694 ITfContext_Release(cxtTest); 1695 1696 cnt = check_context_refcount(cxt); 1697 hr = ITfDocumentMgr_GetBase(g_dm, &cxtTest); 1698 ok(SUCCEEDED(hr),"GetBase Failed\n"); 1699 ok(cxtTest == cxt, "Wrong context on Base\n"); 1700 ok(check_context_refcount(cxt) > cnt, "Ref count did not increase\n"); 1701 ITfContext_Release(cxtTest); 1702 1703 cnt = check_context_refcount(cxt2); 1704 test_OnPopContext = SINK_EXPECTED; 1705 hr = ITfDocumentMgr_Pop(g_dm, 0); 1706 ok(SUCCEEDED(hr),"Pop Failed\n"); 1707 ok(check_context_refcount(cxt2) < cnt, "Ref count did not decrease\n"); 1708 sink_check_ok(&test_OnPopContext,"OnPopContext"); 1709 1710 dmtest = (void *)0xfeedface; 1711 hr = ITfContext_GetDocumentMgr(cxt2,&dmtest); 1712 ok(hr == S_FALSE, "ITfContext_GetDocumentMgr wrong rc %x\n",hr); 1713 ok(dmtest == NULL,"returned documentmgr should be null\n"); 1714 1715 ITfContext_Release(cxt2); 1716 1717 hr = ITfDocumentMgr_GetTop(g_dm, &cxtTest); 1718 ok(SUCCEEDED(hr),"GetTop Failed\n"); 1719 ok(cxtTest == cxt, "Wrong context on top\n"); 1720 ITfContext_Release(cxtTest); 1721 1722 hr = ITfDocumentMgr_GetBase(g_dm, &cxtTest); 1723 ok(SUCCEEDED(hr),"GetBase Failed\n"); 1724 ok(cxtTest == cxt, "Wrong context on base\n"); 1725 ITfContext_Release(cxtTest); 1726 1727 hr = ITfDocumentMgr_CreateContext(g_dm, cid, 0, (IUnknown*)ts, &cxt2, &editCookie); 1728 ok(hr == S_OK,"CreateContext Failed\n"); 1729 1730 test_OnPushContext = SINK_EXPECTED; 1731 test_ACP_AdviseSink = SINK_EXPECTED; 1732 hr = ITfDocumentMgr_Push(g_dm, cxt2); 1733 ok(hr == S_OK,"Push Failed\n"); 1734 sink_check_ok(&test_OnPushContext,"OnPushContext"); 1735 sink_check_ok(&test_ACP_AdviseSink,"TextStoreACP_AdviseSink"); 1736 1737 test_ACP_UnadviseSink = SINK_EXPECTED; 1738 cnt = check_context_refcount(cxt2); 1739 test_OnPopContext = SINK_EXPECTED; 1740 hr = ITfDocumentMgr_Pop(g_dm, 0); 1741 ok(hr == S_OK,"Pop Failed\n"); 1742 ok(check_context_refcount(cxt2) < cnt, "Ref count did not decrease\n"); 1743 sink_check_ok(&test_OnPopContext,"OnPopContext"); 1744 sink_check_ok(&test_ACP_UnadviseSink,"TextStoreACP_AdviseSink"); 1745 1746 hr = ITfDocumentMgr_Pop(g_dm, 0); 1747 ok(FAILED(hr),"Pop Succeeded\n"); 1748 1749 hr = ITfDocumentMgr_GetTop(g_dm, &cxtTest); 1750 ok(SUCCEEDED(hr),"GetTop Failed\n"); 1751 ok(cxtTest == cxt, "Wrong context on top\n"); 1752 ITfContext_Release(cxtTest); 1753 1754 hr = ITfDocumentMgr_GetBase(g_dm, &cxtTest); 1755 ok(SUCCEEDED(hr),"GetBase Failed\n"); 1756 ok(cxtTest == cxt, "Wrong context on base\n"); 1757 ITfContext_Release(cxtTest); 1758 1759 ITfContext_Release(cxt); 1760 ITfContext_Release(cxt2); 1761 ITfContext_Release(cxt3); 1762 ITextStoreACP_Release(ts); 1763 } 1764 1765 static void test_endSession(void) 1766 { 1767 HRESULT hr; 1768 test_ShouldDeactivate = TRUE; 1769 test_CurrentFocus = NULL; 1770 test_PrevFocus = g_dm; 1771 test_OnSetFocus = SINK_OPTIONAL; /* Doesn't fire on Win7 */ 1772 hr = ITfThreadMgr_Deactivate(g_tm); 1773 ok(SUCCEEDED(hr),"Failed to Deactivate\n"); 1774 sink_check_ok(&test_OnSetFocus,"OnSetFocus"); 1775 test_OnSetFocus = SINK_UNEXPECTED; 1776 } 1777 1778 static void test_TfGuidAtom(void) 1779 { 1780 GUID gtest,g1; 1781 HRESULT hr; 1782 TfGuidAtom atom1,atom2; 1783 BOOL equal; 1784 1785 CoCreateGuid(>est); 1786 1787 /* msdn reports this should return E_INVALIDARG. However my test show it crashing (winxp)*/ 1788 /* 1789 hr = ITfCategoryMgr_RegisterGUID(g_cm,>est,NULL); 1790 ok(hr==E_INVALIDARG,"ITfCategoryMgr_RegisterGUID should have failed\n"); 1791 */ 1792 hr = ITfCategoryMgr_RegisterGUID(g_cm,>est,&atom1); 1793 ok(SUCCEEDED(hr),"ITfCategoryMgr_RegisterGUID failed\n"); 1794 hr = ITfCategoryMgr_RegisterGUID(g_cm,>est,&atom2); 1795 ok(SUCCEEDED(hr),"ITfCategoryMgr_RegisterGUID failed\n"); 1796 ok(atom1 == atom2,"atoms do not match\n"); 1797 hr = ITfCategoryMgr_GetGUID(g_cm,atom2,NULL); 1798 ok(hr==E_INVALIDARG,"ITfCategoryMgr_GetGUID should have failed\n"); 1799 hr = ITfCategoryMgr_GetGUID(g_cm,atom2,&g1); 1800 ok(SUCCEEDED(hr),"ITfCategoryMgr_GetGUID failed\n"); 1801 ok(IsEqualGUID(&g1,>est),"guids do not match\n"); 1802 hr = ITfCategoryMgr_IsEqualTfGuidAtom(g_cm,atom1,>est,NULL); 1803 ok(hr==E_INVALIDARG,"ITfCategoryMgr_IsEqualTfGuidAtom should have failed\n"); 1804 hr = ITfCategoryMgr_IsEqualTfGuidAtom(g_cm,atom1,>est,&equal); 1805 ok(SUCCEEDED(hr),"ITfCategoryMgr_IsEqualTfGuidAtom failed\n"); 1806 ok(equal == TRUE,"Equal value invalid\n"); 1807 1808 /* show that cid and tid TfClientIds are also TfGuidAtoms */ 1809 hr = ITfCategoryMgr_IsEqualTfGuidAtom(g_cm,tid,&CLSID_FakeService,&equal); 1810 ok(SUCCEEDED(hr),"ITfCategoryMgr_IsEqualTfGuidAtom failed\n"); 1811 ok(equal == TRUE,"Equal value invalid\n"); 1812 hr = ITfCategoryMgr_GetGUID(g_cm,cid,&g1); 1813 ok(SUCCEEDED(hr),"ITfCategoryMgr_GetGUID failed\n"); 1814 ok(!IsEqualGUID(&g1,&GUID_NULL),"guid should not be NULL\n"); 1815 } 1816 1817 static void test_ClientId(void) 1818 { 1819 ITfClientId *pcid; 1820 TfClientId id1,id2; 1821 HRESULT hr; 1822 GUID g2; 1823 1824 hr = ITfThreadMgr_QueryInterface(g_tm, &IID_ITfClientId, (LPVOID*)&pcid); 1825 ok(SUCCEEDED(hr),"Unable to acquire ITfClientId interface\n"); 1826 1827 CoCreateGuid(&g2); 1828 1829 hr = ITfClientId_GetClientId(pcid,&GUID_NULL,&id1); 1830 ok(SUCCEEDED(hr),"GetClientId failed\n"); 1831 hr = ITfClientId_GetClientId(pcid,&GUID_NULL,&id2); 1832 ok(SUCCEEDED(hr),"GetClientId failed\n"); 1833 ok(id1==id2,"Id's for GUID_NULL do not match\n"); 1834 hr = ITfClientId_GetClientId(pcid,&CLSID_FakeService,&id2); 1835 ok(SUCCEEDED(hr),"GetClientId failed\n"); 1836 ok(id2!=id1,"Id matches GUID_NULL\n"); 1837 ok(id2==tid,"Id for CLSID_FakeService not matching tid\n"); 1838 ok(id2!=cid,"Id for CLSID_FakeService matching cid\n"); 1839 hr = ITfClientId_GetClientId(pcid,&g2,&id2); 1840 ok(SUCCEEDED(hr),"GetClientId failed\n"); 1841 ok(id2!=id1,"Id matches GUID_NULL\n"); 1842 ok(id2!=tid,"Id for random guid matching tid\n"); 1843 ok(id2!=cid,"Id for random guid matching cid\n"); 1844 ITfClientId_Release(pcid); 1845 } 1846 1847 /********************************************************************** 1848 * ITfEditSession 1849 **********************************************************************/ 1850 typedef struct tagEditSession 1851 { 1852 ITfEditSession ITfEditSession_iface; 1853 LONG refCount; 1854 } EditSession; 1855 1856 static inline EditSession *impl_from_ITfEditSession(ITfEditSession *iface) 1857 { 1858 return CONTAINING_RECORD(iface, EditSession, ITfEditSession_iface); 1859 } 1860 1861 static void EditSession_Destructor(EditSession *This) 1862 { 1863 HeapFree(GetProcessHeap(),0,This); 1864 } 1865 1866 static HRESULT WINAPI EditSession_QueryInterface(ITfEditSession *iface, REFIID iid, LPVOID *ppvOut) 1867 { 1868 *ppvOut = NULL; 1869 1870 if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_ITfEditSession)) 1871 { 1872 *ppvOut = iface; 1873 } 1874 1875 if (*ppvOut) 1876 { 1877 ITfEditSession_AddRef(iface); 1878 return S_OK; 1879 } 1880 1881 return E_NOINTERFACE; 1882 } 1883 1884 static ULONG WINAPI EditSession_AddRef(ITfEditSession *iface) 1885 { 1886 EditSession *This = impl_from_ITfEditSession(iface); 1887 return InterlockedIncrement(&This->refCount); 1888 } 1889 1890 static ULONG WINAPI EditSession_Release(ITfEditSession *iface) 1891 { 1892 EditSession *This = impl_from_ITfEditSession(iface); 1893 ULONG ret; 1894 1895 ret = InterlockedDecrement(&This->refCount); 1896 if (ret == 0) 1897 EditSession_Destructor(This); 1898 return ret; 1899 } 1900 1901 static void test_InsertAtSelection(TfEditCookie ec, ITfContext *cxt) 1902 { 1903 HRESULT hr; 1904 ITfInsertAtSelection *iis; 1905 ITfRange *range=NULL; 1906 static const WCHAR txt[] = {'H','e','l','l','o',' ','W','o','r','l','d',0}; 1907 1908 hr = ITfContext_QueryInterface(cxt, &IID_ITfInsertAtSelection , (LPVOID*)&iis); 1909 ok(SUCCEEDED(hr),"Failed to get ITfInsertAtSelection interface\n"); 1910 test_ACP_InsertTextAtSelection = SINK_EXPECTED; 1911 hr = ITfInsertAtSelection_InsertTextAtSelection(iis, ec, 0, txt, 11, &range); 1912 ok(SUCCEEDED(hr),"ITfInsertAtSelection_InsertTextAtSelection failed %x\n",hr); 1913 sink_check_ok(&test_ACP_InsertTextAtSelection,"InsertTextAtSelection"); 1914 ok(range != NULL,"No range returned\n"); 1915 ITfRange_Release(range); 1916 ITfInsertAtSelection_Release(iis); 1917 } 1918 1919 static HRESULT WINAPI EditSession_DoEditSession(ITfEditSession *iface, 1920 TfEditCookie ec) 1921 { 1922 ITfContext *cxt; 1923 ITfDocumentMgr *dm; 1924 ITfRange *range; 1925 TF_SELECTION selection; 1926 ULONG fetched; 1927 HRESULT hr; 1928 1929 sink_fire_ok(&test_DoEditSession,"EditSession_DoEditSession"); 1930 sink_check_ok(&test_ACP_RequestLock,"RequestLock"); 1931 1932 ITfThreadMgr_GetFocus(g_tm, &dm); 1933 ITfDocumentMgr_GetTop(dm,&cxt); 1934 1935 hr = ITfContext_GetStart(cxt,ec,NULL); 1936 ok(hr == E_INVALIDARG,"Unexpected return code %x\n",hr); 1937 1938 range = (ITfRange*)0xdeaddead; 1939 hr = ITfContext_GetStart(cxt,0xdeadcafe,&range); 1940 ok(hr == TF_E_NOLOCK,"Unexpected return code %x\n",hr); 1941 ok(range == NULL,"Range not set to NULL\n"); 1942 1943 hr = ITfContext_GetStart(cxt,ec,&range); 1944 ok(SUCCEEDED(hr),"Unexpected return code %x\n",hr); 1945 ok(range != NULL,"Range set to NULL\n"); 1946 1947 ITfRange_Release(range); 1948 1949 hr = ITfContext_GetEnd(cxt,ec,NULL); 1950 ok(hr == E_INVALIDARG,"Unexpected return code %x\n",hr); 1951 1952 range = (ITfRange*)0xdeaddead; 1953 hr = ITfContext_GetEnd(cxt,0xdeadcafe,&range); 1954 ok(hr == TF_E_NOLOCK,"Unexpected return code %x\n",hr); 1955 ok(range == NULL,"Range not set to NULL\n"); 1956 1957 test_ACP_GetEndACP = SINK_EXPECTED; 1958 hr = ITfContext_GetEnd(cxt,ec,&range); 1959 ok(SUCCEEDED(hr),"Unexpected return code %x\n",hr); 1960 ok(range != NULL,"Range set to NULL\n"); 1961 sink_check_ok(&test_ACP_GetEndACP,"GetEndACP"); 1962 1963 ITfRange_Release(range); 1964 1965 selection.range = NULL; 1966 test_ACP_GetSelection = SINK_EXPECTED; 1967 hr = ITfContext_GetSelection(cxt, ec, TF_DEFAULT_SELECTION, 1, &selection, &fetched); 1968 ok(SUCCEEDED(hr),"ITfContext_GetSelection failed\n"); 1969 ok(fetched == 1,"fetched incorrect\n"); 1970 ok(selection.range != NULL,"NULL range\n"); 1971 sink_check_ok(&test_ACP_GetSelection,"GetSelection"); 1972 ITfRange_Release(selection.range); 1973 1974 test_InsertAtSelection(ec, cxt); 1975 1976 test_ACP_GetEndACP = SINK_EXPECTED; 1977 hr = ITfContext_GetEnd(cxt,ec,&range); 1978 ok(SUCCEEDED(hr),"Unexpected return code %x\n",hr); 1979 ok(range != NULL,"Range set to NULL\n"); 1980 sink_check_ok(&test_ACP_GetEndACP,"GetEndACP"); 1981 1982 selection.range = range; 1983 selection.style.ase = TF_AE_NONE; 1984 selection.style.fInterimChar = FALSE; 1985 test_ACP_SetSelection = SINK_EXPECTED; 1986 hr = ITfContext_SetSelection(cxt, ec, 1, &selection); 1987 ok(SUCCEEDED(hr),"ITfContext_SetSelection failed\n"); 1988 sink_check_ok(&test_ACP_SetSelection,"SetSelection"); 1989 ITfRange_Release(range); 1990 1991 ITfContext_Release(cxt); 1992 ITfDocumentMgr_Release(dm); 1993 return 0xdeadcafe; 1994 } 1995 1996 static const ITfEditSessionVtbl EditSession_EditSessionVtbl = 1997 { 1998 EditSession_QueryInterface, 1999 EditSession_AddRef, 2000 EditSession_Release, 2001 2002 EditSession_DoEditSession 2003 }; 2004 2005 static HRESULT EditSession_Constructor(ITfEditSession **ppOut) 2006 { 2007 EditSession *This; 2008 2009 *ppOut = NULL; 2010 This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(EditSession)); 2011 if (This == NULL) 2012 return E_OUTOFMEMORY; 2013 2014 This->ITfEditSession_iface.lpVtbl = &EditSession_EditSessionVtbl; 2015 This->refCount = 1; 2016 2017 *ppOut = &This->ITfEditSession_iface; 2018 return S_OK; 2019 } 2020 2021 static void test_TStoApplicationText(void) 2022 { 2023 HRESULT hr, hrSession; 2024 ITfEditSession *es; 2025 ITfContext *cxt; 2026 ITfDocumentMgr *dm; 2027 ITfTextEditSink *sink; 2028 ITfSource *source = NULL; 2029 DWORD editSinkCookie = -1; 2030 2031 ITfThreadMgr_GetFocus(g_tm, &dm); 2032 EditSession_Constructor(&es); 2033 ITfDocumentMgr_GetTop(dm,&cxt); 2034 2035 TextEditSink_Constructor(&sink); 2036 hr = ITfContext_QueryInterface(cxt,&IID_ITfSource,(LPVOID*)&source); 2037 ok(SUCCEEDED(hr),"Failed to get IID_ITfSource for Context\n"); 2038 if (source) 2039 { 2040 hr = ITfSource_AdviseSink(source, &IID_ITfTextEditSink, (LPVOID)sink, &editSinkCookie); 2041 ok(SUCCEEDED(hr),"Failed to advise Sink\n"); 2042 ok(editSinkCookie != -1,"Failed to get sink cookie\n"); 2043 } 2044 2045 hrSession = 0xfeedface; 2046 /* Test no permissions flags */ 2047 hr = ITfContext_RequestEditSession(cxt, tid, es, TF_ES_SYNC, &hrSession); 2048 ok(hr == E_INVALIDARG,"RequestEditSession should have failed with %x not %x\n",E_INVALIDARG,hr); 2049 ok(hrSession == E_FAIL,"hrSession should be %x not %x\n",E_FAIL,hrSession); 2050 2051 documentStatus = TS_SD_READONLY; 2052 hrSession = 0xfeedface; 2053 test_ACP_GetStatus = SINK_EXPECTED; 2054 hr = ITfContext_RequestEditSession(cxt, tid, es, TF_ES_SYNC|TF_ES_READWRITE, &hrSession); 2055 ok(SUCCEEDED(hr),"ITfContext_RequestEditSession failed\n"); 2056 ok(hrSession == TS_E_READONLY,"Unexpected hrSession (%x)\n",hrSession); 2057 sink_check_ok(&test_ACP_GetStatus,"GetStatus"); 2058 2059 /* signal a change to allow readwrite sessions */ 2060 documentStatus = 0; 2061 test_ACP_RequestLock = SINK_EXPECTED; 2062 ITextStoreACPSink_OnStatusChange(ACPSink,documentStatus); 2063 sink_check_ok(&test_ACP_RequestLock,"RequestLock"); 2064 2065 test_ACP_GetStatus = SINK_EXPECTED; 2066 test_ACP_RequestLock = SINK_EXPECTED; 2067 test_DoEditSession = SINK_EXPECTED; 2068 hrSession = 0xfeedface; 2069 test_OnEndEdit = SINK_EXPECTED; 2070 hr = ITfContext_RequestEditSession(cxt, tid, es, TF_ES_SYNC|TF_ES_READWRITE, &hrSession); 2071 ok(SUCCEEDED(hr),"ITfContext_RequestEditSession failed\n"); 2072 sink_check_ok(&test_OnEndEdit,"OnEndEdit"); 2073 sink_check_ok(&test_DoEditSession,"DoEditSession"); 2074 sink_check_ok(&test_ACP_GetStatus,"GetStatus"); 2075 ok(hrSession == 0xdeadcafe,"Unexpected hrSession (%x)\n",hrSession); 2076 2077 if (source) 2078 { 2079 hr = ITfSource_UnadviseSink(source, editSinkCookie); 2080 ok(SUCCEEDED(hr),"Failed to unadvise Sink\n"); 2081 ITfSource_Release(source); 2082 } 2083 ITfTextEditSink_Release(sink); 2084 ITfContext_Release(cxt); 2085 ITfDocumentMgr_Release(dm); 2086 ITfEditSession_Release(es); 2087 } 2088 2089 static void enum_compartments(ITfCompartmentMgr *cmpmgr, REFGUID present, REFGUID absent) 2090 { 2091 BOOL found,found2; 2092 IEnumGUID *ppEnum; 2093 found = FALSE; 2094 found2 = FALSE; 2095 if (SUCCEEDED(ITfCompartmentMgr_EnumCompartments(cmpmgr, &ppEnum))) 2096 { 2097 ULONG fetched; 2098 GUID g; 2099 while (IEnumGUID_Next(ppEnum, 1, &g, &fetched) == S_OK) 2100 { 2101 WCHAR str[50]; 2102 CHAR strA[50]; 2103 StringFromGUID2(&g,str,ARRAY_SIZE(str)); 2104 WideCharToMultiByte(CP_ACP,0,str,-1,strA,sizeof(strA),0,0); 2105 trace("found %s\n",strA); 2106 if (present && IsEqualGUID(present,&g)) 2107 found = TRUE; 2108 if (absent && IsEqualGUID(absent, &g)) 2109 found2 = TRUE; 2110 } 2111 IEnumGUID_Release(ppEnum); 2112 } 2113 if (present) 2114 ok(found,"Did not find compartment\n"); 2115 if (absent) 2116 ok(!found2,"Found compartment that should be absent\n"); 2117 } 2118 2119 static void test_Compartments(void) 2120 { 2121 ITfContext *cxt; 2122 ITfDocumentMgr *dm; 2123 ITfCompartmentMgr *cmpmgr; 2124 ITfCompartment *cmp; 2125 HRESULT hr; 2126 2127 ITfThreadMgr_GetFocus(g_tm, &dm); 2128 ITfDocumentMgr_GetTop(dm,&cxt); 2129 2130 /* Global */ 2131 hr = ITfThreadMgr_GetGlobalCompartment(g_tm, &cmpmgr); 2132 ok(SUCCEEDED(hr),"GetGlobalCompartment failed\n"); 2133 hr = ITfCompartmentMgr_GetCompartment(cmpmgr, &GUID_COMPARTMENT_SPEECH_OPENCLOSE, &cmp); 2134 ok(SUCCEEDED(hr),"GetCompartment failed\n"); 2135 ITfCompartment_Release(cmp); 2136 enum_compartments(cmpmgr,&GUID_COMPARTMENT_SPEECH_OPENCLOSE,NULL); 2137 ITfCompartmentMgr_Release(cmpmgr); 2138 2139 /* Thread */ 2140 hr = ITfThreadMgr_QueryInterface(g_tm, &IID_ITfCompartmentMgr, (LPVOID*)&cmpmgr); 2141 ok(SUCCEEDED(hr),"ThreadMgr QI for IID_ITfCompartmentMgr failed\n"); 2142 hr = ITfCompartmentMgr_GetCompartment(cmpmgr, &CLSID_FakeService, &cmp); 2143 ok(SUCCEEDED(hr),"GetCompartment failed\n"); 2144 enum_compartments(cmpmgr,&CLSID_FakeService,&GUID_COMPARTMENT_SPEECH_OPENCLOSE); 2145 ITfCompartmentMgr_ClearCompartment(cmpmgr,tid,&CLSID_FakeService); 2146 enum_compartments(cmpmgr,NULL,&CLSID_FakeService); 2147 ITfCompartmentMgr_Release(cmpmgr); 2148 ITfCompartment_Release(cmp); 2149 2150 /* DocumentMgr */ 2151 hr = ITfDocumentMgr_QueryInterface(dm, &IID_ITfCompartmentMgr, (LPVOID*)&cmpmgr); 2152 ok(SUCCEEDED(hr),"DocumentMgr QI for IID_ITfCompartmentMgr failed\n"); 2153 2154 hr = ITfCompartmentMgr_GetCompartment(cmpmgr, &GUID_COMPARTMENT_PERSISTMENUENABLED, &cmp); 2155 ok(SUCCEEDED(hr),"GetCompartment failed\n"); 2156 enum_compartments(cmpmgr,&GUID_COMPARTMENT_PERSISTMENUENABLED,&GUID_COMPARTMENT_SPEECH_OPENCLOSE); 2157 ITfCompartmentMgr_Release(cmpmgr); 2158 2159 /* Context */ 2160 hr = ITfContext_QueryInterface(cxt, &IID_ITfCompartmentMgr, (LPVOID*)&cmpmgr); 2161 ok(SUCCEEDED(hr),"Context QI for IID_ITfCompartmentMgr failed\n"); 2162 enum_compartments(cmpmgr,NULL,&GUID_COMPARTMENT_PERSISTMENUENABLED); 2163 ITfCompartmentMgr_Release(cmpmgr); 2164 2165 ITfContext_Release(cxt); 2166 ITfDocumentMgr_Release(dm); 2167 } 2168 2169 static void processPendingMessages(void) 2170 { 2171 MSG msg; 2172 int diff = 200; 2173 int min_timeout = 100; 2174 DWORD time = GetTickCount() + diff; 2175 2176 while (diff > 0) 2177 { 2178 if (MsgWaitForMultipleObjects(0, NULL, FALSE, min_timeout, QS_ALLINPUT) == WAIT_TIMEOUT) 2179 break; 2180 while (PeekMessageW(&msg, 0, 0, 0, PM_REMOVE)) 2181 { 2182 TranslateMessage(&msg); 2183 DispatchMessageW(&msg); 2184 } 2185 diff = time - GetTickCount(); 2186 } 2187 } 2188 2189 static void test_AssociateFocus(void) 2190 { 2191 ITfDocumentMgr *dm1, *dm2, *olddm, *dmcheck, *dmorig; 2192 HWND wnd1, wnd2, wnd3; 2193 HRESULT hr; 2194 2195 ITfThreadMgr_GetFocus(g_tm, &dmorig); 2196 test_CurrentFocus = NULL; 2197 test_PrevFocus = dmorig; 2198 test_OnSetFocus = SINK_OPTIONAL; /* Doesn't always fire on Win7 */ 2199 test_ACP_GetStatus = SINK_OPTIONAL; 2200 hr = ITfThreadMgr_SetFocus(g_tm,NULL); 2201 ok(SUCCEEDED(hr),"ITfThreadMgr_SetFocus failed\n"); 2202 sink_check_ok(&test_OnSetFocus,"OnSetFocus"); 2203 test_ACP_GetStatus = SINK_UNEXPECTED; 2204 ITfDocumentMgr_Release(dmorig); 2205 2206 hr = ITfThreadMgr_CreateDocumentMgr(g_tm,&dm1); 2207 ok(SUCCEEDED(hr),"CreateDocumentMgr failed\n"); 2208 2209 hr = ITfThreadMgr_CreateDocumentMgr(g_tm,&dm2); 2210 ok(SUCCEEDED(hr),"CreateDocumentMgr failed\n"); 2211 2212 wnd1 = CreateWindowA("edit",NULL,WS_POPUP,0,0,200,60,NULL,NULL,NULL,NULL); 2213 ok(wnd1!=NULL,"Unable to create window 1\n"); 2214 wnd2 = CreateWindowA("edit",NULL,WS_POPUP,0,65,200,60,NULL,NULL,NULL,NULL); 2215 ok(wnd2!=NULL,"Unable to create window 2\n"); 2216 wnd3 = CreateWindowA("edit",NULL,WS_POPUP,0,130,200,60,NULL,NULL,NULL,NULL); 2217 ok(wnd3!=NULL,"Unable to create window 3\n"); 2218 2219 processPendingMessages(); 2220 2221 test_OnInitDocumentMgr = SINK_OPTIONAL; /* Vista and greater */ 2222 test_OnPushContext = SINK_OPTIONAL; /* Vista and greater */ 2223 test_OnSetFocus = SINK_OPTIONAL; /* Win7 */ 2224 test_PrevFocus = NULL; 2225 test_CurrentFocus = FOCUS_IGNORE; 2226 2227 ShowWindow(wnd1,SW_SHOWNORMAL); 2228 test_OnSetFocus = SINK_UNEXPECTED; 2229 SetFocus(wnd1); 2230 sink_check_ok(&test_OnInitDocumentMgr,"OnInitDocumentMgr"); 2231 sink_check_ok(&test_OnPushContext,"OnPushContext"); 2232 2233 test_OnSetFocus = SINK_OPTIONAL; /* Vista and greater */ 2234 test_ACP_RequestLock = SINK_OPTIONAL; /* Win7 x64 */ 2235 test_ACP_GetSelection = SINK_OPTIONAL; /* Win7 x64 */ 2236 ITfThreadMgr_GetFocus(g_tm, &test_PrevFocus); 2237 test_CurrentFocus = FOCUS_IGNORE; /* This is a default system context */ 2238 processPendingMessages(); 2239 sink_check_ok(&test_OnSetFocus,"OnSetFocus"); 2240 test_ACP_RequestLock = SINK_UNEXPECTED; 2241 test_ACP_GetSelection = SINK_UNEXPECTED; 2242 2243 test_CurrentFocus = dm1; 2244 test_PrevFocus = FOCUS_IGNORE; 2245 test_OnSetFocus = SINK_OPTIONAL; 2246 test_ShouldDeactivate = TRUE; 2247 hr = ITfThreadMgr_AssociateFocus(g_tm,wnd1,dm1,&olddm); 2248 ok(SUCCEEDED(hr),"AssociateFocus failed\n"); 2249 sink_check_ok(&test_OnSetFocus,"OnSetFocus"); 2250 test_ShouldDeactivate = FALSE; 2251 2252 processPendingMessages(); 2253 2254 ITfThreadMgr_GetFocus(g_tm, &dmcheck); 2255 ok(dmcheck == dm1 || broken(dmcheck == dmorig /* Win7+ */), "Expected DocumentMgr not focused\n"); 2256 ITfDocumentMgr_Release(dmcheck); 2257 2258 /* We need to explicitly set focus on Win7+ */ 2259 test_CurrentFocus = dm1; 2260 test_PrevFocus = FOCUS_IGNORE; 2261 test_OnSetFocus = SINK_OPTIONAL; /* Doesn't always fire on Win7+ */ 2262 ITfThreadMgr_SetFocus(g_tm, dm1); 2263 sink_check_ok(&test_OnSetFocus, "OnSetFocus"); 2264 2265 hr = ITfThreadMgr_AssociateFocus(g_tm,wnd2,dm2,&olddm); 2266 ok(SUCCEEDED(hr),"AssociateFocus failed\n"); 2267 processPendingMessages(); 2268 ITfThreadMgr_GetFocus(g_tm, &dmcheck); 2269 ok(dmcheck == dm1, "Expected DocumentMgr not focused\n"); 2270 ITfDocumentMgr_Release(dmcheck); 2271 2272 hr = ITfThreadMgr_AssociateFocus(g_tm,wnd3,dm2,&olddm); 2273 ok(SUCCEEDED(hr),"AssociateFocus failed\n"); 2274 processPendingMessages(); 2275 ITfThreadMgr_GetFocus(g_tm, &dmcheck); 2276 ok(dmcheck == dm1, "Expected DocumentMgr not focused\n"); 2277 ITfDocumentMgr_Release(dmcheck); 2278 2279 test_CurrentFocus = FOCUS_SAVE; 2280 test_PrevFocus = FOCUS_SAVE; 2281 test_OnSetFocus = SINK_SAVE; 2282 test_ShouldDeactivate = TRUE; /* win 8/10 */ 2283 ShowWindow(wnd2,SW_SHOWNORMAL); 2284 SetFocus(wnd2); 2285 sink_check_saved(&test_OnSetFocus,dm1,dm2,"OnSetFocus"); 2286 test_CurrentFocus = FOCUS_IGNORE; /* occasional wine race */ 2287 test_PrevFocus = FOCUS_IGNORE; /* occasional wine race */ 2288 test_OnSetFocus = SINK_IGNORE; /* occasional wine race */ 2289 test_ShouldDeactivate = FALSE; 2290 processPendingMessages(); 2291 2292 ShowWindow(wnd3,SW_SHOWNORMAL); 2293 SetFocus(wnd3); 2294 processPendingMessages(); 2295 2296 test_CurrentFocus = FOCUS_SAVE; 2297 test_PrevFocus = FOCUS_SAVE; 2298 test_OnSetFocus = SINK_SAVE; 2299 SetFocus(wnd1); 2300 processPendingMessages(); 2301 sink_check_saved(&test_OnSetFocus,dm2,dm1,"OnSetFocus"); 2302 2303 hr = ITfThreadMgr_AssociateFocus(g_tm,wnd3,NULL,&olddm); 2304 ok(SUCCEEDED(hr),"AssociateFocus failed\n"); 2305 ok(olddm == dm2, "incorrect old DocumentMgr returned\n"); 2306 ITfDocumentMgr_Release(olddm); 2307 2308 test_CurrentFocus = dmorig; 2309 test_PrevFocus = dm1; 2310 test_OnSetFocus = SINK_OPTIONAL; /* Doesn't always fire on Win7+ */ 2311 test_ACP_GetStatus = SINK_IGNORE; 2312 ITfThreadMgr_SetFocus(g_tm,dmorig); 2313 sink_check_ok(&test_OnSetFocus,"OnSetFocus"); 2314 2315 test_CurrentFocus = FOCUS_SAVE; 2316 test_PrevFocus = FOCUS_SAVE; 2317 test_OnSetFocus = SINK_SAVE; 2318 SetFocus(wnd3); 2319 processPendingMessages(); 2320 sink_check_saved(&test_OnSetFocus,dmorig,FOCUS_IGNORE,"OnSetFocus"); /* CurrentFocus NULL on XP, system default on Vista */ 2321 2322 hr = ITfThreadMgr_AssociateFocus(g_tm,wnd2,NULL,&olddm); 2323 ok(SUCCEEDED(hr),"AssociateFocus failed\n"); 2324 ok(olddm == dm2, "incorrect old DocumentMgr returned\n"); 2325 ITfDocumentMgr_Release(olddm); 2326 hr = ITfThreadMgr_AssociateFocus(g_tm,wnd1,NULL,&olddm); 2327 ok(SUCCEEDED(hr),"AssociateFocus failed\n"); 2328 ok(olddm == dm1, "incorrect old DocumentMgr returned\n"); 2329 ITfDocumentMgr_Release(olddm); 2330 2331 test_OnSetFocus = SINK_IGNORE; /* OnSetFocus fires a couple of times on Win7 */ 2332 test_CurrentFocus = FOCUS_IGNORE; 2333 test_PrevFocus = FOCUS_IGNORE; 2334 SetFocus(wnd2); 2335 processPendingMessages(); 2336 SetFocus(wnd1); 2337 processPendingMessages(); 2338 test_OnSetFocus = SINK_UNEXPECTED; 2339 2340 ITfDocumentMgr_Release(dm1); 2341 ITfDocumentMgr_Release(dm2); 2342 2343 test_CurrentFocus = dmorig; 2344 test_PrevFocus = FOCUS_IGNORE; 2345 test_OnSetFocus = SINK_OPTIONAL; 2346 test_ACP_GetStatus = SINK_IGNORE; 2347 ITfThreadMgr_SetFocus(g_tm,dmorig); 2348 sink_check_ok(&test_OnSetFocus,"OnSetFocus"); 2349 2350 test_OnSetFocus = SINK_IGNORE; /* OnSetFocus fires a couple of times on Win7 */ 2351 test_CurrentFocus = FOCUS_IGNORE; 2352 test_PrevFocus = FOCUS_IGNORE; 2353 DestroyWindow(wnd1); 2354 DestroyWindow(wnd2); 2355 test_OnPopContext = SINK_OPTIONAL; /* Vista and greater */ 2356 test_OnSetFocus = SINK_OPTIONAL; /* Vista and greater */ 2357 ITfThreadMgr_GetFocus(g_tm, &test_PrevFocus); 2358 test_CurrentFocus = NULL; 2359 test_ShouldDeactivate = TRUE; /* Win7 */ 2360 DestroyWindow(wnd3); 2361 test_ShouldDeactivate = FALSE; 2362 sink_check_ok(&test_OnSetFocus,"OnSetFocus"); 2363 sink_check_ok(&test_OnPopContext,"OnPopContext"); 2364 } 2365 2366 static void test_profile_mgr(void) 2367 { 2368 IEnumTfInputProcessorProfiles *enum_profiles; 2369 ITfInputProcessorProfileMgr *ipp_mgr; 2370 HRESULT hres; 2371 2372 hres = ITfInputProcessorProfiles_QueryInterface(g_ipp, &IID_ITfInputProcessorProfileMgr, (void**)&ipp_mgr); 2373 if (hres != S_OK) 2374 { 2375 win_skip("ITfInputProcessorProfileMgr is not supported.\n"); 2376 return; 2377 } 2378 ok(hres == S_OK, "Could not get ITfInputProcessorProfileMgr iface: %08x\n", hres); 2379 2380 hres = ITfInputProcessorProfileMgr_EnumProfiles(ipp_mgr, 0, &enum_profiles); 2381 ok(hres == S_OK, "EnumProfiles failed: %08x\n", hres); 2382 2383 IEnumTfInputProcessorProfiles_Release(enum_profiles); 2384 2385 ITfInputProcessorProfileMgr_Release(ipp_mgr); 2386 } 2387 2388 START_TEST(inputprocessor) 2389 { 2390 if (SUCCEEDED(initialize())) 2391 { 2392 test_Register(); 2393 test_RegisterCategory(); 2394 Sleep(2000); /* Win7 needs some time before the registrations become active */ 2395 processPendingMessages(); 2396 test_EnumLanguageProfiles(); 2397 test_EnumInputProcessorInfo(); 2398 test_Enable(); 2399 test_ThreadMgrAdviseSinks(); 2400 test_Activate(); 2401 test_startSession(); 2402 test_DocumentMgrAdviseSinks(); 2403 test_TfGuidAtom(); 2404 test_ClientId(); 2405 test_KeystrokeMgr(); 2406 test_TStoApplicationText(); 2407 test_Compartments(); 2408 test_AssociateFocus(); 2409 test_endSession(); 2410 test_FindClosestCategory(); 2411 test_Disable(); 2412 test_ThreadMgrUnadviseSinks(); 2413 test_DocumentMgrUnadviseSinks(); 2414 test_UnregisterCategory(); 2415 test_Unregister(); 2416 test_profile_mgr(); 2417 2418 ITextStoreACPSink_Release(ACPSink); 2419 ITfDocumentMgr_Release(g_dm); 2420 } 2421 else 2422 skip("Unable to create InputProcessor\n"); 2423 cleanup(); 2424 } 2425