From e4ef9c5c15c99f03c81d508a0a1ebe169460e7de Mon Sep 17 00:00:00 2001 From: Dylan Smith Date: Wed, 12 Nov 2008 14:47:24 -0500 Subject: [PATCH] richedit: Initial testing of ITextServices methods. --- dlls/riched20/tests/txtsrv.c | 91 +++++++++++++++++++++++++++++++++++- include/textserv.h | 19 -------- 2 files changed, 89 insertions(+), 21 deletions(-) diff --git a/dlls/riched20/tests/txtsrv.c b/dlls/riched20/tests/txtsrv.c index ffc52fd1c43..3d47490d975 100644 --- a/dlls/riched20/tests/txtsrv.c +++ b/dlls/riched20/tests/txtsrv.c @@ -34,6 +34,35 @@ static HMODULE hmoduleRichEdit; +/* Define C Macros for ITextServices calls. */ + +/* Use a special table for x86 machines to convert the thiscall + * calling convention. This isn't needed on other platforms. */ +#ifdef __i386__ +#define TXTSERV_VTABLE(This) (&itextServicesStdcallVtbl) +#else /* __i386__ */ +#define TXTSERV_VTABLE(This) (This)->lpVtbl +#endif /* __i386__ */ + +#define ITextServices_TxSendMessage(This,a,b,c,d) TXTSERV_VTABLE(This)->TxSendMessage(This,a,b,c,d) +#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) +#define ITextServices_TxGetHScroll(This,a,b,c,d,e) TXTSERV_VTABLE(This)->TxGetHScroll(This,a,b,c,d,e) +#define ITextServices_TxGetVScroll(This,a,b,c,d,e) TXTSERV_VTABLE(This)->TxGetVScroll(This,a,b,c,d,e) +#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) +#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) +#define ITextServices_OnTxInplaceActivate(This,a) TXTSERV_VTABLE(This)->OnTxInplaceActivate(This,a) +#define ITextServices_OnTxInplaceDeactivate(This) TXTSERV_VTABLE(This)->OnTxInplaceDeactivate(This) +#define ITextServices_OnTxUIActivate(This) TXTSERV_VTABLE(This)->OnTxUIActivate(This) +#define ITextServices_OnTxUIDeactivate(This) TXTSERV_VTABLE(This)->OnTxUIDeactivate(This) +#define ITextServices_TxGetText(This,a) TXTSERV_VTABLE(This)->TxGetText(This,a) +#define ITextServices_TxSetText(This,a) TXTSERV_VTABLE(This)->TxSetText(This,a) +#define ITextServices_TxGetCurrentTargetX(This,a) TXTSERV_VTABLE(This)->TxGetCurrentTargetX(This,a) +#define ITextServices_TxGetBaseLinePos(This,a) TXTSERV_VTABLE(This)->TxGetBaseLinePos(This,a) +#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) +#define ITextServices_TxGetDropTarget(This,a) TXTSERV_VTABLE(This)->TxGetDropTarget(This,a) +#define ITextServices_OnTxPropertyBitsChange(This,a,b) TXTSERV_VTABLE(This)->OnTxPropertyBitsChange(This,a,b) +#define ITextServices_TxGetCachedSize(This,a,b) TXTSERV_VTABLE(This)->TxGetCachedSize(This,a,b) + /* Set the WINETEST_DEBUG environment variable to be greater than 1 for verbose * function call traces of ITextHost. */ #define TRACECALL if(winetest_debug > 1) trace @@ -412,6 +441,8 @@ static HRESULT WINAPI ITextHostImpl_TxGetSelectionBarWidth(ITextHost *iface, return E_NOTIMPL; } +static ITextServicesVtbl itextServicesStdcallVtbl; + static ITextHostVtbl itextHostVtbl = { ITextHostImpl_QueryInterface, ITextHostImpl_AddRef, @@ -461,6 +492,8 @@ static ITextServices *txtserv = NULL; static ITextHostTestImpl *dummyTextHost; static void *wrapperCodeMem = NULL; +#include "pshpack1.h" + /* Code structure for x86 byte code */ typedef struct { @@ -471,6 +504,17 @@ typedef struct DWORD func; } THISCALL_TO_STDCALL_THUNK; +typedef struct +{ + BYTE pop_eax; /* popl %eax */ + BYTE pop_ecx; /* popl %ecx */ + BYTE push_eax; /* pushl %eax */ + BYTE mov_vtable_eax[2]; /* movl (%ecx), %eax */ + BYTE jmp_eax[2]; /* jmp *$vtablefunc_offset(%eax) */ + int vtablefunc_offset; +} STDCALL_TO_THISCALL_THUNK; + +#include "poppack.h" static void setup_thiscall_wrappers(void) { @@ -478,10 +522,13 @@ static void setup_thiscall_wrappers(void) void** pVtable; void** pVtableEnd; THISCALL_TO_STDCALL_THUNK *thunk; + STDCALL_TO_THISCALL_THUNK *thunk2; wrapperCodeMem = VirtualAlloc(NULL, (sizeof(ITextHostVtbl)/sizeof(void*) - 3) - * sizeof(THISCALL_TO_STDCALL_THUNK), + * sizeof(THISCALL_TO_STDCALL_THUNK) + +(sizeof(ITextServicesVtbl)/sizeof(void*) - 3) + * sizeof(STDCALL_TO_THISCALL_THUNK), MEM_COMMIT, PAGE_EXECUTE_READWRITE); thunk = wrapperCodeMem; @@ -498,7 +545,7 @@ static void setup_thiscall_wrappers(void) /* Skip QueryInterface, AddRef, and Release native actually * defined them with the stdcall calling convention. */ pVtable = (void**)&itextHostVtbl + 3; - pVtableEnd = (void**)((char*)&itextHostVtbl + sizeof(ITextHostVtbl)); + pVtableEnd = (void**)(&itextHostVtbl + 1); while (pVtable != pVtableEnd) { /* write byte code to executable memory */ thunk->pop_eax = 0x58; /* popl %eax */ @@ -511,6 +558,29 @@ static void setup_thiscall_wrappers(void) pVtable++; thunk++; } + + /* Setup an ITextServices standard call vtable that will call the + * native thiscall vtable when the methods are called. */ + + /* QueryInterface, AddRef, and Release should be called directly on the + * real vtable since they use the stdcall calling convention. */ + thunk2 = (STDCALL_TO_THISCALL_THUNK *)thunk; + pVtable = (void**)&itextServicesStdcallVtbl + 3; + pVtableEnd = (void**)(&itextServicesStdcallVtbl + 1); + while (pVtable != pVtableEnd) { + /* write byte code to executable memory */ + thunk2->pop_eax = 0x58; /* popl %eax */ + thunk2->pop_ecx = 0x59; /* popl %ecx */ + thunk2->push_eax = 0x50; /* pushl %eax */ + thunk2->mov_vtable_eax[0] = 0x8b; /* movl (%ecx), %eax */ + thunk2->mov_vtable_eax[1] = 0x01; + thunk2->jmp_eax[0] = 0xff; /* jmp *$vtablefunc_offset(%eax) */ + thunk2->jmp_eax[1] = 0xa0; + thunk2->vtablefunc_offset = (char*)pVtable - (char*)&itextServicesStdcallVtbl; + *pVtable = thunk2; + pVtable++; + thunk2++; + } #endif /* __i386__ */ } @@ -557,6 +627,21 @@ static BOOL init_texthost(void) return TRUE; } +static void test_TxGetText(void) +{ + HRESULT hres; + BSTR rettext; + + if (!init_texthost()) + return; + + hres = ITextServices_TxGetText(txtserv, &rettext); + todo_wine ok(hres == S_OK, "ITextServices_TxGetText failed\n"); + + IUnknown_Release(txtserv); + CoTaskMemFree(dummyTextHost); +} + START_TEST( txtsrv ) { setup_thiscall_wrappers(); @@ -570,6 +655,8 @@ START_TEST( txtsrv ) { IUnknown_Release(txtserv); CoTaskMemFree(dummyTextHost); + + test_TxGetText(); } if (wrapperCodeMem) VirtualFree(wrapperCodeMem, 0, MEM_RELEASE); } diff --git a/include/textserv.h b/include/textserv.h index 9b3cbf92f05..1c262acbb41 100644 --- a/include/textserv.h +++ b/include/textserv.h @@ -147,25 +147,6 @@ DECLARE_INTERFACE_(ITextServices,IUnknown) #define ITextServices_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b) #define ITextServices_AddRef(p) (p)->lpVtbl->AddRef(p) #define ITextServices_Release(p) (p)->lpVtbl->Release(p) -/*** ITextServices methods ***/ -#define ITextServices_TxSendMessage(p,a,b,c,d) (p)->lpVtbl->TxSendMessage(p,a,b,c,d) -#define ITextServices_TxDraw(p,a,b,c,d,e,f,g,h,i,j,k,l) (p)->lpVtbl->TxDraw(p,a,b,c,d,e,f,g,h,i,j,k,l) -#define ITextServices_TxGetHScroll(p,a,b,c,d,e) (p)->lpVtbl->TxGetHScroll(p,a,b,c,d,e) -#define ITextServices_TxGetVScroll(p,a,b,c,d,e) (p)->lpVtbl->TxGetVScroll(p,a,b,c,d,e) -#define ITextServices_OnTxSetCursor(p,a,b,c,d,e,f,g,h,i) (p)->lpVtbl->OnTxSetCursor(p,a,b,c,d,e,f,g,h,i) -#define ITextServices_TxQueryHitPoint(p,a,b,c,d,e,f,g,h,i,j) (p)->lpVtbl->TxQueryHitPoint(p,a,b,c,d,e,f,g,h,i,j) -#define ITextServices_OnTxInplaceActivate(p,a) (p)->lpVtbl->OnTxInplaceActivate(p,a) -#define ITextServices_OnTxInplaceDeactivate(p) (p)->lpVtbl->OnTxInplaceDeactivate(p) -#define ITextServices_OnTxUIActivate(p) (p)->lpVtbl->OnTxUIActivate(p) -#define ITextServices_OnTxUIDeactivate(p) (p)->lpVtbl->OnTxUIDeactivate(p) -#define ITextServices_TxGetText(p,a) (p)->lpVtbl->TxGetText(p,a) -#define ITextServices_TxSetText(p,a) (p)->lpVtbl->TxSetText(p,a) -#define ITextServices_TxGetCurrentTargetX(p,a) (p)->lpVtbl->TxGetCurrentTargetX(p,a) -#define ITextServices_TxGetBaseLinePos(p,a) (p)->lpVtbl->TxGetBaseLinePos(p,a) -#define ITextServices_TxGetNaturalSize(p,a,b,c,d,e,f,g,h) (p)->lpVtbl->TxGetNaturalSize(p,a,b,c,d,e,f,g,h) -#define ITextServices_TxGetDropTarget(p,a) (p)->lpVtbl->TxGetDropTarget(p,a) -#define ITextServices_OnTxPropertyBitsChange(p,a,b) (p)->lpVtbl->OnTxPropertyBitsChange(p,a,b) -#define ITextServices_TxGetCachedSize(p,a,b) (p)->lpVtbl->TxGetCachedSize(p,a,b) #endif #undef INTERFACE