txtsrv.c 13.4 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/*
 * RichEdit - functions and interfaces around CreateTextServices
 *
 * Copyright 2005, 2006, 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
18
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 20 21 22 23 24
 */

#define COBJMACROS

#include "editor.h"
#include "ole2.h"
25
#include "oleauto.h"
26
#include "richole.h"
27
#include "tom.h"
28 29 30 31 32 33 34 35
#include "imm.h"
#include "textserv.h"
#include "wine/debug.h"
#include "editstr.h"

WINE_DEFAULT_DEBUG_CHANNEL(richedit);

typedef struct ITextServicesImpl {
36
   IUnknown IUnknown_inner;
37
   ITextServices ITextServices_iface;
38
   IUnknown *outer_unk;
39
   LONG ref;
40
   ITextHost *pMyHost;
41
   CRITICAL_SECTION csTxtSrv;
42
   ME_TextEditor *editor;
43
   char spare[256];
44 45
} ITextServicesImpl;

46
static inline ITextServicesImpl *impl_from_IUnknown(IUnknown *iface)
47
{
48
   return CONTAINING_RECORD(iface, ITextServicesImpl, IUnknown_inner);
49
}
50

51
static HRESULT WINAPI ITextServicesImpl_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
52
{
53 54 55 56 57 58
   ITextServicesImpl *This = impl_from_IUnknown(iface);

   TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);

   if (IsEqualIID(riid, &IID_IUnknown))
      *ppv = &This->IUnknown_inner;
59
   else if (IsEqualIID(riid, &IID_ITextServices))
60
      *ppv = &This->ITextServices_iface;
61 62
   else if (IsEqualIID(riid, &IID_IRichEditOle) || IsEqualIID(riid, &IID_ITextDocument) ||
            IsEqualIID(riid, &IID_ITextDocument2Old)) {
63 64 65
      if (!This->editor->reOle)
         if (!CreateIRichEditOle(This->outer_unk, This->editor, (void **)(&This->editor->reOle)))
            return E_OUTOFMEMORY;
66
      return IUnknown_QueryInterface(This->editor->reOle, riid, ppv);
67
   } else {
68 69 70
      *ppv = NULL;
      FIXME("Unknown interface: %s\n", debugstr_guid(riid));
      return E_NOINTERFACE;
71
   }
72 73 74

   IUnknown_AddRef((IUnknown*)*ppv);
   return S_OK;
75 76
}

77
static ULONG WINAPI ITextServicesImpl_AddRef(IUnknown *iface)
78
{
79 80 81 82
   ITextServicesImpl *This = impl_from_IUnknown(iface);
   LONG ref = InterlockedIncrement(&This->ref);

   TRACE("(%p) ref=%d\n", This, ref);
83 84 85 86

   return ref;
}

87
static ULONG WINAPI ITextServicesImpl_Release(IUnknown *iface)
88
{
89 90
   ITextServicesImpl *This = impl_from_IUnknown(iface);
   LONG ref = InterlockedDecrement(&This->ref);
91

92
   TRACE("(%p) ref=%d\n", This, ref);
93 94 95

   if (!ref)
   {
Jactry Zeng's avatar
Jactry Zeng committed
96
      ME_DestroyEditor(This->editor);
97
      This->csTxtSrv.DebugInfo->Spare[0] = 0;
98 99 100 101 102 103
      DeleteCriticalSection(&This->csTxtSrv);
      CoTaskMemFree(This);
   }
   return ref;
}

104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
static const IUnknownVtbl textservices_inner_vtbl =
{
   ITextServicesImpl_QueryInterface,
   ITextServicesImpl_AddRef,
   ITextServicesImpl_Release
};

static inline ITextServicesImpl *impl_from_ITextServices(ITextServices *iface)
{
   return CONTAINING_RECORD(iface, ITextServicesImpl, ITextServices_iface);
}

static HRESULT WINAPI fnTextSrv_QueryInterface(ITextServices *iface, REFIID riid, void **ppv)
{
   ITextServicesImpl *This = impl_from_ITextServices(iface);
   return IUnknown_QueryInterface(This->outer_unk, riid, ppv);
}

static ULONG WINAPI fnTextSrv_AddRef(ITextServices *iface)
{
   ITextServicesImpl *This = impl_from_ITextServices(iface);
   return IUnknown_AddRef(This->outer_unk);
}

static ULONG WINAPI fnTextSrv_Release(ITextServices *iface)
{
   ITextServicesImpl *This = impl_from_ITextServices(iface);
   return IUnknown_Release(This->outer_unk);
}

134 135 136
DEFINE_THISCALL_WRAPPER(fnTextSrv_TxSendMessage,20)
DECLSPEC_HIDDEN HRESULT __thiscall fnTextSrv_TxSendMessage(ITextServices *iface, UINT msg, WPARAM wparam,
                                                           LPARAM lparam, LRESULT *plresult)
