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