msctf: Fix an error message.
[wine] / dlls / msctf / context.c
1 /*
2  *  ITfContext implementation
3  *
4  *  Copyright 2009 Aric Stewart, CodeWeavers
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * 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 #include "config.h"
22
23 #include <stdarg.h>
24
25 #define COBJMACROS
26
27 #include "wine/debug.h"
28 #include "windef.h"
29 #include "winbase.h"
30 #include "winreg.h"
31 #include "winuser.h"
32 #include "shlwapi.h"
33 #include "winerror.h"
34 #include "objbase.h"
35 #include "olectl.h"
36
37 #include "wine/unicode.h"
38 #include "wine/list.h"
39
40 #include "msctf.h"
41 #include "msctf_internal.h"
42
43 WINE_DEFAULT_DEBUG_CHANNEL(msctf);
44
45 typedef struct tagContextSink {
46     struct list         entry;
47     union {
48         /* Context Sinks */
49         IUnknown            *pIUnknown;
50         /* ITfContextKeyEventSink  *pITfContextKeyEventSink; */
51         /* ITfEditTransactionSink  *pITfEditTransactionSink; */
52         /* ITfStatusSink           *pITfStatusSink; */
53         ITfTextEditSink     *pITfTextEditSink;
54         /* ITfTextLayoutSink       *pITfTextLayoutSink; */
55     } interfaces;
56 } ContextSink;
57
58 typedef struct tagContext {
59     const ITfContextVtbl *ContextVtbl;
60     const ITfSourceVtbl *SourceVtbl;
61     /* const ITfContextCompositionVtbl *ContextCompositionVtbl; */
62     /* const ITfContextOwnerCompositionServicesVtbl *ContextOwnerCompositionServicesVtbl; */
63     /* const ITfContextOwnerServicesVtbl *ContextOwnerServicesVtbl; */
64     /* const ITfInsertAtSelectionVtbl *InsertAtSelectionVtbl; */
65     /* const ITfMouseTrackerVtbl *MouseTrackerVtbl; */
66     /* const ITfQueryEmbeddedVtbl *QueryEmbeddedVtbl; */
67     /* const ITfSourceSingleVtbl *SourceSingleVtbl; */
68     LONG refCount;
69     BOOL connected;
70
71     TfClientId tidOwner;
72
73     ITextStoreACP   *pITextStoreACP;
74     ITfContextOwnerCompositionSink *pITfContextOwnerCompositionSink;
75
76     ITextStoreACPSink *pITextStoreACPSink;
77     ITfEditSession* currentEditSession;
78
79     /* kept as separate lists to reduce unnecessary iterations */
80     struct list     pContextKeyEventSink;
81     struct list     pEditTransactionSink;
82     struct list     pStatusSink;
83     struct list     pTextEditSink;
84     struct list     pTextLayoutSink;
85
86 } Context;
87
88
89 typedef struct tagTextStoreACPSink {
90     const ITextStoreACPSinkVtbl *TextStoreACPSinkVtbl;
91     /* const ITextStoreACPServicesVtbl *TextStoreACPServicesVtbl; */
92     LONG refCount;
93
94     Context *pContext;
95 } TextStoreACPSink;
96
97
98 static HRESULT TextStoreACPSink_Constructor(ITextStoreACPSink **ppOut, Context *pContext);
99
100 static inline Context *impl_from_ITfSourceVtbl(ITfSource *iface)
101 {
102     return (Context *)((char *)iface - FIELD_OFFSET(Context,SourceVtbl));
103 }
104
105 static void free_sink(ContextSink *sink)
106 {
107         IUnknown_Release(sink->interfaces.pIUnknown);
108         HeapFree(GetProcessHeap(),0,sink);
109 }
110
111 static void Context_Destructor(Context *This)
112 {
113     struct list *cursor, *cursor2;
114     TRACE("destroying %p\n", This);
115
116     if (This->pITextStoreACPSink)
117     {
118         ITextStoreACP_UnadviseSink(This->pITextStoreACP, (IUnknown*)This->pITextStoreACPSink);
119         ITextStoreACPSink_Release(This->pITextStoreACPSink);
120     }
121
122     if (This->pITextStoreACP)
123         ITextStoreACPSink_Release(This->pITextStoreACP);
124
125     if (This->pITfContextOwnerCompositionSink)
126         ITextStoreACPSink_Release(This->pITfContextOwnerCompositionSink);
127
128     LIST_FOR_EACH_SAFE(cursor, cursor2, &This->pContextKeyEventSink)
129     {
130         ContextSink* sink = LIST_ENTRY(cursor,ContextSink,entry);
131         list_remove(cursor);
132         free_sink(sink);
133     }
134     LIST_FOR_EACH_SAFE(cursor, cursor2, &This->pEditTransactionSink)
135     {
136         ContextSink* sink = LIST_ENTRY(cursor,ContextSink,entry);
137         list_remove(cursor);
138         free_sink(sink);
139     }
140     LIST_FOR_EACH_SAFE(cursor, cursor2, &This->pStatusSink)
141     {
142         ContextSink* sink = LIST_ENTRY(cursor,ContextSink,entry);
143         list_remove(cursor);
144         free_sink(sink);
145     }
146     LIST_FOR_EACH_SAFE(cursor, cursor2, &This->pTextEditSink)
147     {
148         ContextSink* sink = LIST_ENTRY(cursor,ContextSink,entry);
149         list_remove(cursor);
150         free_sink(sink);
151     }
152     LIST_FOR_EACH_SAFE(cursor, cursor2, &This->pTextLayoutSink)
153     {
154         ContextSink* sink = LIST_ENTRY(cursor,ContextSink,entry);
155         list_remove(cursor);
156         free_sink(sink);
157     }
158
159     HeapFree(GetProcessHeap(),0,This);
160 }
161
162 static HRESULT WINAPI Context_QueryInterface(ITfContext *iface, REFIID iid, LPVOID *ppvOut)
163 {
164     Context *This = (Context *)iface;
165     *ppvOut = NULL;
166
167     if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_ITfContext))
168     {
169         *ppvOut = This;
170     }
171     else if (IsEqualIID(iid, &IID_ITfSource))
172     {
173         *ppvOut = &This->SourceVtbl;
174     }
175
176     if (*ppvOut)
177     {
178         IUnknown_AddRef(iface);
179         return S_OK;
180     }
181
182     WARN("unsupported interface: %s\n", debugstr_guid(iid));
183     return E_NOINTERFACE;
184 }
185
186 static ULONG WINAPI Context_AddRef(ITfContext *iface)
187 {
188     Context *This = (Context *)iface;
189     return InterlockedIncrement(&This->refCount);
190 }
191
192 static ULONG WINAPI Context_Release(ITfContext *iface)
193 {
194     Context *This = (Context *)iface;
195     ULONG ret;
196
197     ret = InterlockedDecrement(&This->refCount);
198     if (ret == 0)
199         Context_Destructor(This);
200     return ret;
201 }
202
203 /*****************************************************
204  * ITfContext functions
205  *****************************************************/
206 static HRESULT WINAPI Context_RequestEditSession (ITfContext *iface,
207         TfClientId tid, ITfEditSession *pes, DWORD dwFlags,
208         HRESULT *phrSession)
209 {
210     HRESULT hr;
211     Context *This = (Context *)iface;
212     DWORD  dwLockFlags = 0x0;
213     TS_STATUS status;
214
215     TRACE("(%p) %i %p %x %p\n",This, tid, pes, dwFlags, phrSession);
216
217     if (!(dwFlags & TF_ES_READ) && !(dwFlags & TF_ES_READWRITE))
218     {
219         *phrSession = E_FAIL;
220         return E_INVALIDARG;
221     }
222
223     if (!This->pITextStoreACP)
224     {
225         FIXME("No ITextStoreACP avaliable\n");
226         *phrSession = E_FAIL;
227         return E_FAIL;
228     }
229
230     if (!(dwFlags & TF_ES_ASYNC))
231         dwLockFlags |= TS_LF_SYNC;
232
233     if (dwFlags & TF_ES_READ)
234         dwLockFlags |= TS_LF_READ;
235     else if ((dwFlags & TF_ES_READWRITE) == TF_ES_READWRITE)
236         dwLockFlags |= TS_LF_READWRITE;
237
238     /* TODO: cache this */
239     ITextStoreACP_GetStatus(This->pITextStoreACP, &status);
240
241     if (((dwFlags & TF_ES_READWRITE) == TF_ES_READWRITE) && (status.dwDynamicFlags & TS_SD_READONLY))
242     {
243         *phrSession = TS_E_READONLY;
244         return S_OK;
245     }
246
247     if (FAILED (ITfEditSession_QueryInterface(pes, &IID_ITfEditSession, (LPVOID*)&This->currentEditSession)))
248     {
249         *phrSession = E_FAIL;
250         return E_INVALIDARG;
251     }
252
253
254     hr = ITextStoreACP_RequestLock(This->pITextStoreACP, dwLockFlags, phrSession);
255
256     return hr;
257 }
258
259 static HRESULT WINAPI Context_InWriteSession (ITfContext *iface,
260          TfClientId tid,
261          BOOL *pfWriteSession)
262 {
263     Context *This = (Context *)iface;
264     FIXME("STUB:(%p)\n",This);
265     return E_NOTIMPL;
266 }
267
268 static HRESULT WINAPI Context_GetSelection (ITfContext *iface,
269         TfEditCookie ec, ULONG ulIndex, ULONG ulCount,
270         TF_SELECTION *pSelection, ULONG *pcFetched)
271 {
272     Context *This = (Context *)iface;
273     FIXME("STUB:(%p)\n",This);
274     return E_NOTIMPL;
275 }
276
277 static HRESULT WINAPI Context_SetSelection (ITfContext *iface,
278         TfEditCookie ec, ULONG ulCount, const TF_SELECTION *pSelection)
279 {
280     Context *This = (Context *)iface;
281     FIXME("STUB:(%p)\n",This);
282     return E_NOTIMPL;
283 }
284
285 static HRESULT WINAPI Context_GetStart (ITfContext *iface,
286         TfEditCookie ec, ITfRange **ppStart)
287 {
288     Context *This = (Context *)iface;
289     FIXME("STUB:(%p)\n",This);
290     return E_NOTIMPL;
291 }
292
293 static HRESULT WINAPI Context_GetEnd (ITfContext *iface,
294         TfEditCookie ec, ITfRange **ppEnd)
295 {
296     Context *This = (Context *)iface;
297     FIXME("STUB:(%p)\n",This);
298     return E_NOTIMPL;
299 }
300
301 static HRESULT WINAPI Context_GetActiveView (ITfContext *iface,
302   ITfContextView **ppView)
303 {
304     Context *This = (Context *)iface;
305     FIXME("STUB:(%p)\n",This);
306     return E_NOTIMPL;
307 }
308
309 static HRESULT WINAPI Context_EnumViews (ITfContext *iface,
310         IEnumTfContextViews **ppEnum)
311 {
312     Context *This = (Context *)iface;
313     FIXME("STUB:(%p)\n",This);
314     return E_NOTIMPL;
315 }
316
317 static HRESULT WINAPI Context_GetStatus (ITfContext *iface,
318         TF_STATUS *pdcs)
319 {
320     Context *This = (Context *)iface;
321     FIXME("STUB:(%p)\n",This);
322     return E_NOTIMPL;
323 }
324
325 static HRESULT WINAPI Context_GetProperty (ITfContext *iface,
326         REFGUID guidProp, ITfProperty **ppProp)
327 {
328     Context *This = (Context *)iface;
329     FIXME("STUB:(%p)\n",This);
330     return E_NOTIMPL;
331 }
332
333 static HRESULT WINAPI Context_GetAppProperty (ITfContext *iface,
334         REFGUID guidProp, ITfReadOnlyProperty **ppProp)
335 {
336     Context *This = (Context *)iface;
337     FIXME("STUB:(%p)\n",This);
338     return E_NOTIMPL;
339 }
340
341 static HRESULT WINAPI Context_TrackProperties (ITfContext *iface,
342         const GUID **prgProp, ULONG cProp, const GUID **prgAppProp,
343         ULONG cAppProp, ITfReadOnlyProperty **ppProperty)
344 {
345     Context *This = (Context *)iface;
346     FIXME("STUB:(%p)\n",This);
347     return E_NOTIMPL;
348 }
349
350 static HRESULT WINAPI Context_EnumProperties (ITfContext *iface,
351         IEnumTfProperties **ppEnum)
352 {
353     Context *This = (Context *)iface;
354     FIXME("STUB:(%p)\n",This);
355     return E_NOTIMPL;
356 }
357
358 static HRESULT WINAPI Context_GetDocumentMgr (ITfContext *iface,
359         ITfDocumentMgr **ppDm)
360 {
361     Context *This = (Context *)iface;
362     FIXME("STUB:(%p)\n",This);
363     return E_NOTIMPL;
364 }
365
366 static HRESULT WINAPI Context_CreateRangeBackup (ITfContext *iface,
367         TfEditCookie ec, ITfRange *pRange, ITfRangeBackup **ppBackup)
368 {
369     Context *This = (Context *)iface;
370     FIXME("STUB:(%p)\n",This);
371     return E_NOTIMPL;
372 }
373
374 static const ITfContextVtbl Context_ContextVtbl =
375 {
376     Context_QueryInterface,
377     Context_AddRef,
378     Context_Release,
379
380     Context_RequestEditSession,
381     Context_InWriteSession,
382     Context_GetSelection,
383     Context_SetSelection,
384     Context_GetStart,
385     Context_GetEnd,
386     Context_GetActiveView,
387     Context_EnumViews,
388     Context_GetStatus,
389     Context_GetProperty,
390     Context_GetAppProperty,
391     Context_TrackProperties,
392     Context_EnumProperties,
393     Context_GetDocumentMgr,
394     Context_CreateRangeBackup
395 };
396
397 static HRESULT WINAPI Source_QueryInterface(ITfSource *iface, REFIID iid, LPVOID *ppvOut)
398 {
399     Context *This = impl_from_ITfSourceVtbl(iface);
400     return Context_QueryInterface((ITfContext *)This, iid, *ppvOut);
401 }
402
403 static ULONG WINAPI Source_AddRef(ITfSource *iface)
404 {
405     Context *This = impl_from_ITfSourceVtbl(iface);
406     return Context_AddRef((ITfContext *)This);
407 }
408
409 static ULONG WINAPI Source_Release(ITfSource *iface)
410 {
411     Context *This = impl_from_ITfSourceVtbl(iface);
412     return Context_Release((ITfContext *)This);
413 }
414
415 /*****************************************************
416  * ITfSource functions
417  *****************************************************/
418 static WINAPI HRESULT ContextSource_AdviseSink(ITfSource *iface,
419         REFIID riid, IUnknown *punk, DWORD *pdwCookie)
420 {
421     ContextSink *es;
422     Context *This = impl_from_ITfSourceVtbl(iface);
423     TRACE("(%p) %s %p %p\n",This,debugstr_guid(riid),punk,pdwCookie);
424
425     if (!riid || !punk || !pdwCookie)
426         return E_INVALIDARG;
427
428     if (IsEqualIID(riid, &IID_ITfTextEditSink))
429     {
430         es = HeapAlloc(GetProcessHeap(),0,sizeof(ContextSink));
431         if (!es)
432             return E_OUTOFMEMORY;
433         if (FAILED(IUnknown_QueryInterface(punk, riid, (LPVOID *)&es->interfaces.pITfTextEditSink)))
434         {
435             HeapFree(GetProcessHeap(),0,es);
436             return CONNECT_E_CANNOTCONNECT;
437         }
438         list_add_head(&This->pTextEditSink ,&es->entry);
439         *pdwCookie = generate_Cookie(COOKIE_MAGIC_CONTEXTSINK, es);
440     }
441     else
442     {
443         FIXME("(%p) Unhandled Sink: %s\n",This,debugstr_guid(riid));
444         return E_NOTIMPL;
445     }
446
447     TRACE("cookie %x\n",*pdwCookie);
448     return S_OK;
449 }
450
451 static WINAPI HRESULT ContextSource_UnadviseSink(ITfSource *iface, DWORD pdwCookie)
452 {
453     ContextSink *sink;
454     Context *This = impl_from_ITfSourceVtbl(iface);
455
456     TRACE("(%p) %x\n",This,pdwCookie);
457
458     if (get_Cookie_magic(pdwCookie)!=COOKIE_MAGIC_CONTEXTSINK)
459         return E_INVALIDARG;
460
461     sink = (ContextSink*)remove_Cookie(pdwCookie);
462     if (!sink)
463         return CONNECT_E_NOCONNECTION;
464
465     list_remove(&sink->entry);
466     free_sink(sink);
467
468     return S_OK;
469 }
470
471 static const ITfSourceVtbl Context_SourceVtbl =
472 {
473     Source_QueryInterface,
474     Source_AddRef,
475     Source_Release,
476
477     ContextSource_AdviseSink,
478     ContextSource_UnadviseSink,
479 };
480
481 HRESULT Context_Constructor(TfClientId tidOwner, IUnknown *punk, ITfContext **ppOut, TfEditCookie *pecTextStore)
482 {
483     Context *This;
484
485     This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(Context));
486     if (This == NULL)
487         return E_OUTOFMEMORY;
488
489     TRACE("(%p) %x %p %p %p\n",This, tidOwner, punk, ppOut, pecTextStore);
490
491     This->ContextVtbl= &Context_ContextVtbl;
492     This->SourceVtbl = &Context_SourceVtbl;
493     This->refCount = 1;
494     This->tidOwner = tidOwner;
495     This->connected = FALSE;
496
497     if (punk)
498     {
499         IUnknown_QueryInterface(punk, &IID_ITextStoreACP,
500                           (LPVOID*)&This->pITextStoreACP);
501
502         IUnknown_QueryInterface(punk, &IID_ITfContextOwnerCompositionSink,
503                                 (LPVOID*)&This->pITfContextOwnerCompositionSink);
504
505         if (!This->pITextStoreACP && !This->pITfContextOwnerCompositionSink)
506             FIXME("Unhandled pUnk\n");
507     }
508
509     TRACE("returning %p\n", This);
510     *ppOut = (ITfContext*)This;
511     /* FIXME */
512     *pecTextStore = 0xdeaddead;
513
514     list_init(&This->pContextKeyEventSink);
515     list_init(&This->pEditTransactionSink);
516     list_init(&This->pStatusSink);
517     list_init(&This->pTextEditSink);
518     list_init(&This->pTextLayoutSink);
519
520     return S_OK;
521 }
522
523 HRESULT Context_Initialize(ITfContext *iface)
524 {
525     Context *This = (Context *)iface;
526
527     if (This->pITextStoreACP)
528     {
529         if (SUCCEEDED(TextStoreACPSink_Constructor(&This->pITextStoreACPSink, This)))
530             ITextStoreACP_AdviseSink(This->pITextStoreACP, &IID_ITextStoreACPSink,
531                             (IUnknown*)This->pITextStoreACPSink, TS_AS_ALL_SINKS);
532     }
533     This->connected = TRUE;
534     return S_OK;
535 }
536
537 HRESULT Context_Uninitialize(ITfContext *iface)
538 {
539     Context *This = (Context *)iface;
540
541     if (This->pITextStoreACPSink)
542     {
543         ITextStoreACP_UnadviseSink(This->pITextStoreACP, (IUnknown*)This->pITextStoreACPSink);
544         if (ITextStoreACPSink_Release(This->pITextStoreACPSink) == 0)
545             This->pITextStoreACPSink = NULL;
546     }
547     This->connected = FALSE;
548     return S_OK;
549 }
550
551 /**************************************************************************
552  *  ITextStoreACPSink
553  **************************************************************************/
554
555 static void TextStoreACPSink_Destructor(TextStoreACPSink *This)
556 {
557     TRACE("destroying %p\n", This);
558     HeapFree(GetProcessHeap(),0,This);
559 }
560
561 static HRESULT WINAPI TextStoreACPSink_QueryInterface(ITextStoreACPSink *iface, REFIID iid, LPVOID *ppvOut)
562 {
563     TextStoreACPSink *This = (TextStoreACPSink *)iface;
564     *ppvOut = NULL;
565
566     if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_ITextStoreACPSink))
567     {
568         *ppvOut = This;
569     }
570
571     if (*ppvOut)
572     {
573         IUnknown_AddRef(iface);
574         return S_OK;
575     }
576
577     WARN("unsupported interface: %s\n", debugstr_guid(iid));
578     return E_NOINTERFACE;
579 }
580
581 static ULONG WINAPI TextStoreACPSink_AddRef(ITextStoreACPSink *iface)
582 {
583     TextStoreACPSink *This = (TextStoreACPSink *)iface;
584     return InterlockedIncrement(&This->refCount);
585 }
586
587 static ULONG WINAPI TextStoreACPSink_Release(ITextStoreACPSink *iface)
588 {
589     TextStoreACPSink *This = (TextStoreACPSink *)iface;
590     ULONG ret;
591
592     ret = InterlockedDecrement(&This->refCount);
593     if (ret == 0)
594         TextStoreACPSink_Destructor(This);
595     return ret;
596 }
597
598 /*****************************************************
599  * ITextStoreACPSink functions
600  *****************************************************/
601
602 static HRESULT WINAPI TextStoreACPSink_OnTextChange(ITextStoreACPSink *iface,
603         DWORD dwFlags, const TS_TEXTCHANGE *pChange)
604 {
605     TextStoreACPSink *This = (TextStoreACPSink *)iface;
606     FIXME("STUB:(%p)\n",This);
607     return E_NOTIMPL;
608 }
609
610 static HRESULT WINAPI TextStoreACPSink_OnSelectionChange(ITextStoreACPSink *iface)
611 {
612     TextStoreACPSink *This = (TextStoreACPSink *)iface;
613     FIXME("STUB:(%p)\n",This);
614     return E_NOTIMPL;
615 }
616
617 static HRESULT WINAPI TextStoreACPSink_OnLayoutChange(ITextStoreACPSink *iface,
618     TsLayoutCode lcode, TsViewCookie vcView)
619 {
620     TextStoreACPSink *This = (TextStoreACPSink *)iface;
621     FIXME("STUB:(%p)\n",This);
622     return E_NOTIMPL;
623 }
624
625 static HRESULT WINAPI TextStoreACPSink_OnStatusChange(ITextStoreACPSink *iface,
626         DWORD dwFlags)
627 {
628     TextStoreACPSink *This = (TextStoreACPSink *)iface;
629     FIXME("STUB:(%p)\n",This);
630     return E_NOTIMPL;
631 }
632
633 static HRESULT WINAPI TextStoreACPSink_OnAttrsChange(ITextStoreACPSink *iface,
634         LONG acpStart, LONG acpEnd, ULONG cAttrs, const TS_ATTRID *paAttrs)
635 {
636     TextStoreACPSink *This = (TextStoreACPSink *)iface;
637     FIXME("STUB:(%p)\n",This);
638     return E_NOTIMPL;
639 }
640
641 static HRESULT WINAPI TextStoreACPSink_OnLockGranted(ITextStoreACPSink *iface,
642         DWORD dwLockFlags)
643 {
644     TextStoreACPSink *This = (TextStoreACPSink *)iface;
645     HRESULT hr;
646
647     TRACE("(%p) %x\n",This, dwLockFlags);
648
649     if (!This->pContext || !This->pContext->currentEditSession)
650     {
651         ERR("OnLockGranted called on a context without a current edit session\n");
652         return E_FAIL;
653     }
654
655     /* TODO:  generate and use an edit cookie */
656     hr = ITfEditSession_DoEditSession(This->pContext->currentEditSession, 0xdeadcafe);
657
658     ITfEditSession_Release(This->pContext->currentEditSession);
659     This->pContext->currentEditSession = NULL;
660
661     return hr;
662 }
663
664 static HRESULT WINAPI TextStoreACPSink_OnStartEditTransaction(ITextStoreACPSink *iface)
665 {
666     TextStoreACPSink *This = (TextStoreACPSink *)iface;
667     FIXME("STUB:(%p)\n",This);
668     return E_NOTIMPL;
669 }
670
671 static HRESULT WINAPI TextStoreACPSink_OnEndEditTransaction(ITextStoreACPSink *iface)
672 {
673     TextStoreACPSink *This = (TextStoreACPSink *)iface;
674     FIXME("STUB:(%p)\n",This);
675     return E_NOTIMPL;
676 }
677
678 static const ITextStoreACPSinkVtbl TextStoreACPSink_TextStoreACPSinkVtbl =
679 {
680     TextStoreACPSink_QueryInterface,
681     TextStoreACPSink_AddRef,
682     TextStoreACPSink_Release,
683
684     TextStoreACPSink_OnTextChange,
685     TextStoreACPSink_OnSelectionChange,
686     TextStoreACPSink_OnLayoutChange,
687     TextStoreACPSink_OnStatusChange,
688     TextStoreACPSink_OnAttrsChange,
689     TextStoreACPSink_OnLockGranted,
690     TextStoreACPSink_OnStartEditTransaction,
691     TextStoreACPSink_OnEndEditTransaction
692 };
693
694 static HRESULT TextStoreACPSink_Constructor(ITextStoreACPSink **ppOut, Context *pContext)
695 {
696     TextStoreACPSink *This;
697
698     This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(TextStoreACPSink));
699     if (This == NULL)
700         return E_OUTOFMEMORY;
701
702     This->TextStoreACPSinkVtbl= &TextStoreACPSink_TextStoreACPSinkVtbl;
703     This->refCount = 1;
704
705     This->pContext = pContext;
706
707     TRACE("returning %p\n", This);
708     *ppOut = (ITextStoreACPSink*)This;
709     return S_OK;
710 }