137
{
138
   ITextServicesImpl *This = impl_from_ITextServices(iface);
139
   HRESULT hresult;
140
   LRESULT lresult;
141

142 143
   lresult = ME_HandleMessage(This->editor, msg, wparam, lparam, TRUE, &hresult);
   if (plresult) *plresult = lresult;
144
   return hresult;
145 146
}

147 148 149 150 151 152
DEFINE_THISCALL_WRAPPER(fnTextSrv_TxDraw,52)
DECLSPEC_HIDDEN HRESULT __thiscall fnTextSrv_TxDraw(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)
153
{
154
   ITextServicesImpl *This = impl_from_ITextServices(iface);
155 156 157 158 159

   FIXME("%p: STUB\n", This);
   return E_NOTIMPL;
}

160 161 162
DEFINE_THISCALL_WRAPPER(fnTextSrv_TxGetHScroll,24)
DECLSPEC_HIDDEN HRESULT __thiscall fnTextSrv_TxGetHScroll(ITextServices *iface, LONG *plMin, LONG *plMax, LONG *plPos,
                                                          LONG *plPage, BOOL *pfEnabled)
163
{
164
   ITextServicesImpl *This = impl_from_ITextServices(iface);
165

166 167 168 169 170 171 172 173 174 175
   if (plMin)
      *plMin = This->editor->horz_si.nMin;
   if (plMax)
      *plMax = This->editor->horz_si.nMax;
   if (plPos)
      *plPos = This->editor->horz_si.nPos;
   if (plPage)
      *plPage = This->editor->horz_si.nPage;
   if (pfEnabled)
      *pfEnabled = (This->editor->styleFlags & WS_HSCROLL) != 0;
176
   return S_OK;
177 178
}

179 180 181
DEFINE_THISCALL_WRAPPER(fnTextSrv_TxGetVScroll,24)
DECLSPEC_HIDDEN HRESULT __thiscall fnTextSrv_TxGetVScroll(ITextServices *iface, LONG *plMin, LONG *plMax, LONG *plPos,
                                                          LONG *plPage, BOOL *pfEnabled)
182
{
183
   ITextServicesImpl *This = impl_from_ITextServices(iface);
184

185 186 187 188 189 190 191 192 193 194
   if (plMin)
      *plMin = This->editor->vert_si.nMin;
   if (plMax)
      *plMax = This->editor->vert_si.nMax;
   if (plPos)
      *plPos = This->editor->vert_si.nPos;
   if (plPage)
      *plPage = This->editor->vert_si.nPage;
   if (pfEnabled)
      *pfEnabled = (This->editor->styleFlags & WS_VSCROLL) != 0;
195
   return S_OK;
196 197
}

198 199 200 201
DEFINE_THISCALL_WRAPPER(fnTextSrv_OnTxSetCursor,40)
DECLSPEC_HIDDEN HRESULT __thiscall fnTextSrv_OnTxSetCursor(ITextServices *iface, DWORD dwDrawAspect, LONG lindex,
                                                           void *pvAspect, DVTARGETDEVICE *ptd, HDC hdcDraw,
                                                           HDC hicTargetDev, LPCRECT lprcClient, INT x, INT y)
202
{
203
   ITextServicesImpl *This = impl_from_ITextServices(iface);
204 205 206 207 208

   FIXME("%p: STUB\n", This);
   return E_NOTIMPL;
}

209 210 211 212 213
DEFINE_THISCALL_WRAPPER(fnTextSrv_TxQueryHitPoint,44)
DECLSPEC_HIDDEN HRESULT __thiscall fnTextSrv_TxQueryHitPoint(ITextServices *iface, DWORD dwDrawAspect, LONG lindex,
                                                             void *pvAspect, DVTARGETDEVICE *ptd, HDC hdcDraw,
                                                             HDC hicTargetDev, LPCRECT lprcClient, INT x, INT y,
                                                             DWORD *pHitResult)
214
{
215
   ITextServicesImpl *This = impl_from_ITextServices(iface);
216 217 218 219 220

   FIXME("%p: STUB\n", This);
   return E_NOTIMPL;
}

221 222
DEFINE_THISCALL_WRAPPER(fnTextSrv_OnTxInplaceActivate,8)
DECLSPEC_HIDDEN HRESULT __thiscall fnTextSrv_OnTxInplaceActivate(ITextServices *iface, LPCRECT prcClient)
223
{
224
   ITextServicesImpl *This = impl_from_ITextServices(iface);
225 226 227 228 229

   FIXME("%p: STUB\n", This);
   return E_NOTIMPL;
}

