crypt32: Constify some variables.
[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     /* Aggregation */
72     ITfCompartmentMgr  *CompartmentMgr;
73
74     TfClientId tidOwner;
75     TfEditCookie defaultCookie;
76     TS_STATUS documentStatus;
77
78     ITextStoreACP   *pITextStoreACP;
79     ITfContextOwnerCompositionSink *pITfContextOwnerCompositionSink;
80
81     ITextStoreACPSink *pITextStoreACPSink;
82     ITfEditSession* currentEditSession;
83
84     /* kept as separate lists to reduce unnecessary iterations */
85     struct list     pContextKeyEventSink;
86     struct list     pEditTransactionSink;
87     struct list     pStatusSink;
88     struct list     pTextEditSink;
89     struct list     pTextLayoutSink;
90
91 } Context;
92
93 typedef struct tagEditCookie {
94     DWORD lockType;
95     Context *pOwningContext;
96 } EditCookie;
97
98 typedef struct tagTextStoreACPSink {
99     const ITextStoreACPSinkVtbl *TextStoreACPSinkVtbl;
100     /* const ITextStoreACPServicesVtbl *TextStoreACPServicesVtbl; */
101     LONG refCount;
102
103     Context *pContext;
104 } TextStoreACPSink;
105
106
107 static HRESULT TextStoreACPSink_Constructor(ITextStoreACPSink **ppOut, Context *pContext);
108
109 static inline Context *impl_from_ITfSourceVtbl(ITfSource *iface)
110 {
111     return (Context *)((char *)iface - FIELD_OFFSET(Context,SourceVtbl));
112 }
113
114 static inline Context *impl_from_ITfInsertAtSelectionVtbl(ITfInsertAtSelection*iface)
115 {
116     return (Context *)((char *)iface - FIELD_OFFSET(Context,InsertAtSelectionVtbl));
117 }
118
119 static void free_sink(ContextSink *sink)
120 {
121         IUnknown_Release(sink->interfaces.pIUnknown);
122         HeapFree(GetProcessHeap(),0,sink);
123 }
124
125 static void Context_Destructor(Context *This)
126 {
127     struct list *cursor, *cursor2;
128     EditCookie *cookie;
129     TRACE("destroying %p\n", This);
130
131     if (This->pITextStoreACPSink)
132     {
133         ITextStoreACP_UnadviseSink(This->pITextStoreACP, (IUnknown*)This->pITextStoreACPSink);
134         ITextStoreACPSink_Release(This->pITextStoreACPSink);
135     }
136
137     if (This->pITextStoreACP)
138         ITextStoreACPSink_Release(This->pITextStoreACP);
139
140     if (This->pITfContextOwnerCompositionSink)
141         ITextStoreACPSink_Release(This->pITfContextOwnerCompositionSink);
142
143     if (This->defaultCookie)
144     {
145         cookie = remove_Cookie(This->defaultCookie);
146         HeapFree(GetProcessHeap(),0,cookie);
147         This->defaultCookie = 0;
148     }
149
150     LIST_FOR_EACH_SAFE(cursor, cursor2, &This->pContextKeyEventSink)
151     {
152         ContextSink* sink = LIST_ENTRY(cursor,ContextSink,entry);
153         list_remove(cursor);
154         free_sink(sink);
155     }
156     LIST_FOR_EACH_SAFE(cursor, cursor2, &This->pEditTransactionSink)
157     {
158         ContextSink* sink = LIST_ENTRY(cursor,ContextSink,entry);
159         list_remove(cursor);
160         free_sink(sink);
161     }
162     LIST_FOR_EACH_SAFE(cursor, cursor2, &This->pStatusSink)
163     {
164         ContextSink* sink = LIST_ENTRY(cursor,ContextSink,entry);
165         list_remove(cursor);
166         free_sink(sink);
167     }
168     LIST_FOR_EACH_SAFE(cursor, cursor2, &This->pTextEditSink)
169     {
170         ContextSink* sink = LIST_ENTRY(cursor,ContextSink,entry);
171         list_remove(cursor);
172         free_sink(sink);
173     }
174     LIST_FOR_EACH_SAFE(cursor, cursor2, &This->pTextLayoutSink)
175     {
176         ContextSink* sink = LIST_ENTRY(cursor,ContextSink,entry);
177         list_remove(cursor);
178         free_sink(sink);
179     }
180
181     CompartmentMgr_Destructor(This->CompartmentMgr);
182     HeapFree(GetProcessHeap(),0,This);
183 }
184
185 static HRESULT WINAPI Context_QueryInterface(ITfContext *iface, REFIID iid, LPVOID *ppvOut)
186 {
187     Context *This = (Context *)iface;
188     *ppvOut = NULL;
189
190     if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_ITfContext))
191     {
192         *ppvOut = This;
193     }
194     else if (IsEqualIID(iid, &IID_ITfSource))
195     {
196         *ppvOut = &This->SourceVtbl;
197     }
198     else if (IsEqualIID(iid, &IID_ITfInsertAtSelection))
199     {
200         *ppvOut = &This->InsertAtSelectionVtbl;
201     }
202     else if (IsEqualIID(iid, &IID_ITfCompartmentMgr))
203     {
204         *ppvOut = This->CompartmentMgr;
205     }
206
207     if (*ppvOut)
208     {
209         IUnknown_AddRef(iface);
210         return S_OK;
211     }
212
213     WARN("unsupported interface: %s\n", debugstr_guid(iid));
214     return E_NOINTERFACE;
215 }
216
217 static ULONG WINAPI Context_AddRef(ITfContext *iface)
218 {
219     Context *This = (Context *)iface;
220     return InterlockedIncrement(&This->refCount);
221 }
222
223 static ULONG WINAPI Context_Release(ITfContext *iface)
224 {
225     Context *This = (Context *)iface;
226     ULONG ret;
227
228     ret = InterlockedDecrement(&This->refCount);
229     if (ret == 0)
230         Context_Destructor(This);
231     return ret;
232 }
233
234 /*****************************************************
235  * ITfContext functions
236  *****************************************************/
237 static HRESULT WINAPI Context_RequestEditSession (ITfContext *iface,
238         TfClientId tid, ITfEditSession *pes, DWORD dwFlags,
239         HRESULT *phrSession)
240 {
241     HRESULT hr;
242     Context *This = (Context *)iface;
243     DWORD  dwLockFlags = 0x0;
244
245     TRACE("(%p) %i %p %x %p\n",This, tid, pes, dwFlags, phrSession);
246
247     if (!(dwFlags & TF_ES_READ) && !(dwFlags & TF_ES_READWRITE))
248     {
249         *phrSession = E_FAIL;
250         return E_INVALIDARG;
251     }
252
253     if (!This->pITextStoreACP)
254     {
255         FIXME("No ITextStoreACP avaliable\n");
256         *phrSession = E_FAIL;
257         return E_FAIL;
258     }
259
260     if (!(dwFlags & TF_ES_ASYNC))
261         dwLockFlags |= TS_LF_SYNC;
262
263     if ((dwFlags & TF_ES_READWRITE) == TF_ES_READWRITE)
264         dwLockFlags |= TS_LF_READWRITE;
265     else if (dwFlags & TF_ES_READ)
266         dwLockFlags |= TS_LF_READ;
267
268     if (!This->documentStatus.dwDynamicFlags)
269         ITextStoreACP_GetStatus(This->pITextStoreACP, &This->documentStatus);
270
271     if (((dwFlags & TF_ES_READWRITE) == TF_ES_READWRITE) && (This->documentStatus.dwDynamicFlags & TS_SD_READONLY))
272     {
273         *phrSession = TS_E_READONLY;
274         return S_OK;
275     }
276
277     if (FAILED (ITfEditSession_QueryInterface(pes, &IID_ITfEditSession, (LPVOID*)&This->currentEditSession)))
278     {
279         *phrSession = E_FAIL;
280         return E_INVALIDARG;
281     }
282
283     hr = ITextStoreACP_RequestLock(This->pITextStoreACP, dwLockFlags, phrSession);
284
285     return hr;
286 }
287
288 static HRESULT WINAPI Context_InWriteSession (ITfContext *iface,
289          TfClientId tid,
290          BOOL *pfWriteSession)
291 {
292     Context *This = (Context *)iface;
293     FIXME("STUB:(%p)\n",This);
294     return E_NOTIMPL;
295 }
296
297 static HRESULT WINAPI Context_GetSelection (ITfContext *iface,
298         TfEditCookie ec, ULONG ulIndex, ULONG ulCount,
299         TF_SELECTION *pSelection, ULONG *pcFetched)
300 {
301     Context *This = (Context *)iface;
302     EditCookie *cookie;
303     ULONG count, i;
304     ULONG totalFetched = 0;
305     HRESULT hr = S_OK;
306
307     if (!pSelection || !pcFetched)
308         return E_INVALIDARG;
309
310     *pcFetched = 0;
311
312     if (!This->connected)
313         return TF_E_DISCONNECTED;
314
315     if (get_Cookie_magic(ec)!=COOKIE_MAGIC_EDITCOOKIE)
316         return TF_E_NOLOCK;
317
318     if (!This->pITextStoreACP)
319     {
320         FIXME("Context does not have a ITextStoreACP\n");
321         return E_NOTIMPL;
322     }
323
324     cookie = get_Cookie_data(ec);
325
326     if (ulIndex == TF_DEFAULT_SELECTION)
327         count = 1;
328     else
329         count = ulCount;
330
331     for (i = 0; i < count; i++)
332     {
333         DWORD fetched;
334         TS_SELECTION_ACP acps;
335
336         hr = ITextStoreACP_GetSelection(This->pITextStoreACP, ulIndex + i,
337                 1, &acps, &fetched);
338
339         if (hr == TS_E_NOLOCK)
340             return TF_E_NOLOCK;
341         else if (SUCCEEDED(hr))
342         {
343             pSelection[totalFetched].style.ase = acps.style.ase;
344             pSelection[totalFetched].style.fInterimChar = acps.style.fInterimChar;
345             Range_Constructor(iface, This->pITextStoreACP, cookie->lockType, acps.acpStart, acps.acpEnd, &pSelection[totalFetched].range);
346             totalFetched ++;
347         }
348         else
349             break;
350     }
351
352     *pcFetched = totalFetched;
353
354     return hr;
355 }
356
357 static HRESULT WINAPI Context_SetSelection (ITfContext *iface,
358         TfEditCookie ec, ULONG ulCount, const TF_SELECTION *pSelection)
359 {
360     TS_SELECTION_ACP *acp;
361     Context *This = (Context *)iface;
362     INT i;
363     HRESULT hr;
364
365     TRACE("(%p) %i %i %p\n",This,ec,ulCount,pSelection);
366
367     if (!This->pITextStoreACP)
368     {
369         FIXME("Context does not have a ITextStoreACP\n");
370         return E_NOTIMPL;
371     }
372
373     if (get_Cookie_magic(ec)!=COOKIE_MAGIC_EDITCOOKIE)
374         return TF_E_NOLOCK;
375
376     acp = HeapAlloc(GetProcessHeap(), 0, sizeof(TS_SELECTION_ACP) * ulCount);
377     if (!acp)
378         return E_OUTOFMEMORY;
379
380     for (i = 0; i < ulCount; i++)
381         if (FAILED(TF_SELECTION_to_TS_SELECTION_ACP(&pSelection[i], &acp[i])))
382         {
383             TRACE("Selection Conversion Failed\n");
384             HeapFree(GetProcessHeap(), 0 , acp);
385             return E_FAIL;
386         }
387
388     hr = ITextStoreACP_SetSelection(This->pITextStoreACP, ulCount, acp);
389
390     HeapFree(GetProcessHeap(), 0, acp);
391
392     return hr;
393 }
394
395 static HRESULT WINAPI Context_GetStart (ITfContext *iface,
396         TfEditCookie ec, ITfRange **ppStart)
397 {
398     Context *This = (Context *)iface;
399     EditCookie *cookie;
400     TRACE("(%p) %i %p\n",This,ec,ppStart);
401
402     if (!ppStart)
403         return E_INVALIDARG;
404
405     *ppStart = NULL;
406
407     if (!This->connected)
408         return TF_E_DISCONNECTED;
409
410     if (get_Cookie_magic(ec)!=COOKIE_MAGIC_EDITCOOKIE)
411         return TF_E_NOLOCK;
412
413     cookie = get_Cookie_data(ec);
414     return Range_Constructor(iface, This->pITextStoreACP, cookie->lockType, 0, 0, ppStart);
415 }
416
417 static HRESULT WINAPI Context_GetEnd (ITfContext *iface,
418         TfEditCookie ec, ITfRange **ppEnd)
419 {
420     Context *This = (Context *)iface;
421     EditCookie *cookie;
422     LONG end;
423     TRACE("(%p) %i %p\n",This,ec,ppEnd);
424
425     if (!ppEnd)
426         return E_INVALIDARG;
427
428     *ppEnd = NULL;
429
430     if (!This->connected)
431         return TF_E_DISCONNECTED;
432
433     if (get_Cookie_magic(ec)!=COOKIE_MAGIC_EDITCOOKIE)
434         return TF_E_NOLOCK;
435
436     if (!This->pITextStoreACP)
437     {
438         FIXME("Context does not have a ITextStoreACP\n");
439         return E_NOTIMPL;
440     }
441
442     cookie = get_Cookie_data(ec);
443     ITextStoreACP_GetEndACP(This->pITextStoreACP,&end);
444
445     return Range_Constructor(iface, This->pITextStoreACP, cookie->lockType, end, end, ppEnd);
446 }
447
448 static HRESULT WINAPI Context_GetActiveView (ITfContext *iface,
449   ITfContextView **ppView)
450 {
451     Context *This = (Context *)iface;
452     FIXME("STUB:(%p)\n",This);
453     return E_NOTIMPL;
454 }
455
456 static HRESULT WINAPI Context_EnumViews (ITfContext *iface,
457         IEnumTfContextViews **ppEnum)
458 {
459     Context *This = (Context *)iface;
460     FIXME("STUB:(%p)\n",This);
461     return E_NOTIMPL;
462 }
463
464 static HRESULT WINAPI Context_GetStatus (ITfContext *iface,
465         TF_STATUS *pdcs)
466 {
467     Context *This = (Context *)iface;
468     FIXME("STUB:(%p)\n",This);
469     return E_NOTIMPL;
470 }
471
472 static HRESULT WINAPI Context_GetProperty (ITfContext *iface,
473         REFGUID guidProp, ITfProperty **ppProp)
474 {
475     Context *This = (Context *)iface;
476     FIXME("STUB:(%p)\n",This);
477     return E_NOTIMPL;
478 }
479
480 static HRESULT WINAPI Context_GetAppProperty (ITfContext *iface,
481         REFGUID guidProp, ITfReadOnlyProperty **ppProp)
482 {
483     Context *This = (Context *)iface;
484     FIXME("STUB:(%p)\n",This);
485     return E_NOTIMPL;
486 }
487
488 static HRESULT WINAPI Context_TrackProperties (ITfContext *iface,
489         const GUID **prgProp, ULONG cProp, const GUID **prgAppProp,
490         ULONG cAppProp, ITfReadOnlyProperty **ppProperty)
491 {
492     Context *This = (Context *)iface;
493     FIXME("STUB:(%p)\n",This);
494     return E_NOTIMPL;
495 }
496
497 static HRESULT WINAPI Context_EnumProperties (ITfContext *iface,
498         IEnumTfProperties **ppEnum)
499 {
500     Context *This = (Context *)iface;
501     FIXME("STUB:(%p)\n",This);
502     return E_NOTIMPL;
503 }
504
505 static HRESULT WINAPI Context_GetDocumentMgr (ITfContext *iface,
506         ITfDocumentMgr **ppDm)
507 {
508     Context *This = (Context *)iface;
509     FIXME("STUB:(%p)\n",This);
510     return E_NOTIMPL;
511 }
512
513 static HRESULT WINAPI Context_CreateRangeBackup (ITfContext *iface,
514         TfEditCookie ec, ITfRange *pRange, ITfRangeBackup **ppBackup)
515 {
516     Context *This = (Context *)iface;
517     FIXME("STUB:(%p)\n",This);
518     return E_NOTIMPL;
519 }
520
521 static const ITfContextVtbl Context_ContextVtbl =
522 {
523     Context_QueryInterface,
524     Context_AddRef,
525     Context_Release,
526
527     Context_RequestEditSession,
528     Context_InWriteSession,
529     Context_GetSelection,
530     Context_SetSelection,
531     Context_GetStart,
532     Context_GetEnd,
533     Context_GetActiveView,
534     Context_EnumViews,
535     Context_GetStatus,
536     Context_GetProperty,
537     Context_GetAppProperty,
538     Context_TrackProperties,
539     Context_EnumProperties,
540     Context_GetDocumentMgr,
541     Context_CreateRangeBackup
542 };
543
544 static HRESULT WINAPI Source_QueryInterface(ITfSource *iface, REFIID iid, LPVOID *ppvOut)
545 {
546     Context *This = impl_from_ITfSourceVtbl(iface);
547     return Context_QueryInterface((ITfContext *)This, iid, *ppvOut);
548 }
549
550 static ULONG WINAPI Source_AddRef(ITfSource *iface)
551 {
552     Context *This = impl_from_ITfSourceVtbl(iface);
553     return Context_AddRef((ITfContext *)This);
554 }
555
556 static ULONG WINAPI Source_Release(ITfSource *iface)
557 {
558     Context *This = impl_from_ITfSourceVtbl(iface);
559     return Context_Release((ITfContext *)This);
560 }
561
562 /*****************************************************
563  * ITfSource functions
564  *****************************************************/
565 static WINAPI HRESULT ContextSource_AdviseSink(ITfSource *iface,
566         REFIID riid, IUnknown *punk, DWORD *pdwCookie)
567 {
568     ContextSink *es;
569     Context *This = impl_from_ITfSourceVtbl(iface);
570     TRACE("(%p) %s %p %p\n",This,debugstr_guid(riid),punk,pdwCookie);
571
572     if (!riid || !punk || !pdwCookie)
573         return E_INVALIDARG;
574
575     if (IsEqualIID(riid, &IID_ITfTextEditSink))
576     {
577         es = HeapAlloc(GetProcessHeap(),0,sizeof(ContextSink));
578         if (!es)
579             return E_OUTOFMEMORY;
580         if (FAILED(IUnknown_QueryInterface(punk, riid, (LPVOID *)&es->interfaces.pITfTextEditSink)))
581         {
582             HeapFree(GetProcessHeap(),0,es);
583             return CONNECT_E_CANNOTCONNECT;
584         }
585         list_add_head(&This->pTextEditSink ,&es->entry);
586         *pdwCookie = generate_Cookie(COOKIE_MAGIC_CONTEXTSINK, es);
587     }
588     else
589     {
590         FIXME("(%p) Unhandled Sink: %s\n",This,debugstr_guid(riid));
591         return E_NOTIMPL;
592     }
593
594     TRACE("cookie %x\n",*pdwCookie);
595     return S_OK;
596 }
597
598 static WINAPI HRESULT ContextSource_UnadviseSink(ITfSource *iface, DWORD pdwCookie)
599 {
600     ContextSink *sink;
601     Context *This = impl_from_ITfSourceVtbl(iface);
602
603     TRACE("(%p) %x\n",This,pdwCookie);
604
605     if (get_Cookie_magic(pdwCookie)!=COOKIE_MAGIC_CONTEXTSINK)
606         return E_INVALIDARG;
607
608     sink = (ContextSink*)remove_Cookie(pdwCookie);
609     if (!sink)
610         return CONNECT_E_NOCONNECTION;
611
612     list_remove(&sink->entry);
613     free_sink(sink);
614
615     return S_OK;
616 }
617
618 static const ITfSourceVtbl Context_SourceVtbl =
619 {
620     Source_QueryInterface,
621     Source_AddRef,
622     Source_Release,
623
624     ContextSource_AdviseSink,
625     ContextSource_UnadviseSink,
626 };
627
628 /*****************************************************
629  * ITfInsertAtSelection functions
630  *****************************************************/
631 static HRESULT WINAPI InsertAtSelection_QueryInterface(ITfInsertAtSelection *iface, REFIID iid, LPVOID *ppvOut)
632 {
633     Context *This = impl_from_ITfInsertAtSelectionVtbl(iface);
634     return Context_QueryInterface((ITfContext *)This, iid, *ppvOut);
635 }
636
637 static ULONG WINAPI InsertAtSelection_AddRef(ITfInsertAtSelection *iface)
638 {
639     Context *This = impl_from_ITfInsertAtSelectionVtbl(iface);
640     return Context_AddRef((ITfContext *)This);
641 }
642
643 static ULONG WINAPI InsertAtSelection_Release(ITfInsertAtSelection *iface)
644 {
645     Context *This = impl_from_ITfInsertAtSelectionVtbl(iface);
646     return Context_Release((ITfContext *)This);
647 }
648
649 static WINAPI HRESULT InsertAtSelection_InsertTextAtSelection(
650         ITfInsertAtSelection *iface, TfEditCookie ec, DWORD dwFlags,
651         const WCHAR *pchText, LONG cch, ITfRange **ppRange)
652 {
653     Context *This = impl_from_ITfInsertAtSelectionVtbl(iface);
654     EditCookie *cookie;
655     LONG acpStart, acpEnd;
656     TS_TEXTCHANGE change;
657     HRESULT hr;
658
659     TRACE("(%p) %i %x %s %p\n",This, ec, dwFlags, debugstr_wn(pchText,cch), ppRange);
660
661     if (!This->connected)
662         return TF_E_DISCONNECTED;
663
664     if (get_Cookie_magic(ec)!=COOKIE_MAGIC_EDITCOOKIE)
665         return TF_E_NOLOCK;
666
667     cookie = get_Cookie_data(ec);
668
669     if ((cookie->lockType & TS_LF_READWRITE) != TS_LF_READWRITE )
670         return TS_E_READONLY;
671
672     if (!This->pITextStoreACP)
673     {
674         FIXME("Context does not have a ITextStoreACP\n");
675         return E_NOTIMPL;
676     }
677
678     hr = ITextStoreACP_InsertTextAtSelection(This->pITextStoreACP, dwFlags, pchText, cch, &acpStart, &acpEnd, &change);
679     if (SUCCEEDED(hr))
680         Range_Constructor((ITfContext*)This, This->pITextStoreACP, cookie->lockType, change.acpStart, change.acpNewEnd, ppRange);
681
682     return hr;
683 }
684
685 static WINAPI HRESULT InsertAtSelection_InsertEmbeddedAtSelection(
686         ITfInsertAtSelection *iface, TfEditCookie ec, DWORD dwFlags,
687         IDataObject *pDataObject, ITfRange **ppRange)
688 {
689     Context *This = impl_from_ITfInsertAtSelectionVtbl(iface);
690     FIXME("STUB:(%p)\n",This);
691     return E_NOTIMPL;
692 }
693
694 static const ITfInsertAtSelectionVtbl Context_InsertAtSelectionVtbl =
695 {
696     InsertAtSelection_QueryInterface,
697     InsertAtSelection_AddRef,
698     InsertAtSelection_Release,
699
700     InsertAtSelection_InsertTextAtSelection,
701     InsertAtSelection_InsertEmbeddedAtSelection,
702 };
703
704 HRESULT Context_Constructor(TfClientId tidOwner, IUnknown *punk, ITfContext **ppOut, TfEditCookie *pecTextStore)
705 {
706     Context *This;
707     EditCookie *cookie;
708
709     This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(Context));
710     if (This == NULL)
711         return E_OUTOFMEMORY;
712
713     cookie = HeapAlloc(GetProcessHeap(),0,sizeof(EditCookie));
714     if (cookie == NULL)
715     {
716         HeapFree(GetProcessHeap(),0,This);
717         return E_OUTOFMEMORY;
718     }
719
720     TRACE("(%p) %x %p %p %p\n",This, tidOwner, punk, ppOut, pecTextStore);
721
722     This->ContextVtbl= &Context_ContextVtbl;
723     This->SourceVtbl = &Context_SourceVtbl;
724     This->InsertAtSelectionVtbl = &Context_InsertAtSelectionVtbl;
725     This->refCount = 1;
726     This->tidOwner = tidOwner;
727     This->connected = FALSE;
728
729     CompartmentMgr_Constructor((IUnknown*)This, &IID_IUnknown, (IUnknown**)&This->CompartmentMgr);
730
731     cookie->lockType = TF_ES_READ;
732     cookie->pOwningContext = This;
733
734     if (punk)
735     {
736         IUnknown_QueryInterface(punk, &IID_ITextStoreACP,
737                           (LPVOID*)&This->pITextStoreACP);
738
739         IUnknown_QueryInterface(punk, &IID_ITfContextOwnerCompositionSink,
740                                 (LPVOID*)&This->pITfContextOwnerCompositionSink);
741
742         if (!This->pITextStoreACP && !This->pITfContextOwnerCompositionSink)
743             FIXME("Unhandled pUnk\n");
744     }
745
746     This->defaultCookie = generate_Cookie(COOKIE_MAGIC_EDITCOOKIE,cookie);
747     *pecTextStore = This->defaultCookie;
748
749     list_init(&This->pContextKeyEventSink);
750     list_init(&This->pEditTransactionSink);
751     list_init(&This->pStatusSink);
752     list_init(&This->pTextEditSink);
753     list_init(&This->pTextLayoutSink);
754
755     *ppOut = (ITfContext*)This;
756     TRACE("returning %p\n", This);
757
758     return S_OK;
759 }
760
761 HRESULT Context_Initialize(ITfContext *iface)
762 {
763     Context *This = (Context *)iface;
764
765     if (This->pITextStoreACP)
766     {
767         if (SUCCEEDED(TextStoreACPSink_Constructor(&This->pITextStoreACPSink, This)))
768             ITextStoreACP_AdviseSink(This->pITextStoreACP, &IID_ITextStoreACPSink,
769                             (IUnknown*)This->pITextStoreACPSink, TS_AS_ALL_SINKS);
770     }
771     This->connected = TRUE;
772     return S_OK;
773 }
774
775 HRESULT Context_Uninitialize(ITfContext *iface)
776 {
777     Context *This = (Context *)iface;
778
779     if (This->pITextStoreACPSink)
780     {
781         ITextStoreACP_UnadviseSink(This->pITextStoreACP, (IUnknown*)This->pITextStoreACPSink);
782         if (ITextStoreACPSink_Release(This->pITextStoreACPSink) == 0)
783             This->pITextStoreACPSink = NULL;
784     }
785     This->connected = FALSE;
786     return S_OK;
787 }
788
789 /**************************************************************************
790  *  ITextStoreACPSink
791  **************************************************************************/
792
793 static void TextStoreACPSink_Destructor(TextStoreACPSink *This)
794 {
795     TRACE("destroying %p\n", This);
796     HeapFree(GetProcessHeap(),0,This);
797 }
798
799 static HRESULT WINAPI TextStoreACPSink_QueryInterface(ITextStoreACPSink *iface, REFIID iid, LPVOID *ppvOut)
800 {
801     TextStoreACPSink *This = (TextStoreACPSink *)iface;
802     *ppvOut = NULL;
803
804     if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_ITextStoreACPSink))
805     {
806         *ppvOut = This;
807     }
808
809     if (*ppvOut)
810     {
811         IUnknown_AddRef(iface);
812         return S_OK;
813     }
814
815     WARN("unsupported interface: %s\n", debugstr_guid(iid));
816     return E_NOINTERFACE;
817 }
818
819 static ULONG WINAPI TextStoreACPSink_AddRef(ITextStoreACPSink *iface)
820 {
821     TextStoreACPSink *This = (TextStoreACPSink *)iface;
822     return InterlockedIncrement(&This->refCount);
823 }
824
825 static ULONG WINAPI TextStoreACPSink_Release(ITextStoreACPSink *iface)
826 {
827     TextStoreACPSink *This = (TextStoreACPSink *)iface;
828     ULONG ret;
829
830     ret = InterlockedDecrement(&This->refCount);
831     if (ret == 0)
832         TextStoreACPSink_Destructor(This);
833     return ret;
834 }
835
836 /*****************************************************
837  * ITextStoreACPSink functions
838  *****************************************************/
839
840 static HRESULT WINAPI TextStoreACPSink_OnTextChange(ITextStoreACPSink *iface,
841         DWORD dwFlags, const TS_TEXTCHANGE *pChange)
842 {
843     TextStoreACPSink *This = (TextStoreACPSink *)iface;
844     FIXME("STUB:(%p)\n",This);
845     return E_NOTIMPL;
846 }
847
848 static HRESULT WINAPI TextStoreACPSink_OnSelectionChange(ITextStoreACPSink *iface)
849 {
850     TextStoreACPSink *This = (TextStoreACPSink *)iface;
851     FIXME("STUB:(%p)\n",This);
852     return E_NOTIMPL;
853 }
854
855 static HRESULT WINAPI TextStoreACPSink_OnLayoutChange(ITextStoreACPSink *iface,
856     TsLayoutCode lcode, TsViewCookie vcView)
857 {
858     TextStoreACPSink *This = (TextStoreACPSink *)iface;
859     FIXME("STUB:(%p)\n",This);
860     return E_NOTIMPL;
861 }
862
863 static HRESULT WINAPI TextStoreACPSink_OnStatusChange(ITextStoreACPSink *iface,
864         DWORD dwFlags)
865 {
866     TextStoreACPSink *This = (TextStoreACPSink *)iface;
867     HRESULT hr, hrSession;
868
869     TRACE("(%p) %x\n",This, dwFlags);
870
871     if (!This->pContext)
872     {
873         ERR("No context?\n");
874         return E_FAIL;
875     }
876
877     if (!This->pContext->pITextStoreACP)
878     {
879         FIXME("Context does not have a ITextStoreACP\n");
880         return E_NOTIMPL;
881     }
882
883     hr = ITextStoreACP_RequestLock(This->pContext->pITextStoreACP, TS_LF_READ, &hrSession);
884
885     if(SUCCEEDED(hr) && SUCCEEDED(hrSession))
886         This->pContext->documentStatus.dwDynamicFlags = dwFlags;
887
888     return S_OK;
889 }
890
891 static HRESULT WINAPI TextStoreACPSink_OnAttrsChange(ITextStoreACPSink *iface,
892         LONG acpStart, LONG acpEnd, ULONG cAttrs, const TS_ATTRID *paAttrs)
893 {
894     TextStoreACPSink *This = (TextStoreACPSink *)iface;
895     FIXME("STUB:(%p)\n",This);
896     return E_NOTIMPL;
897 }
898
899 static HRESULT WINAPI TextStoreACPSink_OnLockGranted(ITextStoreACPSink *iface,
900         DWORD dwLockFlags)
901 {
902     TextStoreACPSink *This = (TextStoreACPSink *)iface;
903     HRESULT hr;
904     EditCookie *cookie;
905     TfEditCookie ec;
906
907     TRACE("(%p) %x\n",This, dwLockFlags);
908
909     if (!This->pContext)
910     {
911         ERR("OnLockGranted called without a context\n");
912         return E_FAIL;
913     }
914
915     if (!This->pContext->currentEditSession)
916     {
917         FIXME("OnLockGranted called for something other than an EditSession\n");
918         return S_OK;
919     }
920
921     cookie = HeapAlloc(GetProcessHeap(),0,sizeof(EditCookie));
922     if (!cookie)
923         return E_OUTOFMEMORY;
924
925     cookie->lockType = dwLockFlags;
926     cookie->pOwningContext = This->pContext;
927     ec = generate_Cookie(COOKIE_MAGIC_EDITCOOKIE, cookie);
928
929     hr = ITfEditSession_DoEditSession(This->pContext->currentEditSession, ec);
930
931     ITfEditSession_Release(This->pContext->currentEditSession);
932     This->pContext->currentEditSession = NULL;
933
934     /* Edit Cookie is only valid during the edit session */
935     cookie = remove_Cookie(ec);
936     HeapFree(GetProcessHeap(),0,cookie);
937
938     return hr;
939 }
940
941 static HRESULT WINAPI TextStoreACPSink_OnStartEditTransaction(ITextStoreACPSink *iface)
942 {
943     TextStoreACPSink *This = (TextStoreACPSink *)iface;
944     FIXME("STUB:(%p)\n",This);
945     return E_NOTIMPL;
946 }
947
948 static HRESULT WINAPI TextStoreACPSink_OnEndEditTransaction(ITextStoreACPSink *iface)
949 {
950     TextStoreACPSink *This = (TextStoreACPSink *)iface;
951     FIXME("STUB:(%p)\n",This);
952     return E_NOTIMPL;
953 }
954
955 static const ITextStoreACPSinkVtbl TextStoreACPSink_TextStoreACPSinkVtbl =
956 {
957     TextStoreACPSink_QueryInterface,
958     TextStoreACPSink_AddRef,
959     TextStoreACPSink_Release,
960
961     TextStoreACPSink_OnTextChange,
962     TextStoreACPSink_OnSelectionChange,
963     TextStoreACPSink_OnLayoutChange,
964     TextStoreACPSink_OnStatusChange,
965     TextStoreACPSink_OnAttrsChange,
966     TextStoreACPSink_OnLockGranted,
967     TextStoreACPSink_OnStartEditTransaction,
968     TextStoreACPSink_OnEndEditTransaction
969 };
970
971 static HRESULT TextStoreACPSink_Constructor(ITextStoreACPSink **ppOut, Context *pContext)
972 {
973     TextStoreACPSink *This;
974
975     This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(TextStoreACPSink));
976     if (This == NULL)
977         return E_OUTOFMEMORY;
978
979     This->TextStoreACPSinkVtbl= &TextStoreACPSink_TextStoreACPSinkVtbl;
980     This->refCount = 1;
981
982     This->pContext = pContext;
983
984     TRACE("returning %p\n", This);
985     *ppOut = (ITextStoreACPSink*)This;
986     return S_OK;
987 }