2 * Unit test suite for windowless rich edit controls
4 * Copyright 2008 Maarten Lankhorst
5 * Copyright 2008 Austin Lund
6 * Copyright 2008 Dylan Smith
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
34 #include <wine/test.h>
38 static HMODULE hmoduleRichEdit
;
39 static IID
*pIID_ITextServices
;
40 static IID
*pIID_ITextHost
;
41 static IID
*pIID_ITextHost2
;
42 static PCreateTextServices pCreateTextServices
;
44 static const char *debugstr_guid(REFIID riid
)
51 sprintf(buf
, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
52 riid
->Data1
, riid
->Data2
, riid
->Data3
, riid
->Data4
[0],
53 riid
->Data4
[1], riid
->Data4
[2], riid
->Data4
[3], riid
->Data4
[4],
54 riid
->Data4
[5], riid
->Data4
[6], riid
->Data4
[7]);
59 /* Define C Macros for ITextServices calls. */
61 /* Use a special table for x86 machines to convert the thiscall
62 * calling convention. This isn't needed on other platforms. */
64 static ITextServicesVtbl itextServicesStdcallVtbl
;
65 #define TXTSERV_VTABLE(This) (&itextServicesStdcallVtbl)
67 #define TXTSERV_VTABLE(This) (This)->lpVtbl
70 #define ITextServices_TxSendMessage(This,a,b,c,d) TXTSERV_VTABLE(This)->TxSendMessage(This,a,b,c,d)
71 #define ITextServices_TxDraw(This,a,b,c,d,e,f,g,h,i,j,k,l) TXTSERV_VTABLE(This)->TxDraw(This,a,b,c,d,e,f,g,h,i,j,k,l)
72 #define ITextServices_TxGetHScroll(This,a,b,c,d,e) TXTSERV_VTABLE(This)->TxGetHScroll(This,a,b,c,d,e)
73 #define ITextServices_TxGetVScroll(This,a,b,c,d,e) TXTSERV_VTABLE(This)->TxGetVScroll(This,a,b,c,d,e)
74 #define ITextServices_OnTxSetCursor(This,a,b,c,d,e,f,g,h,i) TXTSERV_VTABLE(This)->OnTxSetCursor(This,a,b,c,d,e,f,g,h,i)
75 #define ITextServices_TxQueryHitPoint(This,a,b,c,d,e,f,g,h,i,j) TXTSERV_VTABLE(This)->TxQueryHitPoint(This,a,b,c,d,e,f,g,h,i,j)
76 #define ITextServices_OnTxInplaceActivate(This,a) TXTSERV_VTABLE(This)->OnTxInplaceActivate(This,a)
77 #define ITextServices_OnTxInplaceDeactivate(This) TXTSERV_VTABLE(This)->OnTxInplaceDeactivate(This)
78 #define ITextServices_OnTxUIActivate(This) TXTSERV_VTABLE(This)->OnTxUIActivate(This)
79 #define ITextServices_OnTxUIDeactivate(This) TXTSERV_VTABLE(This)->OnTxUIDeactivate(This)
80 #define ITextServices_TxGetText(This,a) TXTSERV_VTABLE(This)->TxGetText(This,a)
81 #define ITextServices_TxSetText(This,a) TXTSERV_VTABLE(This)->TxSetText(This,a)
82 #define ITextServices_TxGetCurrentTargetX(This,a) TXTSERV_VTABLE(This)->TxGetCurrentTargetX(This,a)
83 #define ITextServices_TxGetBaseLinePos(This,a) TXTSERV_VTABLE(This)->TxGetBaseLinePos(This,a)
84 #define ITextServices_TxGetNaturalSize(This,a,b,c,d,e,f,g,h) TXTSERV_VTABLE(This)->TxGetNaturalSize(This,a,b,c,d,e,f,g,h)
85 #define ITextServices_TxGetDropTarget(This,a) TXTSERV_VTABLE(This)->TxGetDropTarget(This,a)
86 #define ITextServices_OnTxPropertyBitsChange(This,a,b) TXTSERV_VTABLE(This)->OnTxPropertyBitsChange(This,a,b)
87 #define ITextServices_TxGetCachedSize(This,a,b) TXTSERV_VTABLE(This)->TxGetCachedSize(This,a,b)
89 /* Set the WINETEST_DEBUG environment variable to be greater than 1 for verbose
90 * function call traces of ITextHost. */
91 #define TRACECALL if(winetest_debug > 1) trace
93 /************************************************************************/
94 /* ITextHost implementation for conformance testing. */
96 typedef struct ITextHostTestImpl
98 ITextHost ITextHost_iface
;
102 static inline ITextHostTestImpl
*impl_from_ITextHost(ITextHost
*iface
)
104 return CONTAINING_RECORD(iface
, ITextHostTestImpl
, ITextHost_iface
);
107 static HRESULT WINAPI
ITextHostImpl_QueryInterface(ITextHost
*iface
,
111 ITextHostTestImpl
*This
= impl_from_ITextHost(iface
);
113 if (IsEqualIID(riid
, &IID_IUnknown
) || IsEqualIID(riid
, pIID_ITextHost
)) {
115 ITextHost_AddRef((ITextHost
*)*ppvObject
);
119 return E_NOINTERFACE
;
122 static ULONG WINAPI
ITextHostImpl_AddRef(ITextHost
*iface
)
124 ITextHostTestImpl
*This
= impl_from_ITextHost(iface
);
125 ULONG refCount
= InterlockedIncrement(&This
->refCount
);
129 static ULONG WINAPI
ITextHostImpl_Release(ITextHost
*iface
)
131 ITextHostTestImpl
*This
= impl_from_ITextHost(iface
);
132 ULONG refCount
= InterlockedDecrement(&This
->refCount
);
143 static HDC WINAPI
ITextHostImpl_TxGetDC(ITextHost
*iface
)
145 ITextHostTestImpl
*This
= impl_from_ITextHost(iface
);
146 TRACECALL("Call to TxGetDC(%p)\n", This
);
150 static INT WINAPI
ITextHostImpl_TxReleaseDC(ITextHost
*iface
,
153 ITextHostTestImpl
*This
= impl_from_ITextHost(iface
);
154 TRACECALL("Call to TxReleaseDC(%p)\n", This
);
158 static BOOL WINAPI
ITextHostImpl_TxShowScrollBar(ITextHost
*iface
,
162 ITextHostTestImpl
*This
= impl_from_ITextHost(iface
);
163 TRACECALL("Call to TxShowScrollBar(%p, fnBar=%d, fShow=%d)\n",
168 static BOOL WINAPI
ITextHostImpl_TxEnableScrollBar(ITextHost
*iface
,
172 ITextHostTestImpl
*This
= impl_from_ITextHost(iface
);
173 TRACECALL("Call to TxEnableScrollBar(%p, fuSBFlags=%d, fuArrowflags=%d)\n",
174 This
, fuSBFlags
, fuArrowflags
);
178 static BOOL WINAPI
ITextHostImpl_TxSetScrollRange(ITextHost
*iface
,
184 ITextHostTestImpl
*This
= impl_from_ITextHost(iface
);
185 TRACECALL("Call to TxSetScrollRange(%p, fnBar=%d, nMinPos=%d, nMaxPos=%d, fRedraw=%d)\n",
186 This
, fnBar
, nMinPos
, nMaxPos
, fRedraw
);
190 static BOOL WINAPI
ITextHostImpl_TxSetScrollPos(ITextHost
*iface
,
195 ITextHostTestImpl
*This
= impl_from_ITextHost(iface
);
196 TRACECALL("Call to TxSetScrollPos(%p, fnBar=%d, nPos=%d, fRedraw=%d)\n",
197 This
, fnBar
, nPos
, fRedraw
);
201 static void WINAPI
ITextHostImpl_TxInvalidateRect(ITextHost
*iface
,
205 ITextHostTestImpl
*This
= impl_from_ITextHost(iface
);
206 TRACECALL("Call to TxInvalidateRect(%p, prc=%p, fMode=%d)\n",
210 static void WINAPI
ITextHostImpl_TxViewChange(ITextHost
*iface
, BOOL fUpdate
)
212 ITextHostTestImpl
*This
= impl_from_ITextHost(iface
);
213 TRACECALL("Call to TxViewChange(%p, fUpdate=%d)\n",
217 static BOOL WINAPI
ITextHostImpl_TxCreateCaret(ITextHost
*iface
,
219 INT xWidth
, INT yHeight
)
221 ITextHostTestImpl
*This
= impl_from_ITextHost(iface
);
222 TRACECALL("Call to TxCreateCaret(%p, nbmp=%p, xWidth=%d, yHeight=%d)\n",
223 This
, hbmp
, xWidth
, yHeight
);
227 static BOOL WINAPI
ITextHostImpl_TxShowCaret(ITextHost
*iface
, BOOL fShow
)
229 ITextHostTestImpl
*This
= impl_from_ITextHost(iface
);
230 TRACECALL("Call to TxShowCaret(%p, fShow=%d)\n",
235 static BOOL WINAPI
ITextHostImpl_TxSetCaretPos(ITextHost
*iface
,
238 ITextHostTestImpl
*This
= impl_from_ITextHost(iface
);
239 TRACECALL("Call to TxSetCaretPos(%p, x=%d, y=%d)\n", This
, x
, y
);
243 static BOOL WINAPI
ITextHostImpl_TxSetTimer(ITextHost
*iface
,
244 UINT idTimer
, UINT uTimeout
)
246 ITextHostTestImpl
*This
= impl_from_ITextHost(iface
);
247 TRACECALL("Call to TxSetTimer(%p, idTimer=%u, uTimeout=%u)\n",
248 This
, idTimer
, uTimeout
);
252 static void WINAPI
ITextHostImpl_TxKillTimer(ITextHost
*iface
, UINT idTimer
)
254 ITextHostTestImpl
*This
= impl_from_ITextHost(iface
);
255 TRACECALL("Call to TxKillTimer(%p, idTimer=%u)\n", This
, idTimer
);
258 static void WINAPI
ITextHostImpl_TxScrollWindowEx(ITextHost
*iface
,
266 ITextHostTestImpl
*This
= impl_from_ITextHost(iface
);
267 TRACECALL("Call to TxScrollWindowEx(%p, %d, %d, %p, %p, %p, %p, %d)\n",
268 This
, dx
, dy
, lprcScroll
, lprcClip
, hRgnUpdate
, lprcUpdate
, fuScroll
);
271 static void WINAPI
ITextHostImpl_TxSetCapture(ITextHost
*iface
, BOOL fCapture
)
273 ITextHostTestImpl
*This
= impl_from_ITextHost(iface
);
274 TRACECALL("Call to TxSetCapture(%p, fCapture=%d)\n", This
, fCapture
);
277 static void WINAPI
ITextHostImpl_TxSetFocus(ITextHost
*iface
)
279 ITextHostTestImpl
*This
= impl_from_ITextHost(iface
);
280 TRACECALL("Call to TxSetFocus(%p)\n", This
);
283 static void WINAPI
ITextHostImpl_TxSetCursor(ITextHost
*iface
,
287 ITextHostTestImpl
*This
= impl_from_ITextHost(iface
);
288 TRACECALL("Call to TxSetCursor(%p, hcur=%p, fText=%d)\n",
292 static BOOL WINAPI
ITextHostImpl_TxScreenToClient(ITextHost
*iface
,
295 ITextHostTestImpl
*This
= impl_from_ITextHost(iface
);
296 TRACECALL("Call to TxScreenToClient(%p, lppt=%p)\n", This
, lppt
);
300 static BOOL WINAPI
ITextHostImpl_TxClientToScreen(ITextHost
*iface
,
303 ITextHostTestImpl
*This
= impl_from_ITextHost(iface
);
304 TRACECALL("Call to TxClientToScreen(%p, lppt=%p)\n", This
, lppt
);
308 static HRESULT WINAPI
ITextHostImpl_TxActivate(ITextHost
*iface
,
311 ITextHostTestImpl
*This
= impl_from_ITextHost(iface
);
312 TRACECALL("Call to TxActivate(%p, plOldState=%p)\n", This
, plOldState
);
316 static HRESULT WINAPI
ITextHostImpl_TxDeactivate(ITextHost
*iface
,
319 ITextHostTestImpl
*This
= impl_from_ITextHost(iface
);
320 TRACECALL("Call to TxDeactivate(%p, lNewState=%d)\n", This
, lNewState
);
324 static HRESULT WINAPI
ITextHostImpl_TxGetClientRect(ITextHost
*iface
,
327 ITextHostTestImpl
*This
= impl_from_ITextHost(iface
);
328 TRACECALL("Call to TxGetClientRect(%p, prc=%p)\n", This
, prc
);
332 static HRESULT WINAPI
ITextHostImpl_TxGetViewInset(ITextHost
*iface
,
335 ITextHostTestImpl
*This
= impl_from_ITextHost(iface
);
336 TRACECALL("Call to TxGetViewInset(%p, prc=%p)\n", This
, prc
);
340 static HRESULT WINAPI
ITextHostImpl_TxGetCharFormat(ITextHost
*iface
,
341 const CHARFORMATW
**ppCF
)
343 ITextHostTestImpl
*This
= impl_from_ITextHost(iface
);
344 TRACECALL("Call to TxGetCharFormat(%p, ppCF=%p)\n", This
, ppCF
);
348 static HRESULT WINAPI
ITextHostImpl_TxGetParaFormat(ITextHost
*iface
,
349 const PARAFORMAT
**ppPF
)
351 ITextHostTestImpl
*This
= impl_from_ITextHost(iface
);
352 TRACECALL("Call to TxGetParaFormat(%p, ppPF=%p)\n", This
, ppPF
);
356 static COLORREF WINAPI
ITextHostImpl_TxGetSysColor(ITextHost
*iface
,
359 ITextHostTestImpl
*This
= impl_from_ITextHost(iface
);
360 TRACECALL("Call to TxGetSysColor(%p, nIndex=%d)\n", This
, nIndex
);
364 static HRESULT WINAPI
ITextHostImpl_TxGetBackStyle(ITextHost
*iface
,
365 TXTBACKSTYLE
*pStyle
)
367 ITextHostTestImpl
*This
= impl_from_ITextHost(iface
);
368 TRACECALL("Call to TxGetBackStyle(%p, pStyle=%p)\n", This
, pStyle
);
372 static HRESULT WINAPI
ITextHostImpl_TxGetMaxLength(ITextHost
*iface
,
375 ITextHostTestImpl
*This
= impl_from_ITextHost(iface
);
376 TRACECALL("Call to TxGetMaxLength(%p, pLength=%p)\n", This
, pLength
);
380 static HRESULT WINAPI
ITextHostImpl_TxGetScrollBars(ITextHost
*iface
,
383 ITextHostTestImpl
*This
= impl_from_ITextHost(iface
);
384 TRACECALL("Call to TxGetScrollBars(%p, pdwScrollBar=%p)\n",
389 static HRESULT WINAPI
ITextHostImpl_TxGetPasswordChar(ITextHost
*iface
,
392 ITextHostTestImpl
*This
= impl_from_ITextHost(iface
);
393 TRACECALL("Call to TxGetPasswordChar(%p, pch=%p)\n", This
, pch
);
397 static HRESULT WINAPI
ITextHostImpl_TxGetAcceleratorPos(ITextHost
*iface
,
400 ITextHostTestImpl
*This
= impl_from_ITextHost(iface
);
401 TRACECALL("Call to TxGetAcceleratorPos(%p, pch=%p)\n", This
, pch
);
405 static HRESULT WINAPI
ITextHostImpl_TxGetExtent(ITextHost
*iface
,
408 ITextHostTestImpl
*This
= impl_from_ITextHost(iface
);
409 TRACECALL("Call to TxGetExtent(%p, lpExtent=%p)\n", This
, lpExtent
);
413 static HRESULT WINAPI
ITextHostImpl_OnTxCharFormatChange(ITextHost
*iface
,
414 const CHARFORMATW
*pcf
)
416 ITextHostTestImpl
*This
= impl_from_ITextHost(iface
);
417 TRACECALL("Call to OnTxCharFormatChange(%p, pcf=%p)\n", This
, pcf
);
421 static HRESULT WINAPI
ITextHostImpl_OnTxParaFormatChange(ITextHost
*iface
,
422 const PARAFORMAT
*ppf
)
424 ITextHostTestImpl
*This
= impl_from_ITextHost(iface
);
425 TRACECALL("Call to OnTxParaFormatChange(%p, ppf=%p)\n", This
, ppf
);
429 /* This must return S_OK for the native ITextServices object to
431 static HRESULT WINAPI
ITextHostImpl_TxGetPropertyBits(ITextHost
*iface
,
435 ITextHostTestImpl
*This
= impl_from_ITextHost(iface
);
436 TRACECALL("Call to TxGetPropertyBits(%p, dwMask=0x%08x, pdwBits=%p)\n",
437 This
, dwMask
, pdwBits
);
442 static HRESULT WINAPI
ITextHostImpl_TxNotify(ITextHost
*iface
, DWORD iNotify
,
445 ITextHostTestImpl
*This
= impl_from_ITextHost(iface
);
446 TRACECALL("Call to TxNotify(%p, iNotify=%d, pv=%p)\n", This
, iNotify
, pv
);
450 static HIMC WINAPI
ITextHostImpl_TxImmGetContext(ITextHost
*iface
)
452 ITextHostTestImpl
*This
= impl_from_ITextHost(iface
);
453 TRACECALL("Call to TxImmGetContext(%p)\n", This
);
457 static void WINAPI
ITextHostImpl_TxImmReleaseContext(ITextHost
*iface
, HIMC himc
)
459 ITextHostTestImpl
*This
= impl_from_ITextHost(iface
);
460 TRACECALL("Call to TxImmReleaseContext(%p, himc=%p)\n", This
, himc
);
463 /* This function must set the variable pointed to by *lSelBarWidth.
464 Otherwise an uninitialized value will be used to calculate
465 positions and sizes even if E_NOTIMPL is returned. */
466 static HRESULT WINAPI
ITextHostImpl_TxGetSelectionBarWidth(ITextHost
*iface
,
469 ITextHostTestImpl
*This
= impl_from_ITextHost(iface
);
470 TRACECALL("Call to TxGetSelectionBarWidth(%p, lSelBarWidth=%p)\n",
476 static ITextHostVtbl itextHostVtbl
= {
477 ITextHostImpl_QueryInterface
,
478 ITextHostImpl_AddRef
,
479 ITextHostImpl_Release
,
480 ITextHostImpl_TxGetDC
,
481 ITextHostImpl_TxReleaseDC
,
482 ITextHostImpl_TxShowScrollBar
,
483 ITextHostImpl_TxEnableScrollBar
,
484 ITextHostImpl_TxSetScrollRange
,
485 ITextHostImpl_TxSetScrollPos
,
486 ITextHostImpl_TxInvalidateRect
,
487 ITextHostImpl_TxViewChange
,
488 ITextHostImpl_TxCreateCaret
,
489 ITextHostImpl_TxShowCaret
,
490 ITextHostImpl_TxSetCaretPos
,
491 ITextHostImpl_TxSetTimer
,
492 ITextHostImpl_TxKillTimer
,
493 ITextHostImpl_TxScrollWindowEx
,
494 ITextHostImpl_TxSetCapture
,
495 ITextHostImpl_TxSetFocus
,
496 ITextHostImpl_TxSetCursor
,
497 ITextHostImpl_TxScreenToClient
,
498 ITextHostImpl_TxClientToScreen
,
499 ITextHostImpl_TxActivate
,
500 ITextHostImpl_TxDeactivate
,
501 ITextHostImpl_TxGetClientRect
,
502 ITextHostImpl_TxGetViewInset
,
503 ITextHostImpl_TxGetCharFormat
,
504 ITextHostImpl_TxGetParaFormat
,
505 ITextHostImpl_TxGetSysColor
,
506 ITextHostImpl_TxGetBackStyle
,
507 ITextHostImpl_TxGetMaxLength
,
508 ITextHostImpl_TxGetScrollBars
,
509 ITextHostImpl_TxGetPasswordChar
,
510 ITextHostImpl_TxGetAcceleratorPos
,
511 ITextHostImpl_TxGetExtent
,
512 ITextHostImpl_OnTxCharFormatChange
,
513 ITextHostImpl_OnTxParaFormatChange
,
514 ITextHostImpl_TxGetPropertyBits
,
515 ITextHostImpl_TxNotify
,
516 ITextHostImpl_TxImmGetContext
,
517 ITextHostImpl_TxImmReleaseContext
,
518 ITextHostImpl_TxGetSelectionBarWidth
521 static ITextServices
*txtserv
= NULL
;
522 static ITextHostTestImpl
*dummyTextHost
;
523 static void *wrapperCodeMem
= NULL
;
525 #include "pshpack1.h"
527 /* Code structure for x86 byte code */
530 BYTE pop_eax
; /* popl %eax */
531 BYTE push_ecx
; /* pushl %ecx */
532 BYTE push_eax
; /* pushl %eax */
533 BYTE jmp_func
; /* jmp $func */
535 } THISCALL_TO_STDCALL_THUNK
;
539 BYTE pop_eax
; /* popl %eax */
540 BYTE pop_ecx
; /* popl %ecx */
541 BYTE push_eax
; /* pushl %eax */
542 BYTE mov_vtable_eax
[2]; /* movl (%ecx), %eax */
543 BYTE jmp_eax
[2]; /* jmp *$vtablefunc_offset(%eax) */
544 int vtablefunc_offset
;
545 } STDCALL_TO_THISCALL_THUNK
;
549 static void setup_thiscall_wrappers(void)
554 THISCALL_TO_STDCALL_THUNK
*thunk
;
555 STDCALL_TO_THISCALL_THUNK
*thunk2
;
557 wrapperCodeMem
= VirtualAlloc(NULL
,
558 (sizeof(ITextHostVtbl
)/sizeof(void*) - 3)
559 * sizeof(THISCALL_TO_STDCALL_THUNK
)
560 +(sizeof(ITextServicesVtbl
)/sizeof(void*) - 3)
561 * sizeof(STDCALL_TO_THISCALL_THUNK
),
562 MEM_COMMIT
, PAGE_EXECUTE_READWRITE
);
563 thunk
= wrapperCodeMem
;
565 /* Wrap all ITextHostImpl methods with code to perform a thiscall to
566 * stdcall conversion. The thiscall calling convention places the This
567 * pointer in ecx on the x86 platform, and the stdcall calling convention
568 * pushes the This pointer on the stack as the first argument.
570 * The byte code does the conversion then jumps to the real function.
572 * Each wrapper needs to be modified so that the function to jump to is
573 * modified in the byte code. */
575 /* Skip QueryInterface, AddRef, and Release native actually
576 * defined them with the stdcall calling convention. */
577 pVtable
= (void**)&itextHostVtbl
+ 3;
578 pVtableEnd
= (void**)(&itextHostVtbl
+ 1);
579 while (pVtable
!= pVtableEnd
) {
580 /* write byte code to executable memory */
581 thunk
->pop_eax
= 0x58; /* popl %eax */
582 thunk
->push_ecx
= 0x51; /* pushl %ecx */
583 thunk
->push_eax
= 0x50; /* pushl %eax */
584 thunk
->jmp_func
= 0xe9; /* jmp $func */
585 /* The address needs to be relative to the end of the jump instructions. */
586 thunk
->func
= (char*)*pVtable
- (char*)(&thunk
->func
+ 1);
592 /* Setup an ITextServices standard call vtable that will call the
593 * native thiscall vtable when the methods are called. */
595 /* QueryInterface, AddRef, and Release should be called directly on the
596 * real vtable since they use the stdcall calling convention. */
597 thunk2
= (STDCALL_TO_THISCALL_THUNK
*)thunk
;
598 pVtable
= (void**)&itextServicesStdcallVtbl
+ 3;
599 pVtableEnd
= (void**)(&itextServicesStdcallVtbl
+ 1);
600 while (pVtable
!= pVtableEnd
) {
601 /* write byte code to executable memory */
602 thunk2
->pop_eax
= 0x58; /* popl %eax */
603 thunk2
->pop_ecx
= 0x59; /* popl %ecx */
604 thunk2
->push_eax
= 0x50; /* pushl %eax */
605 thunk2
->mov_vtable_eax
[0] = 0x8b; /* movl (%ecx), %eax */
606 thunk2
->mov_vtable_eax
[1] = 0x01;
607 thunk2
->jmp_eax
[0] = 0xff; /* jmp *$vtablefunc_offset(%eax) */
608 thunk2
->jmp_eax
[1] = 0xa0;
609 thunk2
->vtablefunc_offset
= (char*)pVtable
- (char*)&itextServicesStdcallVtbl
;
614 #endif /* __i386__ */
617 /*************************************************************************/
618 /* Conformance test functions. */
620 /* Initialize the test texthost structure */
621 static BOOL
init_texthost(void)
626 dummyTextHost
= CoTaskMemAlloc(sizeof(*dummyTextHost
));
627 if (dummyTextHost
== NULL
) {
628 skip("Insufficient memory to create ITextHost interface\n");
631 dummyTextHost
->ITextHost_iface
.lpVtbl
= &itextHostVtbl
;
632 dummyTextHost
->refCount
= 1;
634 /* MSDN states that an IUnknown object is returned by
635 CreateTextServices which is then queried to obtain a
636 ITextServices object. */
637 result
= (*pCreateTextServices
)(NULL
, &dummyTextHost
->ITextHost_iface
, &init
);
638 ok(result
== S_OK
, "Did not return S_OK when created (result = %x)\n", result
);
639 if (result
!= S_OK
) {
640 CoTaskMemFree(dummyTextHost
);
641 skip("CreateTextServices failed.\n");
645 result
= IUnknown_QueryInterface(init
, pIID_ITextServices
,
647 ok((result
== S_OK
) && (txtserv
!= NULL
), "Querying interface failed (result = %x, txtserv = %p)\n", result
, txtserv
);
648 IUnknown_Release(init
);
649 if (!((result
== S_OK
) && (txtserv
!= NULL
))) {
650 CoTaskMemFree(dummyTextHost
);
651 skip("Could not retrieve ITextServices interface\n");
658 static void free_texthost(void)
660 IUnknown_Release(txtserv
);
661 CoTaskMemFree(dummyTextHost
);
664 static void test_TxGetText(void)
669 if (!init_texthost())
672 hres
= ITextServices_TxGetText(txtserv
, &rettext
);
673 ok(hres
== S_OK
, "ITextServices_TxGetText failed (result = %x)\n", hres
);
678 static void test_TxSetText(void)
682 WCHAR settext
[] = {'T','e','s','t',0};
684 if (!init_texthost())
687 hres
= ITextServices_TxSetText(txtserv
, settext
);
688 ok(hres
== S_OK
, "ITextServices_TxSetText failed (result = %x)\n", hres
);
690 hres
= ITextServices_TxGetText(txtserv
, &rettext
);
691 ok(hres
== S_OK
, "ITextServices_TxGetText failed (result = %x)\n", hres
);
693 ok(SysStringLen(rettext
) == 4,
694 "String returned of wrong length (expected 4, got %d)\n", SysStringLen(rettext
));
695 ok(memcmp(rettext
,settext
,SysStringByteLen(rettext
)) == 0,
696 "String returned differs\n");
698 SysFreeString(rettext
);
702 static void test_TxGetNaturalSize(void) {
706 /* This value is used when calling TxGetNaturalSize. MSDN says
707 that this is not supported however a null pointer cannot be
708 used as it will cause a segmentation violation. The values in
709 the structure being pointed to are required to be INT_MAX
710 otherwise calculations can give wrong values. */
711 const SIZEL psizelExtent
= {INT_MAX
,INT_MAX
};
713 static const WCHAR oneA
[] = {'A',0};
715 /* Results of measurements */
718 /* The device context to do the tests in */
721 /* Variables with the text metric information */
722 INT charwidth_caps_text
[26];
723 TEXTMETRIC tmInfo_text
;
725 if (!init_texthost())
728 hdcDraw
= GetDC(NULL
);
731 /* Populate the metric strucs */
732 SetMapMode(hdcDraw
,MM_TEXT
);
733 GetTextMetrics(hdcDraw
, &tmInfo_text
);
734 SetLastError(0xdeadbeef);
735 ret
= GetCharWidth32(hdcDraw
,'A','Z',charwidth_caps_text
);
736 if (!ret
&& GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
) {
737 win_skip("GetCharWidth32 is not available\n");
741 /* Make measurements in MM_TEXT */
742 SetMapMode(hdcDraw
,MM_TEXT
);
745 result
= ITextServices_TxSetText(txtserv
, oneA
);
746 ok(result
== S_OK
, "ITextServices_TxSetText failed (result = %x)\n", result
);
747 if (result
!= S_OK
) {
748 skip("Could not set text\n");
752 SetLastError(0xdeadbeef);
753 result
= ITextServices_TxGetNaturalSize(txtserv
, DVASPECT_CONTENT
,
755 TXTNS_FITTOCONTENT
, &psizelExtent
,
757 todo_wine
ok(result
== S_OK
|| broken(result
== E_FAIL
), /* WINXP Arabic Language */
758 "TxGetNaturalSize gave unexpected return value (result = %x)\n", result
);
759 if (result
== S_OK
) {
760 todo_wine
ok(ydim
== tmInfo_text
.tmHeight
,
761 "Height calculated incorrectly (expected %d, got %d)\n",
762 tmInfo_text
.tmHeight
, ydim
);
763 /* The native DLL adds one pixel extra when calculating widths. */
764 todo_wine
ok(xdim
>= charwidth_caps_text
[0] && xdim
<= charwidth_caps_text
[0] + 1,
765 "Width calculated incorrectly (expected %d {+1}, got %d)\n",
766 charwidth_caps_text
[0], xdim
);
768 skip("TxGetNaturalSize measurements not performed (xdim = %d, ydim = %d, result = %x, error = %x)\n",
769 xdim
, ydim
, result
, GetLastError());
772 RestoreDC(hdcDraw
,1);
773 ReleaseDC(NULL
,hdcDraw
);
777 static void test_TxDraw(void)
779 HDC tmphdc
= GetDC(NULL
);
780 DWORD dwAspect
= DVASPECT_CONTENT
;
781 HDC hicTargetDev
= NULL
; /* Means "default" device */
782 DVTARGETDEVICE
*ptd
= NULL
;
783 void *pvAspect
= NULL
;
785 RECTL client
= {0,0,100,100};
787 if (!init_texthost())
791 result
= ITextServices_TxDraw(txtserv
, dwAspect
, 0, pvAspect
, ptd
,
792 tmphdc
, hicTargetDev
, &client
, NULL
,
794 ok(result
== S_OK
, "TxDraw failed (result = %x)\n", result
);
801 DEFINE_GUID(expected_iid_itextservices
, 0x8d33f740, 0xcf58, 0x11ce, 0xa8, 0x9d, 0x00, 0xaa, 0x00, 0x6c, 0xad, 0xc5);
802 DEFINE_GUID(expected_iid_itexthost
, 0x13e670f4,0x1a5a,0x11cf,0xab,0xeb,0x00,0xaa,0x00,0xb6,0x5e,0xa1);
803 DEFINE_GUID(expected_iid_itexthost2
, 0x13e670f5,0x1a5a,0x11cf,0xab,0xeb,0x00,0xaa,0x00,0xb6,0x5e,0xa1);
805 static void test_IIDs(void)
807 ok(IsEqualIID(pIID_ITextServices
, &expected_iid_itextservices
),
808 "unexpected value for IID_ITextServices: %s\n", debugstr_guid(pIID_ITextServices
));
809 ok(IsEqualIID(pIID_ITextHost
, &expected_iid_itexthost
),
810 "unexpected value for IID_ITextHost: %s\n", debugstr_guid(pIID_ITextHost
));
811 ok(IsEqualIID(pIID_ITextHost2
, &expected_iid_itexthost2
),
812 "unexpected value for IID_ITextHost2: %s\n", debugstr_guid(pIID_ITextHost2
));
815 /* Outer IUnknown for COM aggregation tests */
817 IUnknown IUnknown_iface
;
822 static inline struct unk_impl
*impl_from_IUnknown(IUnknown
*iface
)
824 return CONTAINING_RECORD(iface
, struct unk_impl
, IUnknown_iface
);
827 static HRESULT WINAPI
unk_QueryInterface(IUnknown
*iface
, REFIID riid
, void **ppv
)
829 struct unk_impl
*This
= impl_from_IUnknown(iface
);
831 return IUnknown_QueryInterface(This
->inner_unk
, riid
, ppv
);
834 static ULONG WINAPI
unk_AddRef(IUnknown
*iface
)
836 struct unk_impl
*This
= impl_from_IUnknown(iface
);
838 return InterlockedIncrement(&This
->ref
);
841 static ULONG WINAPI
unk_Release(IUnknown
*iface
)
843 struct unk_impl
*This
= impl_from_IUnknown(iface
);
845 return InterlockedDecrement(&This
->ref
);
848 static const IUnknownVtbl unk_vtbl
=
855 static void test_COM(void)
857 struct unk_impl unk_obj
= {{&unk_vtbl
}, 19, NULL
};
858 struct ITextHostTestImpl texthost
= {{&itextHostVtbl
}, 1};
859 ITextServices
*textsrv
;
863 /* COM aggregation */
864 hr
= pCreateTextServices(&unk_obj
.IUnknown_iface
, &texthost
.ITextHost_iface
,
866 ok(hr
== S_OK
, "CreateTextServices failed: %08x\n", hr
);
867 hr
= IUnknown_QueryInterface(unk_obj
.inner_unk
, pIID_ITextServices
, (void**)&textsrv
);
868 ok(hr
== S_OK
, "QueryInterface for IID_ITextServices failed: %08x\n", hr
);
869 refcount
= ITextServices_AddRef(textsrv
);
870 ok(refcount
== unk_obj
.ref
, "CreateTextServices just pretends to support COM aggregation\n");
871 refcount
= ITextServices_Release(textsrv
);
872 ok(refcount
== unk_obj
.ref
, "CreateTextServices just pretends to support COM aggregation\n");
873 refcount
= ITextServices_Release(textsrv
);
874 ok(refcount
== 19, "Refcount should be back at 19 but is %u\n", refcount
);
876 IUnknown_Release(unk_obj
.inner_unk
);
881 setup_thiscall_wrappers();
883 /* Must explicitly LoadLibrary(). The test has no references to functions in
884 * RICHED20.DLL, so the linker doesn't actually link to it. */
885 hmoduleRichEdit
= LoadLibrary("RICHED20.DLL");
886 ok(hmoduleRichEdit
!= NULL
, "error: %d\n", (int) GetLastError());
888 pIID_ITextServices
= (IID
*)GetProcAddress(hmoduleRichEdit
, "IID_ITextServices");
889 pIID_ITextHost
= (IID
*)GetProcAddress(hmoduleRichEdit
, "IID_ITextHost");
890 pIID_ITextHost2
= (IID
*)GetProcAddress(hmoduleRichEdit
, "IID_ITextHost2");
891 pCreateTextServices
= (void*)GetProcAddress(hmoduleRichEdit
, "CreateTextServices");
902 test_TxGetNaturalSize();
905 if (wrapperCodeMem
) VirtualFree(wrapperCodeMem
, 0, MEM_RELEASE
);