230 231
DEFINE_THISCALL_WRAPPER(fnTextSrv_OnTxInplaceDeactivate,4)
DECLSPEC_HIDDEN HRESULT __thiscall fnTextSrv_OnTxInplaceDeactivate(ITextServices *iface)
232
{
233
   ITextServicesImpl *This = impl_from_ITextServices(iface);
234 235 236 237 238

   FIXME("%p: STUB\n", This);
   return E_NOTIMPL;
}

239 240
DEFINE_THISCALL_WRAPPER(fnTextSrv_OnTxUIActivate,4)
DECLSPEC_HIDDEN HRESULT __thiscall fnTextSrv_OnTxUIActivate(ITextServices *iface)
241
{
242
   ITextServicesImpl *This = impl_from_ITextServices(iface);
243 244 245 246 247

   FIXME("%p: STUB\n", This);
   return E_NOTIMPL;
}

248 249
DEFINE_THISCALL_WRAPPER(fnTextSrv_OnTxUIDeactivate,4)
DECLSPEC_HIDDEN HRESULT __thiscall fnTextSrv_OnTxUIDeactivate(ITextServices *iface)
250
{
251
   ITextServicesImpl *This = impl_from_ITextServices(iface);
252 253 254 255 256

   FIXME("%p: STUB\n", This);
   return E_NOTIMPL;
}

257 258
DEFINE_THISCALL_WRAPPER(fnTextSrv_TxGetText,8)
DECLSPEC_HIDDEN HRESULT __thiscall fnTextSrv_TxGetText(ITextServices *iface, BSTR *pbstrText)
259
{
260
   ITextServicesImpl *This = impl_from_ITextServices(iface);
261
   int length;
262

263 264 265
   length = ME_GetTextLength(This->editor);
   if (length)
   {
266
      ME_Cursor start;
267 268 269 270 271
      BSTR bstr;
      bstr = SysAllocStringByteLen(NULL, length * sizeof(WCHAR));
      if (bstr == NULL)
         return E_OUTOFMEMORY;

272
      cursor_from_char_ofs( This->editor, 0, &start );
273
      ME_GetTextW(This->editor, bstr, length, &start, INT_MAX, FALSE, FALSE);
274 275 276 277 278 279
      *pbstrText = bstr;
   } else {
      *pbstrText = NULL;
   }

   return S_OK;
280 281
}

282 283
DEFINE_THISCALL_WRAPPER(fnTextSrv_TxSetText,8)
DECLSPEC_HIDDEN HRESULT __thiscall fnTextSrv_TxSetText(ITextServices *iface, LPCWSTR pszText)
284
{
285
   ITextServicesImpl *This = impl_from_ITextServices(iface);
286
   ME_Cursor cursor;
287

288
   ME_SetCursorToStart(This->editor, &cursor);
289 290 291
   ME_InternalDeleteText(This->editor, &cursor, ME_GetTextLength(This->editor), FALSE);
   if(pszText)
       ME_InsertTextFromCursor(This->editor, 0, pszText, -1, This->editor->pBuffer->pDefaultStyle);
292
   set_selection_cursors(This->editor, 0, 0);
293 294 295
   This->editor->nModifyStep = 0;
   OleFlushClipboard();
   ME_EmptyUndoStack(This->editor);
296
   ME_UpdateRepaint(This->editor, FALSE);
297 298

   return S_OK;
299 300
}

301 302
DEFINE_THISCALL_WRAPPER(fnTextSrv_TxGetCurTargetX,8)
DECLSPEC_HIDDEN HRESULT __thiscall fnTextSrv_TxGetCurTargetX(ITextServices *iface, LONG *x)
303
{
304
   ITextServicesImpl *This = impl_from_ITextServices(iface);
305 306 307 308 309

   FIXME("%p: STUB\n", This);
   return E_NOTIMPL;
}

310 311
DEFINE_THISCALL_WRAPPER(fnTextSrv_TxGetBaseLinePos,8)
DECLSPEC_HIDDEN HRESULT __thiscall fnTextSrv_TxGetBaseLinePos(ITextServices *iface, LONG *x)
312
{
313
   ITextServicesImpl *This = impl_from_ITextServices(iface);
314 315 316 317 318

   FIXME("%p: STUB\n", This);
   return E_NOTIMPL;
}

319 320 321 322
DEFINE_THISCALL_WRAPPER(fnTextSrv_TxGetNaturalSize,36)
DECLSPEC_HIDDEN HRESULT __thiscall fnTextSrv_TxGetNaturalSize(ITextServices *iface, DWORD dwAspect, HDC hdcDraw,
                                                              HDC hicTargetDev, DVTARGETDEVICE *ptd, DWORD dwMode,
                                                              const SIZEL *psizelExtent, LONG *pwidth, LONG *pheight)
