diff --git a/dlls/riched20/tests/txtsrv.c b/dlls/riched20/tests/txtsrv.c index a9681a0..df8e48d 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, @@ -471,6 +502,17 @@ typedef struct void* 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 mov_vtablefunc_eax[2]; /* movl $vtablefunc_offset(%eax),%eax */ + BYTE vtablefunc_offset; + BYTE jmp_eax[2]; /* jmp *%eax */ +} STDCALL_TO_THISCALL_THUNK; + static void setup_thiscall_wrappers() { @@ -481,7 +523,9 @@ static void setup_thiscall_wrappers() 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_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE); pCode = wrapperCodeMem; @@ -516,6 +560,35 @@ static void setup_thiscall_wrappers() pVtable++; pCode = (char*)++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. */ + FillMemory(&itextServicesStdcallVtbl, sizeof(void**) * 3, 0); + pVtable = (void**)&itextServicesStdcallVtbl + 3; + pVtableEnd = (void**)((char*)&itextServicesStdcallVtbl + sizeof(ITextServicesVtbl)); + while (pVtable != pVtableEnd) { + STDCALL_TO_THISCALL_THUNK *thunk = (STDCALL_TO_THISCALL_THUNK*)pCode; + + /* write byte code to executable memory */ + thunk->pop_eax = 0x58; /* popl %eax */ + thunk->pop_ecx = 0x59; /* popl %ecx */ + thunk->push_eax = 0x50; /* pushl %eax */ + thunk->mov_vtable_eax[0] = 0x8b; /* movl (%ecx), %eax */ + thunk->mov_vtable_eax[1] = 0x01; + thunk->mov_vtablefunc_eax[0] = 0x8b; /* movl $vtablefunc_offset(%eax),%eax */ + thunk->mov_vtablefunc_eax[1] = 0x40; + thunk->vtablefunc_offset = (BYTE)(pVtable - (void**)&itextServicesStdcallVtbl) + * sizeof(void*); + thunk->jmp_eax[0] = 0xff; /* jmp *%eax */ + thunk->jmp_eax[1] = 0xe0; + + *pVtable = pCode; + pVtable++; + pCode = (char*)++thunk; + } #endif /* __i386__ */ } @@ -570,6 +643,21 @@ BOOL init_texthost() return TRUE; } +static void test_TxGetText() +{ + 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(); @@ -587,5 +675,7 @@ START_TEST( txtsrv ) IUnknown_Release(txtserv); CoTaskMemFree(dummyTextHost); + test_TxGetText(); + destroy_thiscall_wrappers(); } diff --git a/include/textserv.h b/include/textserv.h index 9b3cbf9..1c262ac 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