From cd9da0c2a270ee6b8f8b221205b6bb8c4f441572 Mon Sep 17 00:00:00 2001 From: Austin Lund Date: Thu, 26 Jun 2008 12:28:31 +1000 Subject: [PATCH] riched20: Added windowless text services tests. Implements thiscall to stdcall and vice verse conversions for interfacing with the native dll. Has a basic ITextHost implementation for testing. Added tests for TxSetText, TxGetText, TxGetNaturalSize ITextServices functions. --- dlls/riched20/tests/Makefile.in | 5 +- dlls/riched20/tests/txtsrv.c | 1301 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 1304 insertions(+), 2 deletions(-) create mode 100644 dlls/riched20/tests/txtsrv.c diff --git a/dlls/riched20/tests/Makefile.in b/dlls/riched20/tests/Makefile.in index 0993609..a4db8f1 100644 --- a/dlls/riched20/tests/Makefile.in +++ b/dlls/riched20/tests/Makefile.in @@ -3,11 +3,12 @@ TOPOBJDIR = ../../.. SRCDIR = @srcdir@ VPATH = @srcdir@ TESTDLL = riched20.dll -IMPORTS = ole32 user32 gdi32 kernel32 +IMPORTS = ole32 user32 gdi32 kernel32 uuid riched20 CTESTS = \ editor.c \ - richole.c + richole.c \ + txtsrv.c @MAKE_TEST_RULES@ diff --git a/dlls/riched20/tests/txtsrv.c b/dlls/riched20/tests/txtsrv.c new file mode 100644 index 0000000..0a4ee52 --- /dev/null +++ b/dlls/riched20/tests/txtsrv.c @@ -0,0 +1,1301 @@ +/* + * Unit test suite for windowless rich edit controls + * + * Copyright 2008 Austin Lund + * Copyright 2008 Maarten Lankhorst + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#define COBJMACROS + +#include "config.h" +#include "wine/port.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Implement the undo of the thiscall calling convention + * + * This one is so god damn evil but it WORKS! + * + * This sets up the stack in such a way that the function pointer is + * set on %eax, bar is on %edx (but bar isn't needed, and this is not + * done here), and finally %ecx to This. + * + * "This" was the whole trouble maker since you're not supposed to + * call that, even windows methods won't let you do that in C. + * + * MSVC isn't supported, but who cares? If you want to call them there + * just create a REAL C++ interface to test with. + * + * to recap: + * ITextServices_XXX(iface, ..) becomes: + * + * First define this: + * extern HRESULT WINAPI fnTextSrv_XXX(LPVOID function, + * ITextServices *iface, ........ ); + * + * __ASM_GLOBAL_FUNC(fnTextSrv_XXX, STDCALL_TO_THISCALL) + * + * Then call: + * fnTextSrv_XXX(iface->lpVtbl->XXX, iface, ..... ); + * + * This is only needed for i386. Therefore THISCALL_NEEDED is defined + * for i386 and if it is not defined then the same wrapper just calls + * the function without the thiscall code. + * + */ + +#ifdef __i386__ + +#define STDCALL_TO_THISCALL \ + "movl 0x8(%esp), %ecx\n\t" \ + "push %ebx\n\t" \ + "movl 0x4(%esp),%ebx\n\t" \ + "movl %ebx,0xc(%esp)\n\t" \ + "popl %ebx\n\t" \ + "popl %eax\n\t" \ + "popl %eax\n\t" \ + "jmp *%eax" + +#define THISCALL_NEEDED + +#endif + +/* Every ITextServices function is now wrapped with this + * construct. The native DLL relies on this calling convention. + */ + +#ifdef THISCALL_NEEDED + +extern HRESULT WINAPI fnTextSrv_TxSendMessage(LPVOID function, + ITextServices *iface, + UINT msg, + WPARAM wparam, + LPARAM lparam, + LRESULT* plresult); + +__ASM_GLOBAL_FUNC(fnTextSrv_TxSendMessage, STDCALL_TO_THISCALL) + +#else + +#define fnTextSrv_TxSendMessage(function,iface,msg,wparam,lparam,plresult) \ + function(iface,msg,wparam,lparam,plresult) + +#endif + + +#ifdef THISCALL_NEEDED +extern HRESULT WINAPI fnTextSrv_TxDraw(LPVOID function, + ITextServices *iface, + DWORD dwDrawAspect, + LONG lindex, + void* pvAspect, + DVTARGETDEVICE* ptd, + HDC hdcDraw, + HDC hdcTargetDev, + LPCRECTL lprcBounds, + LPCRECTL lprcWBounds, + LPRECT lprcUpdate, + BOOL (CALLBACK * pfnContinue)(DWORD), + DWORD dwContinue, + LONG lViewId); +__ASM_GLOBAL_FUNC(fnTextSrv_TxDraw, STDCALL_TO_THISCALL) +#else +#define fnTextSrv_TxDraw(function, iface, dwDrawAspect, lindex, \ + pvAspect, ptd, hdcDraw, hdcTargetDev, \ + lprcBounds, lprcWBounds, lprcUpdate, \ + pfnContinue, dwContinue, lViewId) \ + function(iface, dwDrawAspect, lindex, pvAspect, \ + ptd, hdcDraw, hdcTargetDev, lprcBounds, \ + lprcWBounds, lprcUpdate, pfnContinue, \ + dwContinue, lViewId) +#endif + +#ifdef THISCALL_NEEDED +extern HRESULT WINAPI fnTextSrv_TxGetHScroll(LPVOID function, + ITextServices *iface, + LONG* plMin, + LONG* plMax, + LONG* plPos, + LONG* plPage, + BOOL* pfEnabled); + +__ASM_GLOBAL_FUNC(fnTextSrv_TxGetHScroll, STDCALL_TO_THISCALL) +#else +#define fnTextSrv_TxGetHScroll(function, iface, plMin, plMax, \ + plPos, plPage, pfEnabled) \ + function(iface, plMin, plMax, plPos, plPage, pfEnabled) +#endif + +#ifdef THISCALL_NEEDED +extern HRESULT WINAPI fnTextSrv_TxGetVScroll(LPVOID function, + ITextServices *iface, + LONG* plMin, + LONG* plMax, + LONG* plPos, + LONG* plPage, + BOOL* pfEnabled); + +__ASM_GLOBAL_FUNC(fnTextSrv_TxGetVScroll, STDCALL_TO_THISCALL) + +#else + +#define fnTextSrv_TxGetVScroll(function, iface, plMin, plMax, \ + plPos, plPage, pfEnabled) \ + function(iface, plMin, plMax, plPos, plPage, pfEnabled) + + +#endif + +#ifdef THISCALL_NEEDED + +HRESULT WINAPI fnTextSrv_OnTxSetCursor(LPVOID function, + ITextServices *iface, + DWORD dwDrawAspect, + LONG lindex, + void* pvAspect, + DVTARGETDEVICE* ptd, + HDC hdcDraw, + HDC hicTargetDev, + LPCRECT lprcClient, + INT x, INT y); + +__ASM_GLOBAL_FUNC(fnTextSrv_OnTxSetCursor, STDCALL_TO_THISCALL) + +#else + + +#define fnTextSrv_OnTxSetCursor(function, iface, dwDrawAspect, \ + lindex, pvAspect, ptd, hdcDraw, \ + hicTargetDev, lprcClient, x, y) \ + function(iface, dwDrawAspect, lindex, pvAspect, ptd, hdcDraw, \ + hicTargetDev, lprcClient, x, y) + +#endif + +#ifdef THISCALL_NEEDED + +extern HRESULT WINAPI fnTextSrv_TxQueryHitPoint(LPVOID function, + ITextServices *iface, + DWORD dwDrawAspect, + LONG lindex, + void* pvAspect, + DVTARGETDEVICE* ptd, + HDC hdcDraw, + HDC hicTargetDev, + LPCRECT lprcClient, + INT x, INT y, + DWORD* pHitResult); + +__ASM_GLOBAL_FUNC(fnTextSrv_TxQueryHitPoint, STDCALL_TO_THISCALL) + +#else + +#define fnTextSrv_TxQueryHitPoint(function, iface, dwDrawAspect, \ + lindex, pvAspect, ptd, hdcDraw, \ + hicTargetDev, lprcClient, x, y, \ + pHitResult) \ + function(iface, dwDrawAspect, lindex, pvAspect, ptd, hdcDraw, \ + hicTargetDev, lprcClient, x, y, pHitResult) + + +#endif + +#ifdef THISCALL_NEEDED + +extern HRESULT WINAPI fnTextSrv_OnTxInplaceActivate(LPVOID function, + ITextServices *iface, + LPCRECT prcClient); + +__ASM_GLOBAL_FUNC(fnTextSrv_OnTxInplaceActivate, STDCALL_TO_THISCALL) + +#else + +#define fnTextSrv_OnTxInplaceActivate(function, iface, prcClient) \ + function(iface, prcClient) + +#endif + +#ifdef THISCALL_NEEDED + +extern HRESULT WINAPI fnTextSrv_OnTxInplaceDeactivate(LPVOID function, + ITextServices *iface); + +__ASM_GLOBAL_FUNC(fnTextSrv_OnTxInplaceDeactivate, STDCALL_TO_THISCALL) + +#else + +#define fnTextSrv_OnTxInplaceDeactivate(function, iface) \ + function(iface) + +#endif + +#ifdef THISCALL_NEEDED + +extern HRESULT WINAPI fnTextSrv_OnTxUIActivate(LPVOID function, + ITextServices *iface); + +__ASM_GLOBAL_FUNC(fnTextSrv_OnTxUIActivate, STDCALL_TO_THISCALL) + +#else + +#define fnTextSrv_OnTxUIActivate(function, iface) \ + function(iface) + +#endif + +#ifdef THISCALL_NEEDED + +extern HRESULT WINAPI fnTextSrv_OnTxUIDeactivate(LPVOID function, + ITextServices *iface); + +__ASM_GLOBAL_FUNC(fnTextSrv_OnTxUIDeactivate, STDCALL_TO_THISCALL) + +#else + +#define fnTextSrv_OnTxUIDeactivate(function, iface) \ + function(iface) + +#endif + +#ifdef THISCALL_NEEDED + +extern HRESULT WINAPI fnTextSrv_TxGetText(LPVOID function, + ITextServices *iface, + BSTR* pbstrText); + +__ASM_GLOBAL_FUNC(fnTextSrv_TxGetText, STDCALL_TO_THISCALL); + +#else + +#define fnTextSrv_TxGetText(f, iface, pbstrText) f(iface, pbstrText) + +#endif + +#ifdef THISCALL_NEEDED +extern HRESULT WINAPI fnTextSrv_TxSetText(LPVOID function, + ITextServices *iface, + LPCTSTR pszText); + +__ASM_GLOBAL_FUNC(fnTextSrv_TxSetText, STDCALL_TO_THISCALL); +#else +#define fnTextSrv_TxSetText(f, iface, pszText) f(iface, pszText) +#endif + +#ifdef THISCALL_NEEDED +HRESULT WINAPI fnTextSrv_TxGetCurrentTargetX(LPVOID function, + ITextServices *iface, + LONG* x); +__ASM_GLOBAL_FUNC(fnTextSrv_TxGetCurrentTargetX, STDCALL_TO_THISCALL); +#else +#define fnTextSrv_TxGetCurrentTargetX(function, iface, x) \ + function(iface, x) +#endif + +#ifdef THISCALL_NEEDED +HRESULT WINAPI fnTextSrv_TxGetBaseLinePos(LPVOID function, + ITextServices *iface, + LONG* x); +__ASM_GLOBAL_FUNC(fnTextSrv_TxGetBaseLinePos, STDCALL_TO_THISCALL); +#else +#define fnTextSrv_TxGetBaseLinePos(function, iface, x) \ + function(iface, x) +#endif + +#ifdef THISCALL_NEEDED + +HRESULT WINAPI fnTextSrv_TxGetNaturalSize(LPVOID function, + ITextServices *iface, + DWORD dwAspect, + HDC hdcDraw, + HDC hicTargetDev, + DVTARGETDEVICE* ptd, + DWORD dwMode, + const SIZEL* psizelExtent, + LONG* pwidth, + LONG* pheight); +__ASM_GLOBAL_FUNC(fnTextSrv_TxGetNaturalSize, STDCALL_TO_THISCALL); +#else +#define fnTextSrv_TxGetNaturalSize(function, iface, dwAspect, \ + hdcDraw, hicTargetDev, ptd, \ + dwMode,psizelExtent, pwidth, \ + pheight) \ + function(iface, dwAspect, hdcDraw, hicTargetDev, ptd, dwMode, \ + psizelExtent, pwidth, pheight) +#endif + +#ifdef THISCALL_NEEDED +HRESULT WINAPI fnTextSrv_TxGetDropTarget(LPVOID function, + ITextServices *iface, + IDropTarget** ppDropTarget); +__ASM_GLOBAL_FUNC(fnTextSrv_TxGetDropTarget, STDCALL_TO_THISCALL); +#else +#define fnTextSrv_TxGetDropTarget(function, iface, ppDropTarget) \ + function(iface, ppDropTarget) +#endif + +#ifdef THISCALL_NEEDED +HRESULT WINAPI fnTextSrv_OnTxPropertyBitsChange(LPVOID function, + ITextServices *iface, + DWORD dwMask, + DWORD dwBits); +__ASM_GLOBAL_FUNC(fnTextSrv_OnTxPropertyBitsChange, STDCALL_TO_THISCALL); +#else +#define fnTextSrv_OnTxPropertyBitsChange(function, iface, dwMask, dwBits) \ + function(iface, dwMask, dwBits) +#endif + +#ifdef THISCALL_NEEDED +HRESULT WINAPI fnTextSrv_TxGetCachedSize(LPVOID function, + ITextServices *iface, + DWORD* pdwWidth, + DWORD* pdwHeight); +__ASM_GLOBAL_FUNC(fnTextSrv_TxGetCachedSize, STDCALL_TO_THISCALL); +#else +#define fnTextSrv_TxGetCachedSize(function, iface, pdwWidth, pdwHeight) \ + function(iface, pdwWidth, pdwHeight) +#endif + +/************************************************************************/ + +/* ITextHost implementation for conformance testing. */ + +/* Internal variables that control what the ITextHost methods return are + * defined in a globally accessable test implementation structure. + */ + +typedef struct ITextHostTestImpl { + ITextHostVtbl *lpVtbl; + LONG refCount; + + CHARFORMATW defCharFormat; + PARAFORMAT defParaFormat; + DWORD currentPropertyBits; + TXTBACKSTYLE currentBackStyle; + DWORD currentMaxLength; +} ITextHostTestImpl; + +static ITextHostVtbl itestvtbl; + +#define ICOM_THIS_MULTI(impl,field,iface) \ + impl* const This=(impl*)((char*)(iface) - offsetof(impl,field)) + +static HRESULT WINAPI ITextHostImpl_QueryInterface (ITextHost *iface, + REFIID riid, + LPVOID* ppvObject) { + ICOM_THIS_MULTI(ITextHostTestImpl, lpVtbl, iface); + + trace("(%p/%p) QueryInterface requesting rrid %p -> ppvObject %p\n", + This, iface, riid, ppvObject); + *ppvObject = NULL; + + if (IsEqualIID(riid, &IID_IUnknown)) + *ppvObject = (LPVOID)This; + else if (IsEqualIID(riid, &IID_ITextHost)) + *ppvObject = (LPVOID)This; + else + return E_NOINTERFACE; + + trace("ppvObject now %p\n",ppvObject); + if (*ppvObject) + { + ITextHost_AddRef((ITextHost *)(*ppvObject)); + return S_OK; + } + + return E_NOINTERFACE; +} + +static ULONG WINAPI ITextHostImpl_AddRef (ITextHost *iface) { + ICOM_THIS_MULTI(ITextHostTestImpl, lpVtbl, iface); + ULONG refCount = InterlockedIncrement(&This->refCount); + + trace("(%p/%p)->() AddRef from %d\n", This, iface, refCount - 1); + return refCount; +} + +static ULONG WINAPI ITextHostImpl_Release (ITextHost *iface) { + ICOM_THIS_MULTI(ITextHostTestImpl, lpVtbl, iface); + ULONG refCount = InterlockedDecrement(&This->refCount); + + trace("(%p/%p)->() Release from %d\n", This, iface, refCount + 1); + if (!refCount) + { + trace("Destroying Null Renderer\n"); + CoTaskMemFree(This); + return 0; + } + else + return refCount; +} + +HDC WINAPI ITextHostImpl_TxGetDC(ITextHost *iface) { + ICOM_THIS_MULTI(ITextHostTestImpl, lpVtbl, iface); + trace("(%p/%p) Call to TxGetDC\n", This, iface); + return NULL; +} + +INT WINAPI ITextHostImpl_TxReleaseDC(ITextHost *iface, + HDC hdc) { + ICOM_THIS_MULTI(ITextHostTestImpl, lpVtbl, iface); + trace("(%p/%p) Call to TxReleaseDC\n", This, iface); + return 0; +} + +BOOL WINAPI ITextHostImpl_TxShowScrollBar(ITextHost *iface, + INT fnBar, + BOOL fShow) { + ICOM_THIS_MULTI(ITextHostTestImpl, lpVtbl, iface); + trace("(%p/%p) Call to TxShowScrollBar\n", This, iface); + return E_NOTIMPL; +} + +BOOL WINAPI ITextHostImpl_TxEnableScrollBar(ITextHost *iface, + INT fuSBFlags, + INT fuArrowflags) { + ICOM_THIS_MULTI(ITextHostTestImpl, lpVtbl, iface); + trace("(%p/%p) Call to TxEnableScrollBar\n", This, iface); + return E_NOTIMPL; +} + +BOOL WINAPI ITextHostImpl_TxSetScrollRange(ITextHost *iface, + INT fnBar, + LONG nMinPos, + INT nMaxPos, + BOOL fRedraw) { + ICOM_THIS_MULTI(ITextHostTestImpl, lpVtbl, iface); + trace("(%p/%p) Call to TxSetScrollRange\n", This, iface); + return E_NOTIMPL; +} + +BOOL WINAPI ITextHostImpl_TxSetScrollPos(ITextHost *iface, + INT fnBar, + INT nPos, + BOOL fRedraw) { + ICOM_THIS_MULTI(ITextHostTestImpl, lpVtbl, iface); + trace("(%p/%p) Call to TxSetScrollPos\n", This, iface); + return E_NOTIMPL; +} + +void WINAPI ITextHostImpl_TxInvalidateRect(ITextHost *iface, + LPCRECT prc, + BOOL fMode) { + ICOM_THIS_MULTI(ITextHostTestImpl, lpVtbl, iface); + trace("(%p/%p) Call to TxInvalidateRect (prc %p, fMode %d)\n", + This, iface, prc, fMode); + if (prc != NULL) { + trace("LPCRECT prc: (%d, %d, %d, %d)\n", + prc->left,prc->top,prc->bottom,prc->right); + } +} + +void WINAPI ITextHostImpl_TxViewChange(ITextHost *iface, BOOL fUpdate) { + ICOM_THIS_MULTI(ITextHostTestImpl, lpVtbl, iface); + trace("(%p/%p) Call to TxViewChange(fUpdate: %d)\n", + This, iface, fUpdate); +} + +BOOL WINAPI ITextHostImpl_TxCreateCaret(ITextHost *iface, + HBITMAP hbmp, + INT xWidth, INT yHeight) { + ICOM_THIS_MULTI(ITextHostTestImpl, lpVtbl, iface); + trace("(%p/%p) Call to TxCreateCaret\n", This, iface); + return E_NOTIMPL; +} + +BOOL WINAPI ITextHostImpl_TxShowCaret(ITextHost *iface, BOOL fShow) { + ICOM_THIS_MULTI(ITextHostTestImpl, lpVtbl, iface); + trace("(%p/%p) Call to TxShowCaret\n", This, iface); + return E_NOTIMPL; +} + +BOOL WINAPI ITextHostImpl_TxSetCarentPos(ITextHost *iface, + INT x, INT y) { + ICOM_THIS_MULTI(ITextHostTestImpl, lpVtbl, iface); + trace("(%p/%p) Call to TxSetCarentPos\n", This, iface); + return E_NOTIMPL; +} + +BOOL WINAPI ITextHostImpl_TxSetTimer(ITextHost *iface, + UINT idTimer, UINT uTimeout) { + ICOM_THIS_MULTI(ITextHostTestImpl, lpVtbl, iface); + trace("(%p/%p) Call to TxSetTimer\n", This, iface); + return E_NOTIMPL; +} + +void WINAPI ITextHostImpl_TxKillTimer(ITextHost *iface, UINT idTimer) { + ICOM_THIS_MULTI(ITextHostTestImpl, lpVtbl, iface); + trace("(%p/%p) Call to TxKillTimer\n", This, iface); +} + +void WINAPI ITextHostImpl_TxScrollWindowEx(ITextHost *iface, + INT dx, INT dy, + LPCRECT lprcScroll, + LPCRECT lprcClip, + HRGN hRgnUpdate, + LPRECT lprcUpdate, + UINT fuScroll) { + ICOM_THIS_MULTI(ITextHostTestImpl, lpVtbl, iface); + trace("(%p/%p) Call to TxScrollWindowEx\n", This, iface); +} + +void WINAPI ITextHostImpl_TxSetCapture(ITextHost *iface, BOOL fCapture) { + ICOM_THIS_MULTI(ITextHostTestImpl, lpVtbl, iface); + trace("(%p/%p) Call to TxSetCapture\n", This, iface); +} + +void WINAPI ITextHostImpl_TxSetFocus(ITextHost *iface) { + ICOM_THIS_MULTI(ITextHostTestImpl, lpVtbl, iface); + trace("(%p/%p) Call to TxSetFocus\n", This, iface); +} + +void WINAPI ITextHostImpl_TxSetCursor(ITextHost *iface, + HCURSOR hcur, + BOOL fText) { + ICOM_THIS_MULTI(ITextHostTestImpl, lpVtbl, iface); + trace("(%p/%p) Call to TxSetCursor\n", This, iface); +} + +BOOL WINAPI ITextHostImpl_TxScreenToClient(ITextHost *iface, + LPPOINT lppt) { + ICOM_THIS_MULTI(ITextHostTestImpl, lpVtbl, iface); + trace("(%p/%p) Call to TxScreenToClient\n", This, iface); + return E_NOTIMPL; +} + +BOOL WINAPI ITextHostImpl_TxClientToScreen(ITextHost *iface, + LPPOINT lppt) { + ICOM_THIS_MULTI(ITextHostTestImpl, lpVtbl, iface); + trace("(%p/%p) Call to TxClientToScreen\n", This, iface); + return E_NOTIMPL; +} + +HRESULT WINAPI ITextHostImpl_TxActivate(ITextHost *iface, + LONG* plOldState) { + ICOM_THIS_MULTI(ITextHostTestImpl, lpVtbl, iface); + trace("(%p/%p) Call to TxActivate\n", This, iface); + return E_NOTIMPL; +} + +HRESULT WINAPI ITextHostImpl_TxDeactivate(ITextHost *iface, + LONG lNewState) { + ICOM_THIS_MULTI(ITextHostTestImpl, lpVtbl, iface); + trace("(%p/%p) Call to TxDeactivate\n", This, iface); + return E_NOTIMPL; +} + +HRESULT WINAPI ITextHostImpl_TxGetClientRect(ITextHost *iface, + LPRECT prc) { + ICOM_THIS_MULTI(ITextHostTestImpl, lpVtbl, iface); + trace("(%p/%p) Call to TxGetClientRect\n", This, iface); + return E_NOTIMPL; +} + +/* This can affect how the ITextServices object calculates where to put text + * in a really bizzare way. Returning E_NOTIMPL will avoid this calculation. + * + * How this actually affects the calculation needs to be explored. + */ +HRESULT WINAPI ITextHostImpl_TxGetViewInset(ITextHost *iface, + LPRECT prc) { + ICOM_THIS_MULTI(ITextHostTestImpl, lpVtbl, iface); + RECT ret = { 0, 0, 0, 0 }; + trace("(%p/%p) Call to TxGetViewInset (prc %p)\n", This, iface, prc); + prc = &ret; + trace("(%p/%p) TxGetViewInset returning E_NOTIMPL (%d, %d, %d, %d)\n", + This, iface, + ret.left, ret.top, ret.right, ret.bottom); + return E_NOTIMPL; +} + +HRESULT WINAPI ITextHostImpl_TxGetCharFormat(ITextHost *iface, + const CHARFORMATW** ppCF) { + ICOM_THIS_MULTI(ITextHostTestImpl, lpVtbl, iface); + char* name; + trace("(%p/%p) Call to TxGetCharFormat\n", This, iface); + + /* Gather the defCharFormat for the implementation. */ + *ppCF = &(This->defCharFormat); + name = (char *) CoTaskMemAlloc(sizeof(char)*LF_FACESIZE); + WideCharToMultiByte(CP_UTF8, 0, (*ppCF)->szFaceName, LF_FACESIZE, + name, LF_FACESIZE,NULL,NULL); + trace("Returning CharFormat %s (yHeight: %d)\n",name,(*ppCF)->yHeight); + CoTaskMemFree((LPVOID) name); + return S_OK; +} + +HRESULT WINAPI ITextHostImpl_TxGetParaFormat(ITextHost *iface, + const PARAFORMAT** ppPF) { + ICOM_THIS_MULTI(ITextHostTestImpl, lpVtbl, iface); + trace("(%p/%p) Call to TxGetParaFormat\n", This, iface); + + /* Gather the defParaFormat for the implementation. */ + *ppPF = &(This->defParaFormat); + return S_OK; +} + +/* Currently returns the background color (COLOR_WINDOW) and text + * color (COLOR_WINDOWTEXT). */ +COLORREF WINAPI ITextHostImpl_TxGetSysColor(ITextHost *iface, + int nIndex) { + ICOM_THIS_MULTI(ITextHostTestImpl, lpVtbl, iface); + trace("(%p/%p) Call to TxGetSysColor (nIndex %d)\n", This, iface, nIndex); + switch(nIndex) { + case COLOR_WINDOW: + return RGB(127,127,127); + case COLOR_WINDOWTEXT: + return RGB(0,0,0); + } + return E_NOTIMPL; +} + +HRESULT WINAPI ITextHostImpl_TxGetBackStyle(ITextHost *iface, + TXTBACKSTYLE* pStyle) { + ICOM_THIS_MULTI(ITextHostTestImpl, lpVtbl, iface); + trace("(%p/%p) Call to TxGetBackStyle\n", This, iface); + *pStyle = This->currentBackStyle; + trace("TxGetBackStyle Returning TXTBACKSTYLE %d (%p)\n",*pStyle, pStyle); + return S_OK; +} + +HRESULT WINAPI ITextHostImpl_TxGetMaxLength(ITextHost *iface, + DWORD* plength) { + ICOM_THIS_MULTI(ITextHostTestImpl, lpVtbl, iface); + trace("(%p/%p) Call to TxGetMaxLength\n", This, iface); + + *plength = This->currentMaxLength; + trace("TxGetMaxLength Returning DWORD %d (%p)\n", *plength, plength); + return S_OK; +} + +HRESULT WINAPI ITextHostImpl_TxGetScrollbars(ITextHost *iface, + DWORD* pdwScrollBar) { + ICOM_THIS_MULTI(ITextHostTestImpl, lpVtbl, iface); + trace("(%p/%p) Call to TxGetScrollbars\n", This, iface); + return E_NOTIMPL; +} + +HRESULT WINAPI ITextHostImpl_TxGetPasswordChar(ITextHost *iface, + WCHAR* pch) { + ICOM_THIS_MULTI(ITextHostTestImpl, lpVtbl, iface); + trace("(%p/%p) Call to TxGetPasswordChar\n", This, iface); + return E_NOTIMPL; +} + +HRESULT WINAPI ITextHostImpl_TxGetAcceleratorPos(ITextHost *iface, + LONG* pch) { + ICOM_THIS_MULTI(ITextHostTestImpl, lpVtbl, iface); + trace("(%p/%p) Call to TxGetAcceleratorPos\n", This, iface); + return E_NOTIMPL; +} + +/* How this function affects the output of text is seemingly random. + * Returning E_NOTIMPL seems to turn off the calculation which causes + * the weirdness. */ +HRESULT WINAPI ITextHostImpl_TxGetExtent(ITextHost *iface, + LPSIZEL lpExtent) { + ICOM_THIS_MULTI(ITextHostTestImpl, lpVtbl, iface); + trace("(%p/%p) Call to TxGetExtent (lpExtent %p)\n", + This, iface, lpExtent); + return E_NOTIMPL; +} + +HRESULT WINAPI ITextHostImpl_OnTxCharFormatChange(ITextHost *iface, + const CHARFORMATW* pcf) { + ICOM_THIS_MULTI(ITextHostTestImpl, lpVtbl, iface); + trace("(%p/%p) Call to OnTxCharFormatChange\n", This, iface); + return E_NOTIMPL; +} + +HRESULT WINAPI ITextHostImpl_OnTxParaFormatChange(ITextHost *iface, + const PARAFORMAT* ppf) { + ICOM_THIS_MULTI(ITextHostTestImpl, lpVtbl, iface); + trace("(%p/%p) Call to OnTxParaFormatChange\n", This, iface); + return E_NOTIMPL; +} + +HRESULT WINAPI ITextHostImpl_TxGetPropertyBits(ITextHost *iface, + DWORD dwMask, + DWORD* pdwBits) { + DWORD result; + ICOM_THIS_MULTI(ITextHostTestImpl, lpVtbl, iface); + trace("(%p/%p) Call to TxGetPropertyBits (dwMask 0x%08x)\n", + This, iface, dwMask); + trace("Current property bits: 0x%08x\n", This->currentPropertyBits); + result = (This->currentPropertyBits) & dwMask; + trace("Returning property bits 0x%08x\n",result); + pdwBits = &result; + return S_OK; +} + +/* TxNotify MUST return S_OK. Without it random crashes can occur. */ + +HRESULT WINAPI ITextHostImpl_TxNotify(ITextHost *iface, DWORD iNotify, + void* pv) { + ICOM_THIS_MULTI(ITextHostTestImpl, lpVtbl, iface); + trace("(%p/%p) Call to TxNotify (iNotify %d, pv %p)\n", This, + iface, iNotify, pv); + return S_OK; +} + +HIMC WINAPI ITextHostImpl_TxImmGetContext(ITextHost *iface) { + ICOM_THIS_MULTI(ITextHostTestImpl, lpVtbl, iface); + trace("(%p/%p) Call to TxImmGetContext\n", This, iface); + return 0; +} + +void WINAPI ITextHostImpl_TxImmReleaseContext(ITextHost *iface, HIMC himc) { + ICOM_THIS_MULTI(ITextHostTestImpl, lpVtbl, iface); + trace("(%p/%p) Call to TxImmReleaseContext\n", This, iface); +} + +/* This value is somehow important to the calculation of the placement + * of text. If it returns E_NOTIMPL then you get some random value + * which is probably returned from an unused variable in the + * ITextServices code. */ +HRESULT WINAPI ITextHostImpl_TxGetSelectionBarWidth(ITextHost *iface, + LONG* lSelBarWidth) { + ICOM_THIS_MULTI(ITextHostTestImpl, lpVtbl, iface); + trace("(%p/%p) Call to TxGetSelectionBarWidth (lSelBarWidth %p)\n", + This, iface, lSelBarWidth); + *lSelBarWidth = 0; + trace("(%p/%p) TxGetSelectionBarWidth returning S_OK (%d)\n", + This, iface, *lSelBarWidth); + return S_OK; +} + +/* Each function must now be converted into a thiscall style function. + * These wrappers do this. */ + +/* In order to call thiscall functions using stdcall, the values + * passed via the registers are pushed onto the call stack. The + * return pointer needs to be bypassed to maintain the intergrity of + * the stack. + */ + +#ifdef __i386__ /* thiscall functions are i386-specific */ + +#define THISCALL(func) __thiscall_ ## func +#define DEFINE_THISCALL_WRAPPER(func) \ + extern typeof(func) THISCALL(func); \ + __ASM_GLOBAL_FUNC(__thiscall_ ## func, \ + "popl %eax\n\t" \ + "pushl %ecx\n\t" \ + "pushl %eax\n\t" \ + "jmp " __ASM_NAME(#func) ) +#else /* __i386__ */ + +#define THISCALL(func) func +#define DEFINE_THISCALL_WRAPPER(func) /* nothing */ + +#endif /* __i386__ */ + + +DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxGetDC) +DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxReleaseDC) +DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxShowScrollBar) +DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxEnableScrollBar) +DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxSetScrollRange) +DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxSetScrollPos) +DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxInvalidateRect) +DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxViewChange) +DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxCreateCaret) +DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxShowCaret) +DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxSetCarentPos) +DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxSetTimer) +DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxKillTimer) +DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxScrollWindowEx) +DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxSetCapture) +DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxSetFocus) +DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxSetCursor) +DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxScreenToClient) +DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxClientToScreen) +DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxActivate) +DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxDeactivate) +DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxGetClientRect) +DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxGetViewInset) +DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxGetCharFormat) +DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxGetParaFormat) +DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxGetSysColor) +DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxGetBackStyle) +DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxGetMaxLength) +DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxGetScrollbars) +DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxGetPasswordChar) +DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxGetAcceleratorPos) +DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxGetExtent) +DEFINE_THISCALL_WRAPPER(ITextHostImpl_OnTxCharFormatChange) +DEFINE_THISCALL_WRAPPER(ITextHostImpl_OnTxParaFormatChange) +DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxGetPropertyBits) +DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxNotify) +DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxImmGetContext) +DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxImmReleaseContext) +DEFINE_THISCALL_WRAPPER(ITextHostImpl_TxGetSelectionBarWidth) + + +static ITextHostVtbl itestvtbl = { + ITextHostImpl_QueryInterface, + ITextHostImpl_AddRef, + ITextHostImpl_Release, + THISCALL(ITextHostImpl_TxGetDC), + THISCALL(ITextHostImpl_TxReleaseDC), + THISCALL(ITextHostImpl_TxShowScrollBar), + THISCALL(ITextHostImpl_TxEnableScrollBar), + THISCALL(ITextHostImpl_TxSetScrollRange), + THISCALL(ITextHostImpl_TxSetScrollPos), + THISCALL(ITextHostImpl_TxInvalidateRect), + THISCALL(ITextHostImpl_TxViewChange), + THISCALL(ITextHostImpl_TxCreateCaret), + THISCALL(ITextHostImpl_TxShowCaret), + THISCALL(ITextHostImpl_TxSetCarentPos), + THISCALL(ITextHostImpl_TxSetTimer), + THISCALL(ITextHostImpl_TxKillTimer), + THISCALL(ITextHostImpl_TxScrollWindowEx), + THISCALL(ITextHostImpl_TxSetCapture), + THISCALL(ITextHostImpl_TxSetFocus), + THISCALL(ITextHostImpl_TxSetCursor), + THISCALL(ITextHostImpl_TxScreenToClient), + THISCALL(ITextHostImpl_TxClientToScreen), + THISCALL(ITextHostImpl_TxActivate), + THISCALL(ITextHostImpl_TxDeactivate), + THISCALL(ITextHostImpl_TxGetClientRect), + THISCALL(ITextHostImpl_TxGetViewInset), + THISCALL(ITextHostImpl_TxGetCharFormat), + THISCALL(ITextHostImpl_TxGetParaFormat), + THISCALL(ITextHostImpl_TxGetSysColor), + THISCALL(ITextHostImpl_TxGetBackStyle), + THISCALL(ITextHostImpl_TxGetMaxLength), + THISCALL(ITextHostImpl_TxGetScrollbars), + THISCALL(ITextHostImpl_TxGetPasswordChar), + THISCALL(ITextHostImpl_TxGetAcceleratorPos), + THISCALL(ITextHostImpl_TxGetExtent), + THISCALL(ITextHostImpl_OnTxCharFormatChange), + THISCALL(ITextHostImpl_OnTxParaFormatChange), + THISCALL(ITextHostImpl_TxGetPropertyBits), + THISCALL(ITextHostImpl_TxNotify), + THISCALL(ITextHostImpl_TxImmGetContext), + THISCALL(ITextHostImpl_TxImmReleaseContext), + THISCALL(ITextHostImpl_TxGetSelectionBarWidth) +}; + +ITextServices *txtserv = NULL; +ITextHostTestImpl *dummyTextHost; + +/*************************************************************************/ + +/* Conformance test functions. */ + +/* Test TxSetText and actually set the text. */ +void TEST_TxSetText(LPCTSTR newtext) { + HRESULT result; + todo_wine { + result = fnTextSrv_TxSetText(txtserv->lpVtbl->TxSetText, + txtserv,newtext); + trace("Called TxSetText(%p) on (%p): 0x%08x\n", + newtext, txtserv, result); + ok(result == S_OK, "TxSetText failed\n"); + } +} + +/* Test TxGetText and actually retrieve the text. */ +LPCTSTR TEST_TxGetText() { + LPCTSTR rettext; + HRESULT result; + todo_wine { + result = fnTextSrv_TxGetText(txtserv->lpVtbl->TxGetText, + txtserv,(BSTR*)&rettext); + trace("Called TxGetText(%p) on (%p): 0x%08x\n", + rettext, txtserv, result); + ok(result == S_OK, "TxSetText failed\n"); + } + return rettext; +} + +/* Simple test that sets the text then immediately retrives it. The + * result is compared with the original. */ +void TEST_TxSetGetText(LPCTSTR newtext) { + LPCTSTR cmptext; + todo_wine { + TEST_TxSetText(newtext); + cmptext = TEST_TxGetText(); + ok(StrCmp(newtext,cmptext) == 0, + "Returned string not the same as set string\n"); + } +} + +/* This sets up variables which are unused in a default state that + * works. */ +void TEST_TxGetNaturalSize_RAW(HDC hdcDraw, DWORD dwMode, + LONG *pwidth, LONG *pheight) { + HRESULT result; + DWORD dwAspect = (DWORD) ((DVASPECT) DVASPECT_CONTENT); + HDC hicTargetDev = NULL; /* Default device */ + DVTARGETDEVICE *ptd = NULL; + /* MSDN says that this is not supported, this is absolutely required. */ + const SIZEL psizelExtent = {LONG_MAX,LONG_MAX}; + + todo_wine { + trace("Calling TxGetNaturalSize (pwdith %d, pheight %d)\n", + *pwidth, *pheight); + result = fnTextSrv_TxGetNaturalSize(txtserv->lpVtbl->TxGetNaturalSize, + txtserv, + dwAspect, hdcDraw, hicTargetDev, + ptd, dwMode, &psizelExtent, + pwidth, pheight); + trace("Called TxGetNaturalSize (pwidth %d, pheight %d)\n", + *pwidth ,*pheight); + ok(result == S_OK, "TxGetNaturalSize failed\n"); + } +} + +void TEST_TxGetNaturalSize_STRING(HDC hdcDraw, LPCTSTR lpctIn, + INT *lpintXdim, INT *lpintYdim) { + TEST_TxSetText(lpctIn); + TEST_TxGetNaturalSize_RAW(hdcDraw, TXTNS_FITTOCONTENT, + lpintXdim, lpintYdim); + trace("Calculated: %d %d\n", *lpintXdim, *lpintYdim); +} + +/* This test measures simple strings and checks the results. */ +void TEST_TxGetNaturalSize_MEASURE() { + + /* The test strings */ + static const WCHAR oneA[] = {'A',0}; + static const WCHAR twoA[] = {'A','A',0}; + static const WCHAR threeA[] = {'A','A','A',0}; + + static const WCHAR oneI[] = {'I',0}; + static const WCHAR twoI[] = {'I','I',0}; + static const WCHAR threeI[] = {'I','I','I',0}; + + static const WCHAR caps[] = {'A','B','C','D','E','F','G','H','I', + 'J','K','L','M','N','O','P','Q','R', + 'S','T','U','V','W','X','Y','Z',0}; + + /* Variables to hold the results of measurements */ + LONG xdim, ydim; + + /* The device context to do the tests in */ + HDC hdcDraw; + + /* Variables with the text metric information */ + INT charwidth_caps_text[26]; + INT charwidth_caps_himetric[26]; + INT charwidth_lower_text[26]; + INT charwidth_lower_himetric[26]; + TEXTMETRIC tmInfo_text; + TEXTMETRIC tmInfo_himetric; + INT total_caps_text, total_caps_himetric; + + /* An iterator variable */ + INT i; + + /* Obtain a device context form the root window. */ + hdcDraw = GetDC(NULL); + +#define capsize_himetric(char) charwidth_caps_himetric[(int)char - (int)'A'] +#define capsize_text(char) charwidth_caps_text[(int)char - (int)'A'] +#define size_himetric(char) charwidth_lower_himetric[(int)char - (int)'a'] +#define size_text(char) charwidth_lower_text[(int)char - (int)'a'] + + /* Populate the metric strucs with the letters from the English + * alphabet in both MM_TEXT and MM_HIMETRIC. + */ + SetMapMode(hdcDraw,MM_TEXT); + GetTextMetrics(hdcDraw, &tmInfo_text); + trace("Got height: %d (MM_TEXT)\n", tmInfo_text.tmHeight); + GetCharWidth32(hdcDraw,(UINT)'A',(UINT)'Z',charwidth_caps_text); + GetCharWidth32(hdcDraw,(UINT)'a',(UINT)'z',charwidth_lower_text); + total_caps_text = 0; + for (i = 0; i < 26; i++) + total_caps_text += charwidth_caps_text[i]; + + SetMapMode(hdcDraw,MM_HIMETRIC); + GetTextMetrics(hdcDraw, &tmInfo_himetric); + trace("Got height: %d (MM_HIMETRIC)\n", tmInfo_himetric.tmHeight); + GetCharWidth32(hdcDraw,(UINT)'A',(UINT)'Z',charwidth_caps_himetric); + GetCharWidth32(hdcDraw,(UINT)'A',(UINT)'Z',charwidth_lower_himetric); + total_caps_himetric = 0; + for (i = 0; i < 26; i++) + total_caps_himetric += charwidth_caps_himetric[i]; + + SetMapMode(hdcDraw,MM_TEXT); + + trace("Got width of A: %d himetric, %d px)\n",capsize_himetric('A'), + capsize_text('A')); + + trace("Got width of I: %d himetric, %d px\n",capsize_himetric('I'), + capsize_text('I')); + + trace("Sum of length of capitals: %d himetric, %d px\n", + total_caps_himetric, total_caps_text); + + + /* Measurements in MM_TEXT */ + todo_wine { + /* Measure a series of As */ + xdim = 0; ydim = 0; + TEST_TxGetNaturalSize_STRING(hdcDraw, (LPCTSTR)oneA, &xdim, &ydim); + ok(ydim == tmInfo_text.tmHeight, + "Height calculated incorrectly\n"); + ok(xdim >= capsize_text('A') && xdim <= capsize_text('A') + 1, + "Width calculated incorrectly\n"); + + xdim = 0; ydim = 0; + TEST_TxGetNaturalSize_STRING(hdcDraw, (LPCTSTR)twoA, &xdim, &ydim); + ok(ydim == tmInfo_text.tmHeight, + "Height calculated incorrectly\n"); + ok(xdim >= 2*capsize_text('A') && xdim <= 2*capsize_text('A') + 1, + "Width calculated incorrectly\n"); + + xdim = 0; ydim = 0; + TEST_TxGetNaturalSize_STRING(hdcDraw, (LPCTSTR)threeA, &xdim, &ydim); + ok(ydim == tmInfo_text.tmHeight, + "Height calculated incorrectly\n"); + ok(xdim >= 3*capsize_text('A') && xdim <= 3*capsize_text('A') + 1, + "Width calculated incorrectly\n"); + + /* Measure a series of Is */ + xdim = 0; ydim = 0; + TEST_TxGetNaturalSize_STRING(hdcDraw, (LPCTSTR)oneI, &xdim, &ydim); + ok(ydim == tmInfo_text.tmHeight, + "Height calculated incorrectly\n"); + ok(xdim >= capsize_text('I') && xdim <= capsize_text('I') + 1, + "Width calculated incorrectly\n"); + + xdim = 0; ydim = 0; + TEST_TxGetNaturalSize_STRING(hdcDraw, (LPCTSTR)twoI, &xdim, &ydim); + ok(ydim == tmInfo_text.tmHeight, + "Height calculated incorrectly\n"); + ok(xdim >= 2*capsize_text('I') && xdim <= 2*capsize_text('I') + 1, + "Width calculated incorrectly\n"); + + xdim = 0; ydim = 0; + TEST_TxGetNaturalSize_STRING(hdcDraw, (LPCTSTR)threeI, &xdim, &ydim); + ok(ydim == tmInfo_text.tmHeight, + "Height calculated incorrectly\n"); + ok(xdim >= 3*capsize_text('I') && xdim <= 3*capsize_text('I') + 1, + "Width calculated incorrectly\n"); + + /* Measure all capital letters */ + xdim = 0; ydim = 0; + TEST_TxGetNaturalSize_STRING(hdcDraw, (LPCTSTR)caps, &xdim, &ydim); + ok(ydim == tmInfo_text.tmHeight, + "Height calculated incorrectly\n"); + ok(xdim >= total_caps_text && xdim <= total_caps_text + 1, + "Width calculated incorrectly\n"); + } + + SaveDC(hdcDraw); + + /* Perform the measurements in MM_HIMETRIC */ + SetMapMode(hdcDraw,MM_HIMETRIC); + todo_wine{ + /* Measure a series of As */ + xdim = 0; ydim = 0; + TEST_TxGetNaturalSize_STRING(hdcDraw, (LPCTSTR)oneA, &xdim, &ydim); + ok(ydim == -tmInfo_himetric.tmHeight, + "Height calculated incorrectly\n"); + ok(xdim >= capsize_himetric('A') && + xdim <= capsize_himetric('A') + 27, + "Width calculated incorrectly\n"); + + xdim = 0; ydim = 0; + TEST_TxGetNaturalSize_STRING(hdcDraw, (LPCTSTR)twoA, &xdim, &ydim); + ok(ydim == -tmInfo_himetric.tmHeight, + "Height calculated incorrectly\n"); + ok(xdim >= 2*capsize_himetric('A') && + xdim <= 2*capsize_himetric('A') + 27, + "Width calculated incorrectly\n"); + + xdim = 0; ydim = 0; + TEST_TxGetNaturalSize_STRING(hdcDraw, (LPCTSTR)threeA, &xdim, &ydim); + ok(ydim == -tmInfo_himetric.tmHeight, + "Height calculated incorrectly\n"); + ok(xdim >= 3*capsize_himetric('A') && + xdim <= 3*capsize_himetric('A') + 27, + "Width calculated incorrectly\n"); + + /* Measure a series of Is */ + xdim = 0; ydim = 0; + TEST_TxGetNaturalSize_STRING(hdcDraw, (LPCTSTR)oneI, &xdim, &ydim); + ok(ydim == -tmInfo_himetric.tmHeight, + "Height calculated incorrectly\n"); + ok(xdim >= capsize_himetric('I') && + xdim <= capsize_himetric('I') + 27, + "Width calculated incorrectly\n"); + + xdim = 0; ydim = 0; + TEST_TxGetNaturalSize_STRING(hdcDraw, (LPCTSTR)twoI, &xdim, &ydim); + ok(ydim == -tmInfo_himetric.tmHeight, + "Height calculated incorrectly\n"); + ok(xdim >= 2*capsize_himetric('I') && + xdim <= 2*capsize_himetric('I') + 27, + "Width calculated incorrectly\n"); + + xdim = 0; ydim = 0; + TEST_TxGetNaturalSize_STRING(hdcDraw, (LPCTSTR)threeI, &xdim, &ydim); + ok(ydim == -tmInfo_himetric.tmHeight, + "Height calculated incorrectly\n"); + ok(xdim >= 3*capsize_himetric('I') && + xdim <= 3*capsize_himetric('I') + 27, + "Width calculated incorrectly\n"); + + /* Measure all capital letters */ + xdim = 0; ydim = 0; + TEST_TxGetNaturalSize_STRING(hdcDraw, (LPCTSTR)caps, &xdim, &ydim); + ok(ydim == -tmInfo_himetric.tmHeight, + "Height calculated incorrectly\n"); + ok(xdim >= total_caps_himetric && + xdim <= total_caps_himetric + 27, + "Width calculated incorrectly\n"); + } + + RestoreDC(hdcDraw,1); + ReleaseDC(NULL,hdcDraw); +} + +HRESULT callTxSendMessage(UINT msg, WPARAM w, LPARAM l, LRESULT *lr) { + HRESULT result; + result = fnTextSrv_TxSendMessage(txtserv->lpVtbl->TxSendMessage, + txtserv, msg, w, l, lr); + trace("Called TxSendMessage(%u,%lu,%p,%p)) on (%p): (lr %ld) 0x%08x\n", + msg, w, (void *)l, lr, txtserv, *lr, result); + return result; +} + +/* Get the system default font and set ITextServices and the global + * ITextHost accordingly. */ +void setDefaultFonts() { + CHARFORMATW startCharFormat; + PARAFORMAT startParaFormat; + HFONT hFont; + LONG yPixPerInch; + LOGFONT lf; + LPARAM lp; + HDC hDC; + HRESULT result; + LRESULT lr; + + hFont = (HFONT) GetStockObject(SYSTEM_FONT); + GetObject(hFont, sizeof(LOGFONT), &lf); + memset(&startCharFormat,0,sizeof(CHARFORMATW)); + startCharFormat.cbSize = sizeof(CHARFORMATW); + hDC = GetDC(NULL); + yPixPerInch = GetDeviceCaps(hDC, LOGPIXELSY); + startCharFormat.yHeight = -lf.lfHeight * 1440 / yPixPerInch; + ReleaseDC(NULL, hDC); + + startCharFormat.yOffset = 0; + startCharFormat.crTextColor = 0; + startCharFormat.dwEffects = CFM_EFFECTS | CFE_AUTOBACKCOLOR; + startCharFormat.dwEffects &= ~(CFE_PROTECTED | CFE_LINK | CFE_AUTOCOLOR); + startCharFormat.dwMask = CFM_BACKCOLOR | CFM_STYLE; + startCharFormat.bCharSet = lf.lfCharSet; + startCharFormat.bPitchAndFamily = lf.lfPitchAndFamily; + MultiByteToWideChar(CP_ACP, 0, lf.lfFaceName, LF_FACESIZE, + startCharFormat.szFaceName, LF_FACESIZE); + + memset(&startParaFormat, 0, sizeof(PARAFORMAT)); + startParaFormat.cbSize = sizeof(PARAFORMAT); + startParaFormat.dwMask = 0; + startParaFormat.wAlignment = PFA_CENTER; + startParaFormat.cTabCount = 1; + startParaFormat.rgxTabs[0] = 8; + + if (txtserv != NULL) { + lp = (LPARAM)&startCharFormat; + todo_wine { + result = callTxSendMessage(EM_SETCHARFORMAT, 0, lp, &lr); + ok((result == S_OK) && (lr != 0), + "EM_SETCHARFORMAT with default failed\n"); + } + + lp = (LPARAM)&startParaFormat; + todo_wine { + result = callTxSendMessage(EM_SETPARAFORMAT, 0, lp, &lr); + ok((result == S_OK), + "EM_SETPARAFORMAT with default failed (result: %d, lr: %d)\n", + result,(int)lr); + } + } + + dummyTextHost->defCharFormat = startCharFormat; + dummyTextHost->defParaFormat = startParaFormat; +} + +/* Initialize the test texthost structure */ +BOOL init_texthost() { + IUnknown *init; + HRESULT result; + + dummyTextHost = CoTaskMemAlloc(sizeof(*dummyTextHost)); + dummyTextHost->lpVtbl = &itestvtbl; + dummyTextHost->refCount = 1; + dummyTextHost->currentPropertyBits = + TXTBIT_MULTILINE|TXTBIT_RICHTEXT|TXTBIT_WORDWRAP; + setDefaultFonts(); + dummyTextHost->currentBackStyle = TXTBACK_OPAQUE; + dummyTextHost->currentMaxLength = 255; + + init = CoTaskMemAlloc(sizeof(*init)); + result = CreateTextServices(NULL,(ITextHost*)dummyTextHost, &init); + trace("Called CreateTextServices (IUnknown **ppUnk %p, result 0x%08x)\n", + init, result); + ok(result == S_OK, "Did not return OK when created\n"); + if (result != S_OK) return FALSE; + + + result = IUnknown_QueryInterface(init,&IID_ITextServices, + (void **) &(txtserv)); + trace("TxtSrv::QueryInterface RIID %p (return %08x) ITextServices: %p\n", + &IID_ITextServices, result, txtserv); + ok(result == S_OK, "Querying interface failed\n"); + if (result != S_OK) + return FALSE; + ok(&(*txtserv) != NULL , "Could not get ITextServices interface\n"); + + if (&(*txtserv) == NULL) + return FALSE; + return TRUE; + +} + +START_TEST( txtsrv ) +{ + static const WCHAR newtextw[] = + {'A','B','C','D','E','F','G','H','I','J','K','L','M', + 'N','O','P','Q','R','S','T','U','V','W','X','Y','Z',0}; + + if (!init_texthost()) + return; + + TEST_TxSetGetText((LPCTSTR) newtextw); + TEST_TxGetNaturalSize_MEASURE(); +} -- 1.5.4.3