323
{
324
   ITextServicesImpl *This = impl_from_ITextServices(iface);
325 326 327 328 329

   FIXME("%p: STUB\n", This);
   return E_NOTIMPL;
}

330 331
DEFINE_THISCALL_WRAPPER(fnTextSrv_TxGetDropTarget,8)
DECLSPEC_HIDDEN HRESULT __thiscall fnTextSrv_TxGetDropTarget(ITextServices *iface, IDropTarget **ppDropTarget)
332
{
333
   ITextServicesImpl *This = impl_from_ITextServices(iface);
334 335 336 337 338

   FIXME("%p: STUB\n", This);
   return E_NOTIMPL;
}

339 340
DEFINE_THISCALL_WRAPPER(fnTextSrv_OnTxPropertyBitsChange,12)
DECLSPEC_HIDDEN HRESULT __thiscall fnTextSrv_OnTxPropertyBitsChange(ITextServices *iface, DWORD dwMask, DWORD dwBits)
341
{
342
   ITextServicesImpl *This = impl_from_ITextServices(iface);
343 344 345 346 347

   FIXME("%p: STUB\n", This);
   return E_NOTIMPL;
}

348 349
DEFINE_THISCALL_WRAPPER(fnTextSrv_TxGetCachedSize,12)
DECLSPEC_HIDDEN HRESULT __thiscall fnTextSrv_TxGetCachedSize(ITextServices *iface, DWORD *pdwWidth, DWORD *pdwHeight)
350
{
351
   ITextServicesImpl *This = impl_from_ITextServices(iface);
352 353 354 355 356 357

   FIXME("%p: STUB\n", This);
   return E_NOTIMPL;
}


358
static const ITextServicesVtbl textservices_vtbl =
359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374
{
   fnTextSrv_QueryInterface,
   fnTextSrv_AddRef,
   fnTextSrv_Release,
   THISCALL(fnTextSrv_TxSendMessage),
   THISCALL(fnTextSrv_TxDraw),
   THISCALL(fnTextSrv_TxGetHScroll),
   THISCALL(fnTextSrv_TxGetVScroll),
   THISCALL(fnTextSrv_OnTxSetCursor),
   THISCALL(fnTextSrv_TxQueryHitPoint),
   THISCALL(fnTextSrv_OnTxInplaceActivate),
   THISCALL(fnTextSrv_OnTxInplaceDeactivate),
   THISCALL(fnTextSrv_OnTxUIActivate),
   THISCALL(fnTextSrv_OnTxUIDeactivate),
   THISCALL(fnTextSrv_TxGetText),
   THISCALL(fnTextSrv_TxSetText),
375
   THISCALL(fnTextSrv_TxGetCurTargetX),
376 377 378 379 380 381
   THISCALL(fnTextSrv_TxGetBaseLinePos),
   THISCALL(fnTextSrv_TxGetNaturalSize),
   THISCALL(fnTextSrv_TxGetDropTarget),
   THISCALL(fnTextSrv_OnTxPropertyBitsChange),
   THISCALL(fnTextSrv_TxGetCachedSize)
};
382 383 384 385 386 387 388

/******************************************************************
 *        CreateTextServices (RICHED20.4)
 */
HRESULT WINAPI CreateTextServices(IUnknown  *pUnkOuter, ITextHost *pITextHost, IUnknown  **ppUnk)
{
   ITextServicesImpl *ITextImpl;
389

390 391 392 393 394 395 396 397 398 399 400 401
   TRACE("%p %p --> %p\n", pUnkOuter, pITextHost, ppUnk);
   if (pITextHost == NULL)
      return E_POINTER;

   ITextImpl = CoTaskMemAlloc(sizeof(*ITextImpl));
   if (ITextImpl == NULL)
      return E_OUTOFMEMORY;
   InitializeCriticalSection(&ITextImpl->csTxtSrv);
   ITextImpl->csTxtSrv.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": ITextServicesImpl.csTxtSrv");
   ITextImpl->ref = 1;
   ITextHost_AddRef(pITextHost);
   ITextImpl->pMyHost = pITextHost;
402
   ITextImpl->IUnknown_inner.lpVtbl = &textservices_inner_vtbl;
403
   ITextImpl->ITextServices_iface.lpVtbl = &textservices_vtbl;
404
   ITextImpl->editor = ME_MakeEditor(pITextHost, FALSE);
405 406

   if (pUnkOuter)
407 408 409
      ITextImpl->outer_unk = pUnkOuter;
   else
      ITextImpl->outer_unk = &ITextImpl->IUnknown_inner;
410

411
   *ppUnk = &ITextImpl->IUnknown_inner;
412 413
   return S_OK;
}