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 CoInitialize(NULL); 947 hr = CoCreateInstance (&CLSID_TF_InputProcessorProfiles, NULL, 948 CLSCTX_INPROC_SERVER, &IID_ITfInputProcessorProfiles, (void**)&g_ipp); 949 if (SUCCEEDED(hr)) 950 hr = CoCreateInstance (&CLSID_TF_CategoryMgr, NULL, 951 CLSCTX_INPROC_SERVER, &IID_ITfCategoryMgr, (void**)&g_cm); 952 if (SUCCEEDED(hr)) 953 hr = CoCreateInstance (&CLSID_TF_ThreadMgr, NULL, 954 CLSCTX_INPROC_SERVER, &IID_ITfThreadMgr, (void**)&g_tm); 955 return hr; 956 } 957 958 static void cleanup(void) 959 { 960 if (g_ipp) 961 ITfInputProcessorProfiles_Release(g_ipp); 962 if (g_cm) 963 ITfCategoryMgr_Release(g_cm); 964 if (g_tm) 965 ITfThreadMgr_Release(g_tm); 966 CoUninitialize(); 967 } 968 969 static void test_Register(void) 970 { 971 HRESULT hr; 972 973 static const WCHAR szDesc[] = {'F','a','k','e',' ','W','i','n','e',' ','S','e','r','v','i','c','e',0}; 974 static const WCHAR szFile[] = {'F','a','k','e',' ','W','i','n','e',' ','S','e','r','v','i','c','e',' ','F','i','l','e',0}; 975 976 hr = ITfInputProcessorProfiles_GetCurrentLanguage(g_ipp,&gLangid); 977 ok(SUCCEEDED(hr),"Unable to get current language id\n"); 978 trace("Current Language %x\n",gLangid); 979 980 hr = RegisterTextService(&CLSID_FakeService); 981 ok(SUCCEEDED(hr),"Unable to register COM for TextService\n"); 982 hr = ITfInputProcessorProfiles_Register(g_ipp, &CLSID_FakeService); 983 ok(SUCCEEDED(hr),"Unable to register text service(%x)\n",hr); 984 hr = ITfInputProcessorProfiles_AddLanguageProfile(g_ipp, &CLSID_FakeService, gLangid, &CLSID_FakeService, szDesc, sizeof(szDesc)/sizeof(WCHAR), szFile, sizeof(szFile)/sizeof(WCHAR), 1); 985 ok(SUCCEEDED(hr),"Unable to add Language Profile (%x)\n",hr); 986 } 987 988 static void test_Unregister(void) 989 { 990 HRESULT hr; 991 hr = ITfInputProcessorProfiles_Unregister(g_ipp, &CLSID_FakeService); 992 ok(SUCCEEDED(hr),"Unable to unregister text service(%x)\n",hr); 993 UnregisterTextService(); 994 } 995 996 static void test_EnumInputProcessorInfo(void) 997 { 998 IEnumGUID *ppEnum; 999 BOOL found = FALSE; 1000 1001 if (SUCCEEDED(ITfInputProcessorProfiles_EnumInputProcessorInfo(g_ipp, &ppEnum))) 1002 { 1003 ULONG fetched; 1004 GUID g; 1005 while (IEnumGUID_Next(ppEnum, 1, &g, &fetched) == S_OK) 1006 { 1007 if(IsEqualGUID(&g,&CLSID_FakeService)) 1008 found = TRUE; 1009 } 1010 IEnumGUID_Release(ppEnum); 1011 } 1012 ok(found,"Did not find registered text service\n"); 1013 } 1014 1015 static void test_EnumLanguageProfiles(void) 1016 { 1017 BOOL found = FALSE; 1018 IEnumTfLanguageProfiles *ppEnum; 1019 HRESULT hr; 1020 1021 hr = ITfInputProcessorProfiles_EnumLanguageProfiles(g_ipp, gLangid, NULL); 1022 ok(hr == E_INVALIDARG, "EnumLanguageProfiles failed: %x\n", hr); 1023 1024 if (SUCCEEDED(ITfInputProcessorProfiles_EnumLanguageProfiles(g_ipp,gLangid,&ppEnum))) 1025 { 1026 TF_LANGUAGEPROFILE profile; 1027 while (IEnumTfLanguageProfiles_Next(ppEnum,1,&profile,NULL)==S_OK) 1028 { 1029 if (IsEqualGUID(&profile.clsid,&CLSID_FakeService)) 1030 { 1031 found = TRUE; 1032 ok(profile.langid == gLangid, "LangId Incorrect\n"); 1033 ok(IsEqualGUID(&profile.catid,&GUID_TFCAT_TIP_KEYBOARD) || 1034 broken(IsEqualGUID(&profile.catid,&GUID_NULL) /* Win8 */), "CatId Incorrect\n"); 1035 ok(IsEqualGUID(&profile.guidProfile,&CLSID_FakeService), "guidProfile Incorrect\n"); 1036 } 1037 } 1038 IEnumTfLanguageProfiles_Release(ppEnum); 1039 } 1040 ok(found,"Registered text service not found\n"); 1041 } 1042 1043 static void test_RegisterCategory(void) 1044 { 1045 HRESULT hr; 1046 hr = ITfCategoryMgr_RegisterCategory(g_cm, &CLSID_FakeService, &GUID_TFCAT_TIP_KEYBOARD, &CLSID_FakeService); 1047 ok(SUCCEEDED(hr),"ITfCategoryMgr_RegisterCategory failed\n"); 1048 hr = ITfCategoryMgr_RegisterCategory(g_cm, &CLSID_FakeService, &GUID_TFCAT_DISPLAYATTRIBUTEPROVIDER, &CLSID_FakeService); 1049 ok(SUCCEEDED(hr),"ITfCategoryMgr_RegisterCategory failed\n"); 1050 } 1051 1052 static void test_UnregisterCategory(void) 1053 { 1054 HRESULT hr; 1055 hr = ITfCategoryMgr_UnregisterCategory(g_cm, &CLSID_FakeService, &GUID_TFCAT_TIP_KEYBOARD, &CLSID_FakeService); 1056 ok(SUCCEEDED(hr),"ITfCategoryMgr_UnregisterCategory failed\n"); 1057 hr = ITfCategoryMgr_UnregisterCategory(g_cm, &CLSID_FakeService, &GUID_TFCAT_DISPLAYATTRIBUTEPROVIDER, &CLSID_FakeService); 1058 ok(SUCCEEDED(hr),"ITfCategoryMgr_UnregisterCategory failed\n"); 1059 } 1060 1061 static void test_FindClosestCategory(void) 1062 { 1063 GUID output; 1064 HRESULT hr; 1065 const GUID *list[3] = {&GUID_TFCAT_TIP_SPEECH, &GUID_TFCAT_TIP_KEYBOARD, &GUID_TFCAT_TIP_HANDWRITING}; 1066 1067 hr = ITfCategoryMgr_FindClosestCategory(g_cm, &CLSID_FakeService, &output, NULL, 0); 1068 ok(SUCCEEDED(hr),"ITfCategoryMgr_FindClosestCategory failed (%x)\n",hr); 1069 ok(IsEqualGUID(&output,&GUID_TFCAT_DISPLAYATTRIBUTEPROVIDER),"Wrong GUID\n"); 1070 1071 hr = ITfCategoryMgr_FindClosestCategory(g_cm, &CLSID_FakeService, &output, list, 1); 1072 ok(SUCCEEDED(hr),"ITfCategoryMgr_FindClosestCategory failed (%x)\n",hr); 1073 ok(IsEqualGUID(&output,&GUID_NULL),"Wrong GUID\n"); 1074 1075 hr = ITfCategoryMgr_FindClosestCategory(g_cm, &CLSID_FakeService, &output, list, 3); 1076 ok(SUCCEEDED(hr),"ITfCategoryMgr_FindClosestCategory failed (%x)\n",hr); 1077 ok(IsEqualGUID(&output,&GUID_TFCAT_TIP_KEYBOARD),"Wrong GUID\n"); 1078 } 1079 1080 static void test_Enable(void) 1081 { 1082 HRESULT hr; 1083 BOOL enabled = FALSE; 1084 1085 hr = ITfInputProcessorProfiles_EnableLanguageProfile(g_ipp,&CLSID_FakeService, gLangid, &CLSID_FakeService, TRUE); 1086 ok(SUCCEEDED(hr),"Failed to enable text service\n"); 1087 hr = ITfInputProcessorProfiles_IsEnabledLanguageProfile(g_ipp,&CLSID_FakeService, gLangid, &CLSID_FakeService, &enabled); 1088 ok(SUCCEEDED(hr),"Failed to get enabled state\n"); 1089 ok(enabled == TRUE,"enabled state incorrect\n"); 1090 } 1091 1092 static void test_Disable(void) 1093 { 1094 HRESULT hr; 1095 1096 trace("Disabling\n"); 1097 hr = ITfInputProcessorProfiles_EnableLanguageProfile(g_ipp,&CLSID_FakeService, gLangid, &CLSID_FakeService, FALSE); 1098 ok(SUCCEEDED(hr),"Failed to disable text service\n"); 1099 } 1100 1101 static void test_ThreadMgrAdviseSinks(void) 1102 { 1103 ITfSource *source = NULL; 1104 HRESULT hr; 1105 IUnknown *sink; 1106 1107 hr = ITfThreadMgr_QueryInterface(g_tm, &IID_ITfSource, (LPVOID*)&source); 1108 ok(SUCCEEDED(hr),"Failed to get IID_ITfSource for ThreadMgr\n"); 1109 if (!source) 1110 return; 1111 1112 hr = ThreadMgrEventSink_Constructor(&sink); 1113 ok(hr == S_OK, "got %08x\n", hr); 1114 if(FAILED(hr)) return; 1115 1116 tmSinkRefCount = 1; 1117 tmSinkCookie = 0; 1118 hr = ITfSource_AdviseSink(source,&IID_ITfThreadMgrEventSink, sink, &tmSinkCookie); 1119 ok(hr == S_OK, "Failed to Advise Sink\n"); 1120 ok(tmSinkCookie!=0,"Failed to get sink cookie\n"); 1121 1122 /* Advising the sink adds a ref, Releasing here lets the object be deleted 1123 when unadvised */ 1124 tmSinkRefCount = 2; 1125 IUnknown_Release(sink); 1126 1127 hr = ITfSource_AdviseSink(source, &IID_ITfKeyTraceEventSink, (IUnknown*)&TfKeyTraceEventSink, 1128 &key_trace_sink_cookie); 1129 ok(hr == S_OK, "Failed to Advise Sink\n"); 1130 1131 ITfSource_Release(source); 1132 } 1133 1134 static void test_ThreadMgrUnadviseSinks(void) 1135 { 1136 ITfSource *source = NULL; 1137 HRESULT hr; 1138 1139 hr = ITfThreadMgr_QueryInterface(g_tm, &IID_ITfSource, (LPVOID*)&source); 1140 ok(SUCCEEDED(hr),"Failed to get IID_ITfSource for ThreadMgr\n"); 1141 if (!source) 1142 return; 1143 1144 tmSinkRefCount = 1; 1145 hr = ITfSource_UnadviseSink(source, tmSinkCookie); 1146 ok(hr == S_OK, "Failed to unadvise Sink\n"); 1147 1148 hr = ITfSource_UnadviseSink(source, key_trace_sink_cookie); 1149 ok(hr == S_OK, "Failed to unadvise Sink\n"); 1150 1151 ITfSource_Release(source); 1152 } 1153 1154 static void test_DocumentMgrAdviseSinks(void) 1155 { 1156 ITfSource *source; 1157 HRESULT hr; 1158 1159 hr = ITfDocumentMgr_QueryInterface(g_dm, &IID_ITfSource, (void**)&source); 1160 ok(hr == S_OK,"Failed to get IID_ITfSource for DocumentMgr\n"); 1161 1162 dmSinkCookie = 0; 1163 hr = ITfSource_AdviseSink(source, &IID_ITfTransitoryExtensionSink, (IUnknown*)&TfTransitoryExtensionSink, &dmSinkCookie); 1164 ok(hr == S_OK,"Failed to Advise Sink\n"); 1165 1166 ITfSource_Release(source); 1167 } 1168 1169 static void test_DocumentMgrUnadviseSinks(void) 1170 { 1171 ITfSource *source = NULL; 1172 HRESULT hr; 1173 1174 hr = ITfDocumentMgr_QueryInterface(g_dm, &IID_ITfSource, (void**)&source); 1175 ok(hr == S_OK,"Failed to get IID_ITfSource for DocumentMgr\n"); 1176 1177 hr = ITfSource_UnadviseSink(source, dmSinkCookie); 1178 ok(hr == S_OK,"Failed to unadvise Sink\n"); 1179 ITfSource_Release(source); 1180 } 1181 1182 /********************************************************************** 1183 * ITfKeyEventSink 1184 **********************************************************************/ 1185 typedef struct tagKeyEventSink 1186 { 1187 ITfKeyEventSink ITfKeyEventSink_iface; 1188 LONG refCount; 1189 } KeyEventSink; 1190 1191 static inline KeyEventSink *impl_from_ITfKeyEventSink(ITfKeyEventSink *iface) 1192 { 1193 return CONTAINING_RECORD(iface, KeyEventSink, ITfKeyEventSink_iface); 1194 } 1195 1196 static void KeyEventSink_Destructor(KeyEventSink *This) 1197 { 1198 HeapFree(GetProcessHeap(),0,This); 1199 } 1200 1201 static HRESULT WINAPI KeyEventSink_QueryInterface(ITfKeyEventSink *iface, REFIID iid, LPVOID *ppvOut) 1202 { 1203 *ppvOut = NULL; 1204 1205 if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_ITfKeyEventSink)) 1206 { 1207 *ppvOut = iface; 1208 } 1209 1210 if (*ppvOut) 1211 { 1212 ITfKeyEventSink_AddRef(iface); 1213 return S_OK; 1214 } 1215 1216 return E_NOINTERFACE; 1217 } 1218 1219 static ULONG WINAPI KeyEventSink_AddRef(ITfKeyEventSink *iface) 1220 { 1221 KeyEventSink *This = impl_from_ITfKeyEventSink(iface); 1222 return InterlockedIncrement(&This->refCount); 1223 } 1224 1225 static ULONG WINAPI KeyEventSink_Release(ITfKeyEventSink *iface) 1226 { 1227 KeyEventSink *This = impl_from_ITfKeyEventSink(iface); 1228 ULONG ret; 1229 1230 ret = InterlockedDecrement(&This->refCount); 1231 if (ret == 0) 1232 KeyEventSink_Destructor(This); 1233 return ret; 1234 } 1235 1236 static HRESULT WINAPI KeyEventSink_OnSetFocus(ITfKeyEventSink *iface, 1237 BOOL fForeground) 1238 { 1239 sink_fire_ok(&test_KEV_OnSetFocus,"KeyEventSink_OnSetFocus"); 1240 return S_OK; 1241 } 1242 1243 static HRESULT WINAPI KeyEventSink_OnTestKeyDown(ITfKeyEventSink *iface, 1244 ITfContext *pic, WPARAM wParam, LPARAM lParam, BOOL *pfEaten) 1245 { 1246 trace("\n"); 1247 return S_OK; 1248 } 1249 1250 static HRESULT WINAPI KeyEventSink_OnTestKeyUp(ITfKeyEventSink *iface, 1251 ITfContext *pic, WPARAM wParam, LPARAM lParam, BOOL *pfEaten) 1252 { 1253 trace("\n"); 1254 return S_OK; 1255 } 1256 1257 static HRESULT WINAPI KeyEventSink_OnKeyDown(ITfKeyEventSink *iface, 1258 ITfContext *pic, WPARAM wParam, LPARAM lParam, BOOL *pfEaten) 1259 { 1260 trace("\n"); 1261 return S_OK; 1262 } 1263 1264 static HRESULT WINAPI KeyEventSink_OnKeyUp(ITfKeyEventSink *iface, 1265 ITfContext *pic, WPARAM wParam, LPARAM lParam, BOOL *pfEaten) 1266 { 1267 trace("\n"); 1268 return S_OK; 1269 } 1270 1271 static HRESULT WINAPI KeyEventSink_OnPreservedKey(ITfKeyEventSink *iface, 1272 ITfContext *pic, REFGUID rguid, BOOL *pfEaten) 1273 { 1274 trace("\n"); 1275 return S_OK; 1276 } 1277 1278 static const ITfKeyEventSinkVtbl KeyEventSink_KeyEventSinkVtbl = 1279 { 1280 KeyEventSink_QueryInterface, 1281 KeyEventSink_AddRef, 1282 KeyEventSink_Release, 1283 1284 KeyEventSink_OnSetFocus, 1285 KeyEventSink_OnTestKeyDown, 1286 KeyEventSink_OnTestKeyUp, 1287 KeyEventSink_OnKeyDown, 1288 KeyEventSink_OnKeyUp, 1289 KeyEventSink_OnPreservedKey 1290 }; 1291 1292 static HRESULT KeyEventSink_Constructor(ITfKeyEventSink **ppOut) 1293 { 1294 KeyEventSink *This; 1295 1296 This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(KeyEventSink)); 1297 if (This == NULL) 1298 return E_OUTOFMEMORY; 1299 1300 This->ITfKeyEventSink_iface.lpVtbl = &KeyEventSink_KeyEventSinkVtbl; 1301 This->refCount = 1; 1302 1303 *ppOut = &This->ITfKeyEventSink_iface; 1304 return S_OK; 1305 } 1306 1307 1308 static void test_KeystrokeMgr(void) 1309 { 1310 ITfKeystrokeMgr *keymgr= NULL; 1311 HRESULT hr; 1312 TF_PRESERVEDKEY tfpk; 1313 BOOL preserved; 1314 ITfKeyEventSink *sink = NULL; 1315 1316 KeyEventSink_Constructor(&sink); 1317 1318 hr = ITfThreadMgr_QueryInterface(g_tm, &IID_ITfKeystrokeMgr, (LPVOID*)&keymgr); 1319 ok(SUCCEEDED(hr),"Failed to get IID_ITfKeystrokeMgr for ThreadMgr\n"); 1320 1321 tfpk.uVKey = 'A'; 1322 tfpk.uModifiers = TF_MOD_SHIFT; 1323 1324 test_KEV_OnSetFocus = SINK_EXPECTED; 1325 hr = ITfKeystrokeMgr_AdviseKeyEventSink(keymgr,tid,sink,TRUE); 1326 ok(SUCCEEDED(hr),"ITfKeystrokeMgr_AdviseKeyEventSink failed\n"); 1327 sink_check_ok(&test_KEV_OnSetFocus,"KeyEventSink_OnSetFocus"); 1328 hr = ITfKeystrokeMgr_AdviseKeyEventSink(keymgr,tid,sink,TRUE); 1329 ok(hr == CONNECT_E_ADVISELIMIT,"Wrong return, expected CONNECT_E_ADVISELIMIT\n"); 1330 hr = ITfKeystrokeMgr_AdviseKeyEventSink(keymgr,cid,sink,TRUE); 1331 ok(hr == E_INVALIDARG,"Wrong return, expected E_INVALIDARG\n"); 1332 1333 hr =ITfKeystrokeMgr_PreserveKey(keymgr, 0, &CLSID_PreservedKey, &tfpk, NULL, 0); 1334 ok(hr==E_INVALIDARG,"ITfKeystrokeMgr_PreserveKey improperly succeeded\n"); 1335 1336 hr =ITfKeystrokeMgr_PreserveKey(keymgr, tid, &CLSID_PreservedKey, &tfpk, NULL, 0); 1337 ok(SUCCEEDED(hr),"ITfKeystrokeMgr_PreserveKey failed\n"); 1338 1339 hr =ITfKeystrokeMgr_PreserveKey(keymgr, tid, &CLSID_PreservedKey, &tfpk, NULL, 0); 1340 ok(hr == TF_E_ALREADY_EXISTS,"ITfKeystrokeMgr_PreserveKey improperly succeeded\n"); 1341 1342 preserved = FALSE; 1343 hr = ITfKeystrokeMgr_IsPreservedKey(keymgr, &CLSID_PreservedKey, &tfpk, &preserved); 1344 ok(hr == S_OK, "ITfKeystrokeMgr_IsPreservedKey failed\n"); 1345 if (hr == S_OK) ok(preserved == TRUE,"misreporting preserved key\n"); 1346 1347 hr = ITfKeystrokeMgr_UnpreserveKey(keymgr, &CLSID_PreservedKey,&tfpk); 1348 ok(SUCCEEDED(hr),"ITfKeystrokeMgr_UnpreserveKey failed\n"); 1349 1350 hr = ITfKeystrokeMgr_IsPreservedKey(keymgr, &CLSID_PreservedKey, &tfpk, &preserved); 1351 ok(hr == S_FALSE, "ITfKeystrokeMgr_IsPreservedKey failed\n"); 1352 if (hr == S_FALSE) ok(preserved == FALSE,"misreporting preserved key\n"); 1353 1354 hr = ITfKeystrokeMgr_UnpreserveKey(keymgr, &CLSID_PreservedKey,&tfpk); 1355 ok(hr==CONNECT_E_NOCONNECTION,"ITfKeystrokeMgr_UnpreserveKey improperly succeeded\n"); 1356 1357 hr = ITfKeystrokeMgr_UnadviseKeyEventSink(keymgr,tid); 1358 ok(SUCCEEDED(hr),"ITfKeystrokeMgr_UnadviseKeyEventSink failed\n"); 1359 1360 ITfKeystrokeMgr_Release(keymgr); 1361 ITfKeyEventSink_Release(sink); 1362 } 1363 1364 static void test_Activate(void) 1365 { 1366 HRESULT hr; 1367 1368 test_ShouldActivate = TRUE; /* Win7 */ 1369 hr = ITfInputProcessorProfiles_ActivateLanguageProfile(g_ipp,&CLSID_FakeService,gLangid,&CLSID_FakeService); 1370 ok(SUCCEEDED(hr),"Failed to Activate text service\n"); 1371 test_ShouldActivate = FALSE; 1372 } 1373 1374 1375 static void test_EnumContexts(ITfDocumentMgr *dm, ITfContext *search) 1376 { 1377 HRESULT hr; 1378 IEnumTfContexts* pEnum; 1379 BOOL found = FALSE; 1380 1381 hr = ITfDocumentMgr_EnumContexts(dm,&pEnum); 1382 ok(SUCCEEDED(hr),"EnumContexts failed\n"); 1383 if (SUCCEEDED(hr)) 1384 { 1385 ULONG fetched; 1386 ITfContext *cxt; 1387 while (IEnumTfContexts_Next(pEnum, 1, &cxt, &fetched) == S_OK) 1388 { 1389 if (!search) 1390 found = TRUE; 1391 else if (search == cxt) 1392 found = TRUE; 1393 ITfContext_Release(cxt); 1394 } 1395 IEnumTfContexts_Release(pEnum); 1396 } 1397 if (search) 1398 ok(found,"Did not find proper ITfContext\n"); 1399 else 1400 ok(!found,"Found an ITfContext we should should not have\n"); 1401 } 1402 1403 static void test_EnumDocumentMgr(ITfThreadMgr *tm, ITfDocumentMgr *search, ITfDocumentMgr *absent) 1404 { 1405 HRESULT hr; 1406 IEnumTfDocumentMgrs* pEnum; 1407 BOOL found = FALSE; 1408 BOOL notfound = TRUE; 1409 1410 hr = ITfThreadMgr_EnumDocumentMgrs(tm,&pEnum); 1411 ok(SUCCEEDED(hr),"EnumDocumentMgrs failed\n"); 1412 if (SUCCEEDED(hr)) 1413 { 1414 ULONG fetched; 1415 ITfDocumentMgr *dm; 1416 while (IEnumTfDocumentMgrs_Next(pEnum, 1, &dm, &fetched) == S_OK) 1417 { 1418 if (!search) 1419 found = TRUE; 1420 else if (search == dm) 1421 found = TRUE; 1422 if (absent && dm == absent) 1423 notfound = FALSE; 1424 ITfDocumentMgr_Release(dm); 1425 } 1426 IEnumTfDocumentMgrs_Release(pEnum); 1427 } 1428 if (search) 1429 ok(found,"Did not find proper ITfDocumentMgr\n"); 1430 else 1431 ok(!found,"Found an ITfDocumentMgr we should should not have\n"); 1432 if (absent) 1433 ok(notfound,"Found an ITfDocumentMgr we believe should be absent\n"); 1434 } 1435 1436 static inline int check_context_refcount(ITfContext *iface) 1437 { 1438 ITfContext_AddRef(iface); 1439 return ITfContext_Release(iface); 1440 } 1441 1442 1443 /********************************************************************** 1444 * ITfTextEditSink 1445 **********************************************************************/ 1446 typedef struct tagTextEditSink 1447 { 1448 ITfTextEditSink ITfTextEditSink_iface; 1449 LONG refCount; 1450 } TextEditSink; 1451 1452 static inline TextEditSink *impl_from_ITfTextEditSink(ITfTextEditSink *iface) 1453 { 1454 return CONTAINING_RECORD(iface, TextEditSink, ITfTextEditSink_iface); 1455 } 1456 1457 static void TextEditSink_Destructor(TextEditSink *This) 1458 { 1459 HeapFree(GetProcessHeap(),0,This); 1460 } 1461 1462 static HRESULT WINAPI TextEditSink_QueryInterface(ITfTextEditSink *iface, REFIID iid, LPVOID *ppvOut) 1463 { 1464 *ppvOut = NULL; 1465 1466 if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_ITfTextEditSink)) 1467 { 1468 *ppvOut = iface; 1469 } 1470 1471 if (*ppvOut) 1472 { 1473 ITfTextEditSink_AddRef(iface); 1474 return S_OK; 1475 } 1476 1477 return E_NOINTERFACE; 1478 } 1479 1480 static ULONG WINAPI TextEditSink_AddRef(ITfTextEditSink *iface) 1481 { 1482 TextEditSink *This = impl_from_ITfTextEditSink(iface); 1483 return InterlockedIncrement(&This->refCount); 1484 } 1485 1486 static ULONG WINAPI TextEditSink_Release(ITfTextEditSink *iface) 1487 { 1488 TextEditSink *This = impl_from_ITfTextEditSink(iface); 1489 ULONG ret; 1490 1491 ret = InterlockedDecrement(&This->refCount); 1492 if (ret == 0) 1493 TextEditSink_Destructor(This); 1494 return ret; 1495 } 1496 1497 static HRESULT WINAPI TextEditSink_OnEndEdit(ITfTextEditSink *iface, 1498 ITfContext *pic, TfEditCookie ecReadOnly, ITfEditRecord *pEditRecord) 1499 { 1500 sink_fire_ok(&test_OnEndEdit,"TextEditSink_OnEndEdit"); 1501 return S_OK; 1502 } 1503 1504 static const ITfTextEditSinkVtbl TextEditSink_TextEditSinkVtbl = 1505 { 1506 TextEditSink_QueryInterface, 1507 TextEditSink_AddRef, 1508 TextEditSink_Release, 1509 1510 TextEditSink_OnEndEdit 1511 }; 1512 1513 static HRESULT TextEditSink_Constructor(ITfTextEditSink **ppOut) 1514 { 1515 TextEditSink *This; 1516 1517 *ppOut = NULL; 1518 This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(TextEditSink)); 1519 if (This == NULL) 1520 return E_OUTOFMEMORY; 1521 1522 This->ITfTextEditSink_iface.lpVtbl = &TextEditSink_TextEditSinkVtbl; 1523 This->refCount = 1; 1524 1525 *ppOut = &This->ITfTextEditSink_iface; 1526 return S_OK; 1527 } 1528 1529 static void test_startSession(void) 1530 { 1531 HRESULT hr; 1532 DWORD cnt; 1533 DWORD editCookie; 1534 ITfDocumentMgr *dmtest; 1535 ITfContext *cxt,*cxt2,*cxt3,*cxtTest; 1536 ITextStoreACP *ts = NULL; 1537 TfClientId cid2 = 0; 1538 ITfThreadMgrEx *tmex; 1539 1540 hr = ITfThreadMgr_Deactivate(g_tm); 1541 ok(hr == E_UNEXPECTED,"Deactivate should have failed with E_UNEXPECTED\n"); 1542 1543 test_ShouldActivate = TRUE; 1544 hr = ITfThreadMgr_Activate(g_tm,&cid); 1545 ok(SUCCEEDED(hr),"Failed to Activate\n"); 1546 ok(cid != tid,"TextService id mistakenly matches Client id\n"); 1547 1548 test_ShouldActivate = FALSE; 1549 hr = ITfThreadMgr_Activate(g_tm,&cid2); 1550 ok(SUCCEEDED(hr),"Failed to Activate\n"); 1551 ok(cid == cid2, "Second activate client ID does not match\n"); 1552 1553 hr = ITfThreadMgr_QueryInterface(g_tm, &IID_ITfThreadMgrEx, (void **)&tmex); 1554 if (hr == S_OK) 1555 { 1556 hr = ITfThreadMgrEx_ActivateEx(tmex, &cid2, 0); 1557 ok(SUCCEEDED(hr), "Failed to Activate\n"); 1558 ok(cid == cid2, "ActivateEx client ID does not match\n"); 1559 1560 ITfThreadMgrEx_Release(tmex); 1561 } 1562 else 1563 win_skip("ITfThreadMgrEx is not supported\n"); 1564 1565 hr = ITfThreadMgr_Deactivate(g_tm); 1566 ok(SUCCEEDED(hr), "Failed to Deactivate\n"); 1567 hr = ITfThreadMgr_Deactivate(g_tm); 1568 ok(SUCCEEDED(hr), "Failed to Deactivate\n"); 1569 1570 test_EnumDocumentMgr(g_tm,NULL,NULL); 1571 1572 hr = ITfThreadMgr_CreateDocumentMgr(g_tm,&g_dm); 1573 ok(SUCCEEDED(hr),"CreateDocumentMgr failed\n"); 1574 1575 test_EnumDocumentMgr(g_tm,g_dm,NULL); 1576 1577 hr = ITfThreadMgr_CreateDocumentMgr(g_tm,&dmtest); 1578 ok(SUCCEEDED(hr),"CreateDocumentMgr failed\n"); 1579 1580 test_EnumDocumentMgr(g_tm,dmtest,NULL); 1581 1582 ITfDocumentMgr_Release(dmtest); 1583 test_EnumDocumentMgr(g_tm,g_dm,dmtest); 1584 1585 hr = ITfThreadMgr_GetFocus(g_tm,&dmtest); 1586 ok(SUCCEEDED(hr),"GetFocus Failed\n"); 1587 ok(dmtest == NULL,"Initial focus not null\n"); 1588 1589 test_CurrentFocus = g_dm; 1590 test_PrevFocus = NULL; 1591 test_OnSetFocus = SINK_OPTIONAL; /* Doesn't always fire on Win7 */ 1592 hr = ITfThreadMgr_SetFocus(g_tm,g_dm); 1593 ok(SUCCEEDED(hr),"SetFocus Failed\n"); 1594 sink_check_ok(&test_OnSetFocus,"OnSetFocus"); 1595 1596 hr = ITfThreadMgr_GetFocus(g_tm,&dmtest); 1597 ok(SUCCEEDED(hr),"GetFocus Failed\n"); 1598 ok(g_dm == dmtest,"Expected DocumentMgr not focused\n"); 1599 1600 ITfDocumentMgr_Release(g_dm); 1601 1602 hr = ITfThreadMgr_GetFocus(g_tm,&dmtest); 1603 ok(SUCCEEDED(hr),"GetFocus Failed\n"); 1604 ok(g_dm == dmtest,"Expected DocumentMgr not focused\n"); 1605 ITfDocumentMgr_Release(dmtest); 1606 1607 hr = TextStoreACP_Constructor((IUnknown**)&ts); 1608 ok(SUCCEEDED(hr),"Constructor Failed\n"); 1609 if (FAILED(hr)) return; 1610 1611 hr = ITfDocumentMgr_CreateContext(g_dm, cid, 0, (IUnknown*)ts, &cxt, &editCookie); 1612 ok(SUCCEEDED(hr),"CreateContext Failed\n"); 1613 1614 hr = ITfDocumentMgr_CreateContext(g_dm, cid, 0, NULL, &cxt2, &editCookie); 1615 ok(SUCCEEDED(hr),"CreateContext Failed\n"); 1616 1617 hr = ITfDocumentMgr_CreateContext(g_dm, cid, 0, NULL, &cxt3, &editCookie); 1618 ok(SUCCEEDED(hr),"CreateContext Failed\n"); 1619 1620 test_EnumContexts(g_dm, NULL); 1621 1622 hr = ITfContext_GetDocumentMgr(cxt,&dmtest); 1623 ok(hr == S_OK, "ITfContext_GetDocumentMgr failed with %x\n",hr); 1624 ok(dmtest == g_dm, "Wrong documentmgr\n"); 1625 ITfDocumentMgr_Release(dmtest); 1626 1627 cnt = check_context_refcount(cxt); 1628 test_OnPushContext = SINK_EXPECTED; 1629 test_ACP_AdviseSink = SINK_EXPECTED; 1630 test_OnInitDocumentMgr = SINK_EXPECTED; 1631 hr = ITfDocumentMgr_Push(g_dm, cxt); 1632 ok(SUCCEEDED(hr),"Push Failed\n"); 1633 ok(check_context_refcount(cxt) > cnt, "Ref count did not increase\n"); 1634 sink_check_ok(&test_OnPushContext,"OnPushContext"); 1635 sink_check_ok(&test_OnInitDocumentMgr,"OnInitDocumentMgr"); 1636 sink_check_ok(&test_ACP_AdviseSink,"TextStoreACP_AdviseSink"); 1637 1638 test_EnumContexts(g_dm, cxt); 1639 1640 hr = ITfDocumentMgr_GetTop(g_dm, &cxtTest); 1641 ok(SUCCEEDED(hr),"GetTop Failed\n"); 1642 ok(cxtTest == cxt, "Wrong context on top\n"); 1643 ok(check_context_refcount(cxt) > cnt, "Ref count did not increase\n"); 1644 cnt = ITfContext_Release(cxtTest); 1645 1646 hr = ITfDocumentMgr_GetBase(g_dm, &cxtTest); 1647 ok(SUCCEEDED(hr),"GetBase Failed\n"); 1648 ok(cxtTest == cxt, "Wrong context on Base\n"); 1649 ok(check_context_refcount(cxt) > cnt, "Ref count did not increase\n"); 1650 ITfContext_Release(cxtTest); 1651 1652 check_context_refcount(cxt2); 1653 test_OnPushContext = SINK_EXPECTED; 1654 hr = ITfDocumentMgr_Push(g_dm, cxt2); 1655 ok(SUCCEEDED(hr),"Push Failed\n"); 1656 sink_check_ok(&test_OnPushContext,"OnPushContext"); 1657 1658 cnt = check_context_refcount(cxt2); 1659 hr = ITfDocumentMgr_GetTop(g_dm, &cxtTest); 1660 ok(SUCCEEDED(hr),"GetTop Failed\n"); 1661 ok(cxtTest == cxt2, "Wrong context on top\n"); 1662 ok(check_context_refcount(cxt2) > cnt, "Ref count did not increase\n"); 1663 ITfContext_Release(cxtTest); 1664 1665 cnt = check_context_refcount(cxt); 1666 hr = ITfDocumentMgr_GetBase(g_dm, &cxtTest); 1667 ok(SUCCEEDED(hr),"GetBase Failed\n"); 1668 ok(cxtTest == cxt, "Wrong context on Base\n"); 1669 ok(check_context_refcount(cxt) > cnt, "Ref count did not increase\n"); 1670 ITfContext_Release(cxtTest); 1671 1672 cnt = check_context_refcount(cxt3); 1673 hr = ITfDocumentMgr_Push(g_dm, cxt3); 1674 ok(FAILED(hr),"Push Succeeded\n"); 1675 ok(check_context_refcount(cxt3) == cnt, "Ref changed\n"); 1676 1677 cnt = check_context_refcount(cxt2); 1678 hr = ITfDocumentMgr_GetTop(g_dm, &cxtTest); 1679 ok(SUCCEEDED(hr),"GetTop Failed\n"); 1680 ok(cxtTest == cxt2, "Wrong context on top\n"); 1681 ok(check_context_refcount(cxt2) > cnt, "Ref count did not increase\n"); 1682 ITfContext_Release(cxtTest); 1683 1684 cnt = check_context_refcount(cxt); 1685 hr = ITfDocumentMgr_GetBase(g_dm, &cxtTest); 1686 ok(SUCCEEDED(hr),"GetBase Failed\n"); 1687 ok(cxtTest == cxt, "Wrong context on Base\n"); 1688 ok(check_context_refcount(cxt) > cnt, "Ref count did not increase\n"); 1689 ITfContext_Release(cxtTest); 1690 1691 cnt = check_context_refcount(cxt2); 1692 test_OnPopContext = SINK_EXPECTED; 1693 hr = ITfDocumentMgr_Pop(g_dm, 0); 1694 ok(SUCCEEDED(hr),"Pop Failed\n"); 1695 ok(check_context_refcount(cxt2) < cnt, "Ref count did not decrease\n"); 1696 sink_check_ok(&test_OnPopContext,"OnPopContext"); 1697 1698 dmtest = (void *)0xfeedface; 1699 hr = ITfContext_GetDocumentMgr(cxt2,&dmtest); 1700 ok(hr == S_FALSE, "ITfContext_GetDocumentMgr wrong rc %x\n",hr); 1701 ok(dmtest == NULL,"returned documentmgr should be null\n"); 1702 1703 ITfContext_Release(cxt2); 1704 1705 hr = ITfDocumentMgr_GetTop(g_dm, &cxtTest); 1706 ok(SUCCEEDED(hr),"GetTop Failed\n"); 1707 ok(cxtTest == cxt, "Wrong context on top\n"); 1708 ITfContext_Release(cxtTest); 1709 1710 hr = ITfDocumentMgr_GetBase(g_dm, &cxtTest); 1711 ok(SUCCEEDED(hr),"GetBase Failed\n"); 1712 ok(cxtTest == cxt, "Wrong context on base\n"); 1713 ITfContext_Release(cxtTest); 1714 1715 hr = ITfDocumentMgr_CreateContext(g_dm, cid, 0, (IUnknown*)ts, &cxt2, &editCookie); 1716 ok(hr == S_OK,"CreateContext Failed\n"); 1717 1718 test_OnPushContext = SINK_EXPECTED; 1719 test_ACP_AdviseSink = SINK_EXPECTED; 1720 hr = ITfDocumentMgr_Push(g_dm, cxt2); 1721 ok(hr == S_OK,"Push Failed\n"); 1722 sink_check_ok(&test_OnPushContext,"OnPushContext"); 1723 sink_check_ok(&test_ACP_AdviseSink,"TextStoreACP_AdviseSink"); 1724 1725 test_ACP_UnadviseSink = SINK_EXPECTED; 1726 cnt = check_context_refcount(cxt2); 1727 test_OnPopContext = SINK_EXPECTED; 1728 hr = ITfDocumentMgr_Pop(g_dm, 0); 1729 ok(hr == S_OK,"Pop Failed\n"); 1730 ok(check_context_refcount(cxt2) < cnt, "Ref count did not decrease\n"); 1731 sink_check_ok(&test_OnPopContext,"OnPopContext"); 1732 sink_check_ok(&test_ACP_UnadviseSink,"TextStoreACP_AdviseSink"); 1733 1734 hr = ITfDocumentMgr_Pop(g_dm, 0); 1735 ok(FAILED(hr),"Pop Succeeded\n"); 1736 1737 hr = ITfDocumentMgr_GetTop(g_dm, &cxtTest); 1738 ok(SUCCEEDED(hr),"GetTop Failed\n"); 1739 ok(cxtTest == cxt, "Wrong context on top\n"); 1740 ITfContext_Release(cxtTest); 1741 1742 hr = ITfDocumentMgr_GetBase(g_dm, &cxtTest); 1743 ok(SUCCEEDED(hr),"GetBase Failed\n"); 1744 ok(cxtTest == cxt, "Wrong context on base\n"); 1745 ITfContext_Release(cxtTest); 1746 1747 ITfContext_Release(cxt); 1748 ITfContext_Release(cxt2); 1749 ITfContext_Release(cxt3); 1750 ITextStoreACP_Release(ts); 1751 } 1752 1753 static void test_endSession(void) 1754 { 1755 HRESULT hr; 1756 test_ShouldDeactivate = TRUE; 1757 test_CurrentFocus = NULL; 1758 test_PrevFocus = g_dm; 1759 test_OnSetFocus = SINK_OPTIONAL; /* Doesn't fire on Win7 */ 1760 hr = ITfThreadMgr_Deactivate(g_tm); 1761 ok(SUCCEEDED(hr),"Failed to Deactivate\n"); 1762 sink_check_ok(&test_OnSetFocus,"OnSetFocus"); 1763 test_OnSetFocus = SINK_UNEXPECTED; 1764 } 1765 1766 static void test_TfGuidAtom(void) 1767 { 1768 GUID gtest,g1; 1769 HRESULT hr; 1770 TfGuidAtom atom1,atom2; 1771 BOOL equal; 1772 1773 CoCreateGuid(>est); 1774 1775 /* msdn reports this should return E_INVALIDARG. However my test show it crashing (winxp)*/ 1776 /* 1777 hr = ITfCategoryMgr_RegisterGUID(g_cm,>est,NULL); 1778 ok(hr==E_INVALIDARG,"ITfCategoryMgr_RegisterGUID should have failed\n"); 1779 */ 1780 hr = ITfCategoryMgr_RegisterGUID(g_cm,>est,&atom1); 1781 ok(SUCCEEDED(hr),"ITfCategoryMgr_RegisterGUID failed\n"); 1782 hr = ITfCategoryMgr_RegisterGUID(g_cm,>est,&atom2); 1783 ok(SUCCEEDED(hr),"ITfCategoryMgr_RegisterGUID failed\n"); 1784 ok(atom1 == atom2,"atoms do not match\n"); 1785 hr = ITfCategoryMgr_GetGUID(g_cm,atom2,NULL); 1786 ok(hr==E_INVALIDARG,"ITfCategoryMgr_GetGUID should have failed\n"); 1787 hr = ITfCategoryMgr_GetGUID(g_cm,atom2,&g1); 1788 ok(SUCCEEDED(hr),"ITfCategoryMgr_GetGUID failed\n"); 1789 ok(IsEqualGUID(&g1,>est),"guids do not match\n"); 1790 hr = ITfCategoryMgr_IsEqualTfGuidAtom(g_cm,atom1,>est,NULL); 1791 ok(hr==E_INVALIDARG,"ITfCategoryMgr_IsEqualTfGuidAtom should have failed\n"); 1792 hr = ITfCategoryMgr_IsEqualTfGuidAtom(g_cm,atom1,>est,&equal); 1793 ok(SUCCEEDED(hr),"ITfCategoryMgr_IsEqualTfGuidAtom failed\n"); 1794 ok(equal == TRUE,"Equal value invalid\n"); 1795 1796 /* show that cid and tid TfClientIds are also TfGuidAtoms */ 1797 hr = ITfCategoryMgr_IsEqualTfGuidAtom(g_cm,tid,&CLSID_FakeService,&equal); 1798 ok(SUCCEEDED(hr),"ITfCategoryMgr_IsEqualTfGuidAtom failed\n"); 1799 ok(equal == TRUE,"Equal value invalid\n"); 1800 hr = ITfCategoryMgr_GetGUID(g_cm,cid,&g1); 1801 ok(SUCCEEDED(hr),"ITfCategoryMgr_GetGUID failed\n"); 1802 ok(!IsEqualGUID(&g1,&GUID_NULL),"guid should not be NULL\n"); 1803 } 1804 1805 static void test_ClientId(void) 1806 { 1807 ITfClientId *pcid; 1808 TfClientId id1,id2; 1809 HRESULT hr; 1810 GUID g2; 1811 1812 hr = ITfThreadMgr_QueryInterface(g_tm, &IID_ITfClientId, (LPVOID*)&pcid); 1813 ok(SUCCEEDED(hr),"Unable to acquire ITfClientId interface\n"); 1814 1815 CoCreateGuid(&g2); 1816 1817 hr = ITfClientId_GetClientId(pcid,&GUID_NULL,&id1); 1818 ok(SUCCEEDED(hr),"GetClientId failed\n"); 1819 hr = ITfClientId_GetClientId(pcid,&GUID_NULL,&id2); 1820 ok(SUCCEEDED(hr),"GetClientId failed\n"); 1821 ok(id1==id2,"Id's for GUID_NULL do not match\n"); 1822 hr = ITfClientId_GetClientId(pcid,&CLSID_FakeService,&id2); 1823 ok(SUCCEEDED(hr),"GetClientId failed\n"); 1824 ok(id2!=id1,"Id matches GUID_NULL\n"); 1825 ok(id2==tid,"Id for CLSID_FakeService not matching tid\n"); 1826 ok(id2!=cid,"Id for CLSID_FakeService matching cid\n"); 1827 hr = ITfClientId_GetClientId(pcid,&g2,&id2); 1828 ok(SUCCEEDED(hr),"GetClientId failed\n"); 1829 ok(id2!=id1,"Id matches GUID_NULL\n"); 1830 ok(id2!=tid,"Id for random guid matching tid\n"); 1831 ok(id2!=cid,"Id for random guid matching cid\n"); 1832 ITfClientId_Release(pcid); 1833 } 1834 1835 /********************************************************************** 1836 * ITfEditSession 1837 **********************************************************************/ 1838 typedef struct tagEditSession 1839 { 1840 ITfEditSession ITfEditSession_iface; 1841 LONG refCount; 1842 } EditSession; 1843 1844 static inline EditSession *impl_from_ITfEditSession(ITfEditSession *iface) 1845 { 1846 return CONTAINING_RECORD(iface, EditSession, ITfEditSession_iface); 1847 } 1848 1849 static void EditSession_Destructor(EditSession *This) 1850 { 1851 HeapFree(GetProcessHeap(),0,This); 1852 } 1853 1854 static HRESULT WINAPI EditSession_QueryInterface(ITfEditSession *iface, REFIID iid, LPVOID *ppvOut) 1855 { 1856 *ppvOut = NULL; 1857 1858 if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_ITfEditSession)) 1859 { 1860 *ppvOut = iface; 1861 } 1862 1863 if (*ppvOut) 1864 { 1865 ITfEditSession_AddRef(iface); 1866 return S_OK; 1867 } 1868 1869 return E_NOINTERFACE; 1870 } 1871 1872 static ULONG WINAPI EditSession_AddRef(ITfEditSession *iface) 1873 { 1874 EditSession *This = impl_from_ITfEditSession(iface); 1875 return InterlockedIncrement(&This->refCount); 1876 } 1877 1878 static ULONG WINAPI EditSession_Release(ITfEditSession *iface) 1879 { 1880 EditSession *This = impl_from_ITfEditSession(iface); 1881 ULONG ret; 1882 1883 ret = InterlockedDecrement(&This->refCount); 1884 if (ret == 0) 1885 EditSession_Destructor(This); 1886 return ret; 1887 } 1888 1889 static void test_InsertAtSelection(TfEditCookie ec, ITfContext *cxt) 1890 { 1891 HRESULT hr; 1892 ITfInsertAtSelection *iis; 1893 ITfRange *range=NULL; 1894 static const WCHAR txt[] = {'H','e','l','l','o',' ','W','o','r','l','d',0}; 1895 1896 hr = ITfContext_QueryInterface(cxt, &IID_ITfInsertAtSelection , (LPVOID*)&iis); 1897 ok(SUCCEEDED(hr),"Failed to get ITfInsertAtSelection interface\n"); 1898 test_ACP_InsertTextAtSelection = SINK_EXPECTED; 1899 hr = ITfInsertAtSelection_InsertTextAtSelection(iis, ec, 0, txt, 11, &range); 1900 ok(SUCCEEDED(hr),"ITfInsertAtSelection_InsertTextAtSelection failed %x\n",hr); 1901 sink_check_ok(&test_ACP_InsertTextAtSelection,"InsertTextAtSelection"); 1902 ok(range != NULL,"No range returned\n"); 1903 ITfRange_Release(range); 1904 ITfInsertAtSelection_Release(iis); 1905 } 1906 1907 static HRESULT WINAPI EditSession_DoEditSession(ITfEditSession *iface, 1908 TfEditCookie ec) 1909 { 1910 ITfContext *cxt; 1911 ITfDocumentMgr *dm; 1912 ITfRange *range; 1913 TF_SELECTION selection; 1914 ULONG fetched; 1915 HRESULT hr; 1916 1917 sink_fire_ok(&test_DoEditSession,"EditSession_DoEditSession"); 1918 sink_check_ok(&test_ACP_RequestLock,"RequestLock"); 1919 1920 ITfThreadMgr_GetFocus(g_tm, &dm); 1921 ITfDocumentMgr_GetTop(dm,&cxt); 1922 1923 hr = ITfContext_GetStart(cxt,ec,NULL); 1924 ok(hr == E_INVALIDARG,"Unexpected return code %x\n",hr); 1925 1926 range = (ITfRange*)0xdeaddead; 1927 hr = ITfContext_GetStart(cxt,0xdeadcafe,&range); 1928 ok(hr == TF_E_NOLOCK,"Unexpected return code %x\n",hr); 1929 ok(range == NULL,"Range not set to NULL\n"); 1930 1931 hr = ITfContext_GetStart(cxt,ec,&range); 1932 ok(SUCCEEDED(hr),"Unexpected return code %x\n",hr); 1933 ok(range != NULL,"Range set to NULL\n"); 1934 1935 ITfRange_Release(range); 1936 1937 hr = ITfContext_GetEnd(cxt,ec,NULL); 1938 ok(hr == E_INVALIDARG,"Unexpected return code %x\n",hr); 1939 1940 range = (ITfRange*)0xdeaddead; 1941 hr = ITfContext_GetEnd(cxt,0xdeadcafe,&range); 1942 ok(hr == TF_E_NOLOCK,"Unexpected return code %x\n",hr); 1943 ok(range == NULL,"Range not set to NULL\n"); 1944 1945 test_ACP_GetEndACP = SINK_EXPECTED; 1946 hr = ITfContext_GetEnd(cxt,ec,&range); 1947 ok(SUCCEEDED(hr),"Unexpected return code %x\n",hr); 1948 ok(range != NULL,"Range set to NULL\n"); 1949 sink_check_ok(&test_ACP_GetEndACP,"GetEndACP"); 1950 1951 ITfRange_Release(range); 1952 1953 selection.range = NULL; 1954 test_ACP_GetSelection = SINK_EXPECTED; 1955 hr = ITfContext_GetSelection(cxt, ec, TF_DEFAULT_SELECTION, 1, &selection, &fetched); 1956 ok(SUCCEEDED(hr),"ITfContext_GetSelection failed\n"); 1957 ok(fetched == 1,"fetched incorrect\n"); 1958 ok(selection.range != NULL,"NULL range\n"); 1959 sink_check_ok(&test_ACP_GetSelection,"GetSelection"); 1960 ITfRange_Release(selection.range); 1961 1962 test_InsertAtSelection(ec, cxt); 1963 1964 test_ACP_GetEndACP = SINK_EXPECTED; 1965 hr = ITfContext_GetEnd(cxt,ec,&range); 1966 ok(SUCCEEDED(hr),"Unexpected return code %x\n",hr); 1967 ok(range != NULL,"Range set to NULL\n"); 1968 sink_check_ok(&test_ACP_GetEndACP,"GetEndACP"); 1969 1970 selection.range = range; 1971 selection.style.ase = TF_AE_NONE; 1972 selection.style.fInterimChar = FALSE; 1973 test_ACP_SetSelection = SINK_EXPECTED; 1974 hr = ITfContext_SetSelection(cxt, ec, 1, &selection); 1975 ok(SUCCEEDED(hr),"ITfContext_SetSelection failed\n"); 1976 sink_check_ok(&test_ACP_SetSelection,"SetSelection"); 1977 ITfRange_Release(range); 1978 1979 ITfContext_Release(cxt); 1980 ITfDocumentMgr_Release(dm); 1981 return 0xdeadcafe; 1982 } 1983 1984 static const ITfEditSessionVtbl EditSession_EditSessionVtbl = 1985 { 1986 EditSession_QueryInterface, 1987 EditSession_AddRef, 1988 EditSession_Release, 1989 1990 EditSession_DoEditSession 1991 }; 1992 1993 static HRESULT EditSession_Constructor(ITfEditSession **ppOut) 1994 { 1995 EditSession *This; 1996 1997 *ppOut = NULL; 1998 This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(EditSession)); 1999 if (This == NULL) 2000 return E_OUTOFMEMORY; 2001 2002 This->ITfEditSession_iface.lpVtbl = &EditSession_EditSessionVtbl; 2003 This->refCount = 1; 2004 2005 *ppOut = &This->ITfEditSession_iface; 2006 return S_OK; 2007 } 2008 2009 static void test_TStoApplicationText(void) 2010 { 2011 HRESULT hr, hrSession; 2012 ITfEditSession *es; 2013 ITfContext *cxt; 2014 ITfDocumentMgr *dm; 2015 ITfTextEditSink *sink; 2016 ITfSource *source = NULL; 2017 DWORD editSinkCookie = -1; 2018 2019 ITfThreadMgr_GetFocus(g_tm, &dm); 2020 EditSession_Constructor(&es); 2021 ITfDocumentMgr_GetTop(dm,&cxt); 2022 2023 TextEditSink_Constructor(&sink); 2024 hr = ITfContext_QueryInterface(cxt,&IID_ITfSource,(LPVOID*)&source); 2025 ok(SUCCEEDED(hr),"Failed to get IID_ITfSource for Context\n"); 2026 if (source) 2027 { 2028 hr = ITfSource_AdviseSink(source, &IID_ITfTextEditSink, (LPVOID)sink, &editSinkCookie); 2029 ok(SUCCEEDED(hr),"Failed to advise Sink\n"); 2030 ok(editSinkCookie != -1,"Failed to get sink cookie\n"); 2031 } 2032 2033 hrSession = 0xfeedface; 2034 /* Test no permissions flags */ 2035 hr = ITfContext_RequestEditSession(cxt, tid, es, TF_ES_SYNC, &hrSession); 2036 ok(hr == E_INVALIDARG,"RequestEditSession should have failed with %x not %x\n",E_INVALIDARG,hr); 2037 ok(hrSession == E_FAIL,"hrSession should be %x not %x\n",E_FAIL,hrSession); 2038 2039 documentStatus = TS_SD_READONLY; 2040 hrSession = 0xfeedface; 2041 test_ACP_GetStatus = SINK_EXPECTED; 2042 hr = ITfContext_RequestEditSession(cxt, tid, es, TF_ES_SYNC|TF_ES_READWRITE, &hrSession); 2043 ok(SUCCEEDED(hr),"ITfContext_RequestEditSession failed\n"); 2044 ok(hrSession == TS_E_READONLY,"Unexpected hrSession (%x)\n",hrSession); 2045 sink_check_ok(&test_ACP_GetStatus,"GetStatus"); 2046 2047 /* signal a change to allow readwrite sessions */ 2048 documentStatus = 0; 2049 test_ACP_RequestLock = SINK_EXPECTED; 2050 ITextStoreACPSink_OnStatusChange(ACPSink,documentStatus); 2051 sink_check_ok(&test_ACP_RequestLock,"RequestLock"); 2052 2053 test_ACP_GetStatus = SINK_EXPECTED; 2054 test_ACP_RequestLock = SINK_EXPECTED; 2055 test_DoEditSession = SINK_EXPECTED; 2056 hrSession = 0xfeedface; 2057 test_OnEndEdit = SINK_EXPECTED; 2058 hr = ITfContext_RequestEditSession(cxt, tid, es, TF_ES_SYNC|TF_ES_READWRITE, &hrSession); 2059 ok(SUCCEEDED(hr),"ITfContext_RequestEditSession failed\n"); 2060 sink_check_ok(&test_OnEndEdit,"OnEndEdit"); 2061 sink_check_ok(&test_DoEditSession,"DoEditSession"); 2062 sink_check_ok(&test_ACP_GetStatus,"GetStatus"); 2063 ok(hrSession == 0xdeadcafe,"Unexpected hrSession (%x)\n",hrSession); 2064 2065 if (source) 2066 { 2067 hr = ITfSource_UnadviseSink(source, editSinkCookie); 2068 ok(SUCCEEDED(hr),"Failed to unadvise Sink\n"); 2069 ITfSource_Release(source); 2070 } 2071 ITfTextEditSink_Release(sink); 2072 ITfContext_Release(cxt); 2073 ITfDocumentMgr_Release(dm); 2074 ITfEditSession_Release(es); 2075 } 2076 2077 static void enum_compartments(ITfCompartmentMgr *cmpmgr, REFGUID present, REFGUID absent) 2078 { 2079 BOOL found,found2; 2080 IEnumGUID *ppEnum; 2081 found = FALSE; 2082 found2 = FALSE; 2083 if (SUCCEEDED(ITfCompartmentMgr_EnumCompartments(cmpmgr, &ppEnum))) 2084 { 2085 ULONG fetched; 2086 GUID g; 2087 while (IEnumGUID_Next(ppEnum, 1, &g, &fetched) == S_OK) 2088 { 2089 WCHAR str[50]; 2090 CHAR strA[50]; 2091 StringFromGUID2(&g,str,sizeof(str)/sizeof(str[0])); 2092 WideCharToMultiByte(CP_ACP,0,str,-1,strA,sizeof(strA),0,0); 2093 trace("found %s\n",strA); 2094 if (present && IsEqualGUID(present,&g)) 2095 found = TRUE; 2096 if (absent && IsEqualGUID(absent, &g)) 2097 found2 = TRUE; 2098 } 2099 IEnumGUID_Release(ppEnum); 2100 } 2101 if (present) 2102 ok(found,"Did not find compartment\n"); 2103 if (absent) 2104 ok(!found2,"Found compartment that should be absent\n"); 2105 } 2106 2107 static void test_Compartments(void) 2108 { 2109 ITfContext *cxt; 2110 ITfDocumentMgr *dm; 2111 ITfCompartmentMgr *cmpmgr; 2112 ITfCompartment *cmp; 2113 HRESULT hr; 2114 2115 ITfThreadMgr_GetFocus(g_tm, &dm); 2116 ITfDocumentMgr_GetTop(dm,&cxt); 2117 2118 /* Global */ 2119 hr = ITfThreadMgr_GetGlobalCompartment(g_tm, &cmpmgr); 2120 ok(SUCCEEDED(hr),"GetGlobalCompartment failed\n"); 2121 hr = ITfCompartmentMgr_GetCompartment(cmpmgr, &GUID_COMPARTMENT_SPEECH_OPENCLOSE, &cmp); 2122 ok(SUCCEEDED(hr),"GetCompartment failed\n"); 2123 ITfCompartment_Release(cmp); 2124 enum_compartments(cmpmgr,&GUID_COMPARTMENT_SPEECH_OPENCLOSE,NULL); 2125 ITfCompartmentMgr_Release(cmpmgr); 2126 2127 /* Thread */ 2128 hr = ITfThreadMgr_QueryInterface(g_tm, &IID_ITfCompartmentMgr, (LPVOID*)&cmpmgr); 2129 ok(SUCCEEDED(hr),"ThreadMgr QI for IID_ITfCompartmentMgr failed\n"); 2130 hr = ITfCompartmentMgr_GetCompartment(cmpmgr, &CLSID_FakeService, &cmp); 2131 ok(SUCCEEDED(hr),"GetCompartment failed\n"); 2132 enum_compartments(cmpmgr,&CLSID_FakeService,&GUID_COMPARTMENT_SPEECH_OPENCLOSE); 2133 ITfCompartmentMgr_ClearCompartment(cmpmgr,tid,&CLSID_FakeService); 2134 enum_compartments(cmpmgr,NULL,&CLSID_FakeService); 2135 ITfCompartmentMgr_Release(cmpmgr); 2136 ITfCompartment_Release(cmp); 2137 2138 /* DocumentMgr */ 2139 hr = ITfDocumentMgr_QueryInterface(dm, &IID_ITfCompartmentMgr, (LPVOID*)&cmpmgr); 2140 ok(SUCCEEDED(hr),"DocumentMgr QI for IID_ITfCompartmentMgr failed\n"); 2141 2142 hr = ITfCompartmentMgr_GetCompartment(cmpmgr, &GUID_COMPARTMENT_PERSISTMENUENABLED, &cmp); 2143 ok(SUCCEEDED(hr),"GetCompartment failed\n"); 2144 enum_compartments(cmpmgr,&GUID_COMPARTMENT_PERSISTMENUENABLED,&GUID_COMPARTMENT_SPEECH_OPENCLOSE); 2145 ITfCompartmentMgr_Release(cmpmgr); 2146 2147 /* Context */ 2148 hr = ITfContext_QueryInterface(cxt, &IID_ITfCompartmentMgr, (LPVOID*)&cmpmgr); 2149 ok(SUCCEEDED(hr),"Context QI for IID_ITfCompartmentMgr failed\n"); 2150 enum_compartments(cmpmgr,NULL,&GUID_COMPARTMENT_PERSISTMENUENABLED); 2151 ITfCompartmentMgr_Release(cmpmgr); 2152 2153 ITfContext_Release(cxt); 2154 ITfDocumentMgr_Release(dm); 2155 } 2156 2157 static void processPendingMessages(void) 2158 { 2159 MSG msg; 2160 int diff = 200; 2161 int min_timeout = 100; 2162 DWORD time = GetTickCount() + diff; 2163 2164 while (diff > 0) 2165 { 2166 if (MsgWaitForMultipleObjects(0, NULL, FALSE, min_timeout, QS_ALLINPUT) == WAIT_TIMEOUT) 2167 break; 2168 while (PeekMessageW(&msg, 0, 0, 0, PM_REMOVE)) 2169 { 2170 TranslateMessage(&msg); 2171 DispatchMessageW(&msg); 2172 } 2173 diff = time - GetTickCount(); 2174 } 2175 } 2176 2177 static void test_AssociateFocus(void) 2178 { 2179 ITfDocumentMgr *dm1, *dm2, *olddm, *dmcheck, *dmorig; 2180 HWND wnd1, wnd2, wnd3; 2181 HRESULT hr; 2182 2183 ITfThreadMgr_GetFocus(g_tm, &dmorig); 2184 test_CurrentFocus = NULL; 2185 test_PrevFocus = dmorig; 2186 test_OnSetFocus = SINK_OPTIONAL; /* Doesn't always fire on Win7 */ 2187 test_ACP_GetStatus = SINK_OPTIONAL; 2188 hr = ITfThreadMgr_SetFocus(g_tm,NULL); 2189 ok(SUCCEEDED(hr),"ITfThreadMgr_SetFocus failed\n"); 2190 sink_check_ok(&test_OnSetFocus,"OnSetFocus"); 2191 test_ACP_GetStatus = SINK_UNEXPECTED; 2192 ITfDocumentMgr_Release(dmorig); 2193 2194 hr = ITfThreadMgr_CreateDocumentMgr(g_tm,&dm1); 2195 ok(SUCCEEDED(hr),"CreateDocumentMgr failed\n"); 2196 2197 hr = ITfThreadMgr_CreateDocumentMgr(g_tm,&dm2); 2198 ok(SUCCEEDED(hr),"CreateDocumentMgr failed\n"); 2199 2200 wnd1 = CreateWindowA("edit",NULL,WS_POPUP,0,0,200,60,NULL,NULL,NULL,NULL); 2201 ok(wnd1!=NULL,"Unable to create window 1\n"); 2202 wnd2 = CreateWindowA("edit",NULL,WS_POPUP,0,65,200,60,NULL,NULL,NULL,NULL); 2203 ok(wnd2!=NULL,"Unable to create window 2\n"); 2204 wnd3 = CreateWindowA("edit",NULL,WS_POPUP,0,130,200,60,NULL,NULL,NULL,NULL); 2205 ok(wnd3!=NULL,"Unable to create window 3\n"); 2206 2207 processPendingMessages(); 2208 2209 test_OnInitDocumentMgr = SINK_OPTIONAL; /* Vista and greater */ 2210 test_OnPushContext = SINK_OPTIONAL; /* Vista and greater */ 2211 test_OnSetFocus = SINK_OPTIONAL; /* Win7 */ 2212 test_PrevFocus = NULL; 2213 test_CurrentFocus = FOCUS_IGNORE; 2214 2215 ShowWindow(wnd1,SW_SHOWNORMAL); 2216 test_OnSetFocus = SINK_UNEXPECTED; 2217 SetFocus(wnd1); 2218 sink_check_ok(&test_OnInitDocumentMgr,"OnInitDocumentMgr"); 2219 sink_check_ok(&test_OnPushContext,"OnPushContext"); 2220 2221 test_OnSetFocus = SINK_OPTIONAL; /* Vista and greater */ 2222 test_ACP_RequestLock = SINK_OPTIONAL; /* Win7 x64 */ 2223 test_ACP_GetSelection = SINK_OPTIONAL; /* Win7 x64 */ 2224 ITfThreadMgr_GetFocus(g_tm, &test_PrevFocus); 2225 test_CurrentFocus = FOCUS_IGNORE; /* This is a default system context */ 2226 processPendingMessages(); 2227 sink_check_ok(&test_OnSetFocus,"OnSetFocus"); 2228 test_ACP_RequestLock = SINK_UNEXPECTED; 2229 test_ACP_GetSelection = SINK_UNEXPECTED; 2230 2231 test_CurrentFocus = dm1; 2232 test_PrevFocus = FOCUS_IGNORE; 2233 test_OnSetFocus = SINK_OPTIONAL; 2234 test_ShouldDeactivate = TRUE; 2235 hr = ITfThreadMgr_AssociateFocus(g_tm,wnd1,dm1,&olddm); 2236 ok(SUCCEEDED(hr),"AssociateFocus failed\n"); 2237 sink_check_ok(&test_OnSetFocus,"OnSetFocus"); 2238 test_ShouldDeactivate = FALSE; 2239 2240 processPendingMessages(); 2241 2242 ITfThreadMgr_GetFocus(g_tm, &dmcheck); 2243 ok(dmcheck == dm1 || broken(dmcheck == dmorig /* Win7+ */), "Expected DocumentMgr not focused\n"); 2244 ITfDocumentMgr_Release(dmcheck); 2245 2246 /* We need to explicitly set focus on Win7+ */ 2247 test_CurrentFocus = dm1; 2248 test_PrevFocus = FOCUS_IGNORE; 2249 test_OnSetFocus = SINK_OPTIONAL; /* Doesn't always fire on Win7+ */ 2250 ITfThreadMgr_SetFocus(g_tm, dm1); 2251 sink_check_ok(&test_OnSetFocus, "OnSetFocus"); 2252 2253 hr = ITfThreadMgr_AssociateFocus(g_tm,wnd2,dm2,&olddm); 2254 ok(SUCCEEDED(hr),"AssociateFocus failed\n"); 2255 processPendingMessages(); 2256 ITfThreadMgr_GetFocus(g_tm, &dmcheck); 2257 ok(dmcheck == dm1, "Expected DocumentMgr not focused\n"); 2258 ITfDocumentMgr_Release(dmcheck); 2259 2260 hr = ITfThreadMgr_AssociateFocus(g_tm,wnd3,dm2,&olddm); 2261 ok(SUCCEEDED(hr),"AssociateFocus failed\n"); 2262 processPendingMessages(); 2263 ITfThreadMgr_GetFocus(g_tm, &dmcheck); 2264 ok(dmcheck == dm1, "Expected DocumentMgr not focused\n"); 2265 ITfDocumentMgr_Release(dmcheck); 2266 2267 test_CurrentFocus = FOCUS_SAVE; 2268 test_PrevFocus = FOCUS_SAVE; 2269 test_OnSetFocus = SINK_SAVE; 2270 test_ShouldDeactivate = TRUE; /* win 8/10 */ 2271 ShowWindow(wnd2,SW_SHOWNORMAL); 2272 SetFocus(wnd2); 2273 sink_check_saved(&test_OnSetFocus,dm1,dm2,"OnSetFocus"); 2274 test_CurrentFocus = FOCUS_IGNORE; /* occasional wine race */ 2275 test_PrevFocus = FOCUS_IGNORE; /* occasional wine race */ 2276 test_OnSetFocus = SINK_IGNORE; /* occasional wine race */ 2277 test_ShouldDeactivate = FALSE; 2278 processPendingMessages(); 2279 2280 ShowWindow(wnd3,SW_SHOWNORMAL); 2281 SetFocus(wnd3); 2282 processPendingMessages(); 2283 2284 test_CurrentFocus = FOCUS_SAVE; 2285 test_PrevFocus = FOCUS_SAVE; 2286 test_OnSetFocus = SINK_SAVE; 2287 SetFocus(wnd1); 2288 processPendingMessages(); 2289 sink_check_saved(&test_OnSetFocus,dm2,dm1,"OnSetFocus"); 2290 2291 hr = ITfThreadMgr_AssociateFocus(g_tm,wnd3,NULL,&olddm); 2292 ok(SUCCEEDED(hr),"AssociateFocus failed\n"); 2293 ok(olddm == dm2, "incorrect old DocumentMgr returned\n"); 2294 ITfDocumentMgr_Release(olddm); 2295 2296 test_CurrentFocus = dmorig; 2297 test_PrevFocus = dm1; 2298 test_OnSetFocus = SINK_OPTIONAL; /* Doesn't always fire on Win7+ */ 2299 test_ACP_GetStatus = SINK_IGNORE; 2300 ITfThreadMgr_SetFocus(g_tm,dmorig); 2301 sink_check_ok(&test_OnSetFocus,"OnSetFocus"); 2302 2303 test_CurrentFocus = FOCUS_SAVE; 2304 test_PrevFocus = FOCUS_SAVE; 2305 test_OnSetFocus = SINK_SAVE; 2306 SetFocus(wnd3); 2307 processPendingMessages(); 2308 sink_check_saved(&test_OnSetFocus,dmorig,FOCUS_IGNORE,"OnSetFocus"); /* CurrentFocus NULL on XP, system default on Vista */ 2309 2310 hr = ITfThreadMgr_AssociateFocus(g_tm,wnd2,NULL,&olddm); 2311 ok(SUCCEEDED(hr),"AssociateFocus failed\n"); 2312 ok(olddm == dm2, "incorrect old DocumentMgr returned\n"); 2313 ITfDocumentMgr_Release(olddm); 2314 hr = ITfThreadMgr_AssociateFocus(g_tm,wnd1,NULL,&olddm); 2315 ok(SUCCEEDED(hr),"AssociateFocus failed\n"); 2316 ok(olddm == dm1, "incorrect old DocumentMgr returned\n"); 2317 ITfDocumentMgr_Release(olddm); 2318 2319 test_OnSetFocus = SINK_IGNORE; /* OnSetFocus fires a couple of times on Win7 */ 2320 test_CurrentFocus = FOCUS_IGNORE; 2321 test_PrevFocus = FOCUS_IGNORE; 2322 SetFocus(wnd2); 2323 processPendingMessages(); 2324 SetFocus(wnd1); 2325 processPendingMessages(); 2326 test_OnSetFocus = SINK_UNEXPECTED; 2327 2328 ITfDocumentMgr_Release(dm1); 2329 ITfDocumentMgr_Release(dm2); 2330 2331 test_CurrentFocus = dmorig; 2332 test_PrevFocus = FOCUS_IGNORE; 2333 test_OnSetFocus = SINK_OPTIONAL; 2334 test_ACP_GetStatus = SINK_IGNORE; 2335 ITfThreadMgr_SetFocus(g_tm,dmorig); 2336 sink_check_ok(&test_OnSetFocus,"OnSetFocus"); 2337 2338 test_OnSetFocus = SINK_IGNORE; /* OnSetFocus fires a couple of times on Win7 */ 2339 test_CurrentFocus = FOCUS_IGNORE; 2340 test_PrevFocus = FOCUS_IGNORE; 2341 DestroyWindow(wnd1); 2342 DestroyWindow(wnd2); 2343 test_OnPopContext = SINK_OPTIONAL; /* Vista and greater */ 2344 test_OnSetFocus = SINK_OPTIONAL; /* Vista and greater */ 2345 ITfThreadMgr_GetFocus(g_tm, &test_PrevFocus); 2346 test_CurrentFocus = NULL; 2347 test_ShouldDeactivate = TRUE; /* Win7 */ 2348 DestroyWindow(wnd3); 2349 test_ShouldDeactivate = FALSE; 2350 sink_check_ok(&test_OnSetFocus,"OnSetFocus"); 2351 sink_check_ok(&test_OnPopContext,"OnPopContext"); 2352 } 2353 2354 static void test_profile_mgr(void) 2355 { 2356 IEnumTfInputProcessorProfiles *enum_profiles; 2357 ITfInputProcessorProfileMgr *ipp_mgr; 2358 HRESULT hres; 2359 2360 hres = ITfInputProcessorProfiles_QueryInterface(g_ipp, &IID_ITfInputProcessorProfileMgr, (void**)&ipp_mgr); 2361 if (hres != S_OK) 2362 { 2363 win_skip("ITfInputProcessorProfileMgr is not supported.\n"); 2364 return; 2365 } 2366 ok(hres == S_OK, "Could not get ITfInputProcessorProfileMgr iface: %08x\n", hres); 2367 2368 hres = ITfInputProcessorProfileMgr_EnumProfiles(ipp_mgr, 0, &enum_profiles); 2369 ok(hres == S_OK, "EnumProfiles failed: %08x\n", hres); 2370 2371 IEnumTfInputProcessorProfiles_Release(enum_profiles); 2372 2373 ITfInputProcessorProfileMgr_Release(ipp_mgr); 2374 } 2375 2376 START_TEST(inputprocessor) 2377 { 2378 if (SUCCEEDED(initialize())) 2379 { 2380 test_Register(); 2381 test_RegisterCategory(); 2382 Sleep(2000); /* Win7 needs some time before the registrations become active */ 2383 processPendingMessages(); 2384 test_EnumLanguageProfiles(); 2385 test_EnumInputProcessorInfo(); 2386 test_Enable(); 2387 test_ThreadMgrAdviseSinks(); 2388 test_Activate(); 2389 test_startSession(); 2390 test_DocumentMgrAdviseSinks(); 2391 test_TfGuidAtom(); 2392 test_ClientId(); 2393 test_KeystrokeMgr(); 2394 test_TStoApplicationText(); 2395 test_Compartments(); 2396 test_AssociateFocus(); 2397 test_endSession(); 2398 test_FindClosestCategory(); 2399 test_Disable(); 2400 test_ThreadMgrUnadviseSinks(); 2401 test_DocumentMgrUnadviseSinks(); 2402 test_UnregisterCategory(); 2403 test_Unregister(); 2404 test_profile_mgr(); 2405 2406 ITextStoreACPSink_Release(ACPSink); 2407 ITfDocumentMgr_Release(g_dm); 2408 } 2409 else 2410 skip("Unable to create InputProcessor\n"); 2411 cleanup(); 2412 } 2413