OSDN Git Service

ドキュメントをすべてクリアーした後にIMEで入力しようとすると例外が発生するバグを修正した
[fooeditengine/FooEditEngine.git] / Common / DotNetTextStore / TextStoreBase.cs
1 // TSF のデバッグ表示を行うかどうか?\r
2 //#define TSF_DEBUG_OUTPUT\r
3 using System;\r
4 using System.Collections.Generic;\r
5 using System.Linq;\r
6 using System.Text;\r
7 using System.Diagnostics;\r
8 using System.Reflection;\r
9 using System.Runtime.CompilerServices;\r
10 using System.Runtime.InteropServices;\r
11 using System.Globalization;\r
12 \r
13 using DotNetTextStore.UnmanagedAPI.TSF;\r
14 using DotNetTextStore.UnmanagedAPI.TSF.TextStore;\r
15 using DotNetTextStore.UnmanagedAPI.WinDef;\r
16 using DotNetTextStore.UnmanagedAPI.WinError;\r
17 \r
18 namespace DotNetTextStore\r
19 {\r
20 #if TSF_DEBUG_OUTPUT\r
21     /// <summary>コールスタックの階層にあわせてインデントしてデバッグ表示するクラス。</summary>\r
22     public class DebugOut : IDisposable\r
23     {\r
24         public DebugOut(string i_string, params object[] i_params)\r
25         {\r
26             _text = string.Format(i_string, i_params);\r
27 \r
28             s_callCount++;\r
29             Debug.WriteLine("");\r
30             Debug.WriteLine(string.Format("{0, 4} : ↓↓↓ ", s_callCount) + _text);\r
31         }\r
32 \r
33         public void Dispose()\r
34         {\r
35             s_callCount++;\r
36             Debug.WriteLine(string.Format("{0, 4} : ↑↑↑ ", s_callCount) + _text);\r
37         }\r
38 \r
39         public static string GetCaller([CallerMemberName] string caller="")\r
40         {\r
41             return caller;\r
42         }\r
43 \r
44         string      _text;\r
45         static int  s_callCount = 0;\r
46     }\r
47 #endif\r
48 \r
49     //=============================================================================================\r
50 \r
51 \r
52     public struct TextDisplayAttribute\r
53     {\r
54         public int startIndex;\r
55         public int endIndex;\r
56         public TF_DISPLAYATTRIBUTE attribute;\r
57     }\r
58 \r
59     //========================================================================================\r
60 \r
61 \r
62     /// <summary>Dispose() で TextStore のロック解除を行うクラス。</summary>\r
63     public class Unlocker : IDisposable\r
64     {\r
65         /// <summary>コンストラクタ</summary>\r
66         public Unlocker(TextStoreBase io_textStore)\r
67         {\r
68             _textStore = io_textStore;\r
69         }\r
70         /// <summary>ロックが成功したかどうか調べる。</summary>\r
71         public bool IsLocked\r
72         {\r
73             get { return _textStore != null; }\r
74         }\r
75         /// <summary>アンロックを行う。</summary>\r
76         void IDisposable.Dispose()\r
77         {\r
78             if (_textStore != null)\r
79             {\r
80                 _textStore.UnlockDocument();\r
81                 _textStore = null;\r
82             }\r
83         }\r
84 \r
85         /// <summary>アンロックを行うテキストストア</summary>\r
86         TextStoreBase _textStore;\r
87     }\r
88 \r
89     public abstract class TextStoreBase\r
90     {\r
91         public delegate bool IsReadOnlyHandler();\r
92         public event IsReadOnlyHandler IsReadOnly;\r
93 \r
94         public delegate bool IsLoadingHandler();\r
95         public event IsLoadingHandler IsLoading;\r
96 \r
97         public delegate int GetStringLengthHandler();\r
98         public event GetStringLengthHandler GetStringLength;\r
99 \r
100         public delegate void GetSelectionIndexHandler(out int o_start, out int o_end);\r
101         public event GetSelectionIndexHandler GetSelectionIndex;\r
102 \r
103         public delegate void SetSelectionIndexHandler(int i_start, int i_end);\r
104         public event SetSelectionIndexHandler SetSelectionIndex;\r
105 \r
106         public delegate string GetStringHandler(int start, int length);\r
107         public event GetStringHandler GetString;\r
108 \r
109         public delegate void InsertAtSelectionHandler(string i_value);\r
110         public event InsertAtSelectionHandler InsertAtSelection;\r
111 \r
112         public delegate void GetScreenExtentHandler(\r
113             out POINT o_pointTopLeft,\r
114             out POINT o_pointBottomRight\r
115         );\r
116         public event GetScreenExtentHandler GetScreenExtent;\r
117 \r
118         public delegate void GetStringExtentHandler(\r
119             int i_startIndex,\r
120             int i_endIndex,\r
121             out POINT o_pointTopLeft,\r
122             out POINT o_pointBottomRight\r
123         );\r
124         public event GetStringExtentHandler GetStringExtent;\r
125 \r
126         public delegate bool CompositionStartedHandler();\r
127         public event CompositionStartedHandler CompositionStarted;\r
128 \r
129         public delegate void CompostionUpdateHandler(int start, int end);\r
130         public event CompostionUpdateHandler CompositionUpdated;\r
131 \r
132         public delegate void CompositionEndedHandler();\r
133         public event CompositionEndedHandler CompositionEnded;\r
134 \r
135         #region "生成と破棄"\r
136         public TextStoreBase()\r
137         {\r
138 #if TSF_DEBUG_OUTPUT\r
139             using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )\r
140 #endif\r
141             {\r
142                 try\r
143                 {\r
144                     // スレッドマネージャ-の生成\r
145                     CreateThreadMgr();\r
146                     // カテゴリマネージャーの生成\r
147                     CreateCategoryMgr();\r
148                     // 表示属性マネージャーの生成\r
149                     CreateDisplayAttributeMgr();\r
150 \r
151                     // ドキュメントマネージャーの生成\r
152                     _threadMgr.CreateDocumentMgr(out _documentMgr);\r
153 \r
154                     // スレッドマネージャのアクティブ化\r
155                     int clientId = 0;\r
156                     _threadMgr.Activate(out clientId);\r
157 \r
158                     // コンテキストの生成\r
159                     _documentMgr.CreateContext(clientId, 0, this, out _context, out _editCookie);\r
160 \r
161                     // コンテキストの push\r
162                     _documentMgr.Push(_context);\r
163 \r
164                     // ファンクションプロバイダーを取得する。\r
165                     Guid guid = TfDeclarations.GUID_SYSTEM_FUNCTIONPROVIDER;\r
166                     _threadMgr.GetFunctionProvider(ref guid, out _functionProvider);\r
167 \r
168                     // ITfReconversion オブジェクトを取得する。\r
169                     var guidNull = new Guid();\r
170                     var guidReconversion = new Guid("4cea93c0-0a58-11d3-8df0-00105a2799b5");    //ITfFnReconversionの定義から\r
171                     object reconversion = null;\r
172                     _functionProvider.GetFunction(\r
173                         ref guidNull,\r
174                         ref guidReconversion,\r
175                         out reconversion\r
176                     );\r
177                     _reconversion = reconversion as ITfFnReconversion;\r
178 \r
179                     // MODEBIAS の初期化\r
180                     uint guidAtom = 0;\r
181                     Guid guidModebiasNone = TfDeclarations.GUID_MODEBIAS_NONE;\r
182                     _categoryMgr.RegisterGUID(ref guidModebiasNone, out guidAtom);\r
183                     _attributeInfo[0].attrID = TfDeclarations.GUID_PROP_MODEBIAS;\r
184                     _attributeInfo[0].flags = AttributeInfoFlags.None;\r
185                     _attributeInfo[0].currentValue.vt = (short)VarEnum.VT_EMPTY;\r
186                     _attributeInfo[0].defaultValue.vt = (short)VarEnum.VT_I4;\r
187                     _attributeInfo[0].defaultValue.data1 = (IntPtr)guidAtom;\r
188                 }\r
189                 catch (Exception exception)\r
190                 {\r
191                     Debug.WriteLine(exception.Message);\r
192                     Dispose(false);\r
193                 }\r
194             }\r
195         }\r
196 \r
197         /// <summary>\r
198         /// オブジェクトの破棄を行う。このメソッドは必ず呼び出す必要があります\r
199         /// </summary>\r
200         /// <param name="flag"></param>\r
201         protected void Dispose(bool flag)\r
202         {\r
203             if (flag)\r
204                 return;\r
205 #if TSF_DEBUG_OUTPUT\r
206             using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )\r
207 #endif\r
208             {\r
209                 ReleaseComObject("_reconversion", ref _reconversion);\r
210                 ReleaseComObject("_functionProvider", ref _functionProvider);\r
211                 ReleaseComObject("_context", ref _context);\r
212                 DestroyDocumentMgr();\r
213                 DestroyDisplayAttributeMgr();\r
214                 DestroyCategoryMgr();\r
215                 DestroyThreadMgr();\r
216 \r
217                 GC.SuppressFinalize(this);\r
218             }\r
219         }\r
220 \r
221         /// <summary>\r
222         /// スレッドマネージャの生成。このメソッドの実装は必須です\r
223         /// </summary>\r
224         /// \r
225         /// <exception cref="COMException">\r
226         /// スレッドマネージャーの生成に失敗した場合。\r
227         /// </exception>\r
228         protected virtual void CreateThreadMgr()\r
229         {\r
230             throw new NotImplementedException();\r
231         }\r
232 \r
233         /// <summary>\r
234         /// スレッドマネージャーの解放。\r
235         /// </summary>\r
236         void DestroyThreadMgr()\r
237         {\r
238             if (_threadMgr != null)\r
239             {\r
240                 try { _threadMgr.Deactivate(); }\r
241                 catch (Exception) { }\r
242 \r
243                 ReleaseComObject("_threadMgr", ref _threadMgr);\r
244             }\r
245         }\r
246 \r
247         /// <summary>\r
248         /// カテゴリマネージャーの生成。\r
249         /// </summary>\r
250         /// \r
251         /// <exception cref="COMException">\r
252         /// カテゴリマネージャーの生成に失敗した場合。\r
253         /// </exception>\r
254         void CreateCategoryMgr()\r
255         {\r
256             if (_categoryMgr == null)\r
257             {\r
258                 var clsid = Marshal.GetTypeFromCLSID(TfDeclarations.CLSID_TF_CategoryMgr);\r
259                 _categoryMgr = Activator.CreateInstance(clsid) as ITfCategoryMgr;\r
260 \r
261                 if (_categoryMgr == null)\r
262                 {\r
263                     const string message = "カテゴリマネージャーの生成に失敗しました。";\r
264                     Debug.WriteLine(message);\r
265                     throw new COMException(message, HRESULT.E_NOTIMPL);\r
266                 }\r
267             }\r
268         }\r
269 \r
270         /// <summary>\r
271         /// カテゴリマネージャーの解放。\r
272         /// </summary>\r
273         void DestroyCategoryMgr()\r
274         {\r
275             ReleaseComObject("_categoryMgr", ref _categoryMgr);\r
276         }\r
277 \r
278         /// <summary>\r
279         /// 表示属性マネージャーの生成。\r
280         /// </summary>\r
281         /// \r
282         /// <exception cref="COMException">\r
283         /// 表示属性マネージャーの生成に失敗した場合。\r
284         /// </exception>\r
285         void CreateDisplayAttributeMgr()\r
286         {\r
287             if (_displayAttributeMgr == null)\r
288             {\r
289                 var clsid = Marshal.GetTypeFromCLSID(TfDeclarations.CLSID_TF_DisplayAttributeMgr);\r
290                 _displayAttributeMgr = Activator.CreateInstance(clsid) as ITfDisplayAttributeMgr;\r
291 \r
292                 if (_displayAttributeMgr == null)\r
293                 {\r
294                     const string message = "表示属性マネージャーの生成に失敗しました。";\r
295                     Debug.WriteLine(message);\r
296                     throw new COMException(message, HRESULT.E_NOTIMPL);\r
297                 }\r
298             }\r
299         }\r
300 \r
301         /// <summary>\r
302         /// 表示属性マネージャーの解放。\r
303         /// </summary>\r
304         void DestroyDisplayAttributeMgr()\r
305         {\r
306             ReleaseComObject("_displayAttributeMgr", ref _displayAttributeMgr);\r
307         }\r
308 \r
309         /// <summary>\r
310         /// ドキュメントマネージャーの解放\r
311         /// </summary>\r
312         void DestroyDocumentMgr()\r
313         {\r
314             if (_documentMgr != null)\r
315             {\r
316                 try { _documentMgr.Pop(PopFlags.TF_POPF_ALL); }\r
317                 catch (Exception) { }\r
318 \r
319                 ReleaseComObject("_documentMgr", ref _documentMgr);\r
320             }\r
321         }\r
322 \r
323         /// <summary>\r
324         /// COM オブジェクトのリリースとデバッグメッセージ出力。\r
325         /// </summary>\r
326         protected static void ReleaseComObject<ComObject>(\r
327             string i_objectName,\r
328             ref ComObject io_comObject\r
329         )\r
330         {\r
331             if (io_comObject != null)\r
332             {\r
333                 var refCount = Marshal.ReleaseComObject(io_comObject);\r
334 #if TSF_DEBUG_OUTPUT\r
335                     Debug.WriteLine(\r
336                         "Marshal.ReleaseComObject({0}) returns {1}.",\r
337                         i_objectName,\r
338                         refCount\r
339                     );\r
340 #endif\r
341 \r
342                 io_comObject = default(ComObject);\r
343             }\r
344         }\r
345         #endregion\r
346 \r
347         #region "コントロール側が状況に応じて呼び出さなければいけない TSF に通知を送るメソッド"\r
348         /// <summary>\r
349         /// 選択領域が変更されたことをTSFに伝える。各種ハンドラ内からコールしてはいけない。\r
350         /// </summary>\r
351         public void NotifySelectionChanged()\r
352         {\r
353             if( _sink != null )\r
354             {\r
355                 if( (_adviseFlags & AdviseFlags.TS_AS_SEL_CHANGE) != 0 )\r
356                     _sink.OnSelectionChange();\r
357             }\r
358         }\r
359 \r
360         \r
361         //=========================================================================================\r
362 \r
363 \r
364         /// <summary>\r
365         /// テキストが変更されたことをTSFに伝える。各種ハンドラ内からコールしてはいけない。\r
366         /// </summary>\r
367         public void NotifyTextChanged(TS_TEXTCHANGE textChange)\r
368         {\r
369             if( _sink != null )\r
370             {\r
371                 if( (_adviseFlags & AdviseFlags.TS_AS_TEXT_CHANGE) != 0 )\r
372                     _sink.OnTextChange(0, ref textChange);\r
373                 _sink.OnLayoutChange(TsLayoutCode.TS_LC_CHANGE, 1);\r
374             }\r
375         }\r
376 \r
377         \r
378         //=========================================================================================\r
379 \r
380         /// <summary>\r
381         /// テキストが変更されたことをTSFに伝える。各種ハンドラ内からコールしてはいけない。\r
382         /// </summary>\r
383         /// <param name="start">開始位置</param>\r
384         /// <param name="oldend">更新前の終了位置</param>\r
385         /// <param name="newend">更新後の終了位置</param>\r
386         /// <remarks>\r
387         /// 詳しいことはITextStoreACPSink::OnTextChangeを参照してください\r
388         /// </remarks>\r
389         public void NotifyTextChanged(int start,int oldend,int newend)\r
390         {\r
391             if (_sink != null)\r
392             {\r
393                 if ((_adviseFlags & AdviseFlags.TS_AS_TEXT_CHANGE) != 0)\r
394                 {\r
395                     var textChange = new TS_TEXTCHANGE();\r
396                     textChange.start = start;\r
397                     textChange.oldEnd = oldend;\r
398                     textChange.newEnd = newend;\r
399 \r
400                     _sink.OnTextChange(0, ref textChange);\r
401                 }\r
402                 _sink.OnLayoutChange(TsLayoutCode.TS_LC_CHANGE, 1);\r
403             }\r
404         }\r
405 \r
406         /// <summary>\r
407         /// テキストが変更されたことをTSFに伝える。各種ハンドラ内からコールしてはいけない。\r
408         /// </summary>\r
409         /// <param name="i_oldLength"></param>\r
410         /// <param name="i_newLength"></param>\r
411         public void NotifyTextChanged(int i_oldLength, int i_newLength)\r
412         {\r
413             if( _sink != null )\r
414             {\r
415                 if( (_adviseFlags & AdviseFlags.TS_AS_TEXT_CHANGE) != 0 )\r
416                 {\r
417                     var textChange = new TS_TEXTCHANGE();\r
418                     textChange.start = 0;\r
419                     textChange.oldEnd = i_oldLength;\r
420                     textChange.newEnd = i_newLength;\r
421 \r
422                     _sink.OnTextChange(0, ref textChange);\r
423                 }\r
424                 _sink.OnLayoutChange(TsLayoutCode.TS_LC_CHANGE, 1);\r
425             }\r
426         }\r
427 \r
428         \r
429         \r
430         //=========================================================================================\r
431 \r
432 \r
433         /// <summary>コントロールがフォーカスを取得した時に呼び出さなければいけない。</summary>\r
434         public void SetFocus()\r
435         {\r
436             if (_threadMgr != null)\r
437                 _threadMgr.SetFocus(_documentMgr);\r
438         }\r
439         #endregion "コントロール側が状況に応じて呼び出さなければいけない TSF に通知を送るメソッド"\r
440 \r
441         #region ロック関連\r
442         /// <summary>\r
443         /// ドキュメントのロックを行う。\r
444         /// </summary>\r
445         /// <param name="i_writable">読み書き両用ロックか?false の場合、読み取り専用。</param>\r
446         /// <returns>Unlocker のインスタンスを返す。失敗した場合 null を返す。</returns>\r
447         public Unlocker LockDocument(bool i_writable)\r
448         {\r
449             #if TSF_DEBUG_OUTPUT\r
450             using(var dbgout = new DebugOut("{0}({1})", DebugOut.GetCaller(),\r
451                                                         i_writable) )\r
452             #endif\r
453             {\r
454                 lock(this)\r
455                 {\r
456                     if( this._lockFlags == 0 )\r
457                     {\r
458                         if( i_writable )\r
459                             this._lockFlags = LockFlags.TS_LF_READWRITE;\r
460                         else\r
461                             this._lockFlags = LockFlags.TS_LF_READ;\r
462 \r
463                         #if TSF_DEBUG_OUTPUT\r
464                             Debug.WriteLine("LockDocument is succeeded.");\r
465                         #endif\r
466 \r
467                         return new Unlocker(this);\r
468                     }\r
469                     else\r
470                     {\r
471                         #if TSF_DEBUG_OUTPUT\r
472                             Debug.WriteLine("LockDocument is failed. {0}", _lockFlags);\r
473                         #endif\r
474 \r
475                         return null;\r
476                     }\r
477                 }\r
478             }\r
479         }\r
480 \r
481 \r
482         //========================================================================================\r
483 \r
484         \r
485         /// <summary>\r
486         /// ドキュメントのロックを行う。\r
487         /// </summary>\r
488         /// <param name="i_writable">読み書き両用ロックか?false の場合、読み取り専用。</param>\r
489         /// <returns>Unlocker のインスタンスを返す。失敗した場合 null を返す。</returns>\r
490         public Unlocker LockDocument(LockFlags i_flags)\r
491         {\r
492             #if TSF_DEBUG_OUTPUT\r
493             using(var dbgout = new DebugOut("{0}({1})", DebugOut.GetCaller(),\r
494                                                         i_flags) )\r
495             #endif\r
496             {\r
497                 lock(this)\r
498                 {\r
499                     if( this._lockFlags == 0 )\r
500                     {\r
501                         this._lockFlags = i_flags;\r
502 \r
503                         #if TSF_DEBUG_OUTPUT\r
504                             Debug.WriteLine("LockDocument is succeeded.");\r
505                         #endif\r
506 \r
507                         return new Unlocker(this);\r
508                     }\r
509                     else\r
510                     {\r
511                         #if TSF_DEBUG_OUTPUT\r
512                             Debug.WriteLine("LockDocument is failed. {0}", _lockFlags);\r
513                         #endif\r
514 \r
515                         return null;\r
516                     }\r
517                 }\r
518             }\r
519         }\r
520 \r
521 \r
522         //========================================================================================\r
523 \r
524         \r
525         /// <summary>\r
526         /// ドキュメントのアンロックを行う。\r
527         /// </summary>\r
528         public void UnlockDocument()\r
529         {\r
530             #if TSF_DEBUG_OUTPUT\r
531             using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )\r
532             #endif\r
533             {\r
534                 lock(this)\r
535                 {\r
536                     _lockFlags = 0;\r
537                 }\r
538 \r
539                 if( _pendingLockUpgrade )\r
540                 {\r
541                     _pendingLockUpgrade = false;\r
542                     int sessionResult;\r
543                     RequestLock(LockFlags.TS_LF_READWRITE, out sessionResult);\r
544                 }\r
545             }\r
546         }\r
547 \r
548 \r
549         //========================================================================================\r
550 \r
551         \r
552         /// <summary>\r
553         /// 指定されたフラグでロックしている状態かどうか調べる。\r
554         /// </summary>\r
555         /// <param name="i_lockFlags"></param>\r
556         /// <returns>ロックされている場合は true, されていない場合は false を返す。</returns>\r
557         public bool IsLocked(LockFlags i_lockFlags)\r
558         {\r
559             #if TSF_DEBUG_OUTPUT\r
560             using(var dbgout = new DebugOut("{0}({1})",\r
561                                             DebugOut.GetCaller(), i_lockFlags) )\r
562             #endif\r
563             {\r
564                 #if TSF_DEBUG_OUTPUT\r
565                     Debug.WriteLine(\r
566                         "IsLocked() returns " + ((this._lockFlags & i_lockFlags) == i_lockFlags)\r
567                     );\r
568                 #endif\r
569                 return (this._lockFlags & i_lockFlags) == i_lockFlags;\r
570             }\r
571         }\r
572 \r
573         /// <summary>\r
574         /// ロックされているか調べる\r
575         /// </summary>\r
576         /// <returns>ロックされているなら真、そうでなければ偽を返す</returns>\r
577         public bool IsLocked()\r
578         {\r
579 #if TSF_DEBUG_OUTPUT\r
580             using(var dbgout = new DebugOut("{0}",\r
581                                             DebugOut.GetCaller()) )\r
582 #endif\r
583             {\r
584                 bool retval = this._lockFlags != 0;\r
585 #if TSF_DEBUG_OUTPUT\r
586                     Debug.WriteLine(\r
587                         "IsLocked() returns " + retval\r
588                     );\r
589 #endif\r
590                 return retval;\r
591             }\r
592         }\r
593         #endregion\r
594 \r
595         #region ITextStroeACP,ITextStoreACP2の共通部分\r
596 \r
597         /// <summary>\r
598         /// 文字列を挿入する。\r
599         /// </summary>\r
600         public void InsertTextAtSelection(string s)\r
601         {\r
602             TS_TEXTCHANGE textChange = new TS_TEXTCHANGE();\r
603 \r
604             using (var unlocker = LockDocument(true))\r
605             {\r
606                 if (unlocker != null)\r
607                 {\r
608                     int startIndex, endIndex;\r
609 \r
610                     InsertTextAtSelection(\r
611                         UnmanagedAPI.TSF.TextStore.InsertAtSelectionFlags.TF_IAS_NOQUERY,\r
612                         s.ToCharArray(),\r
613                         s.Length,\r
614                         out startIndex,\r
615                         out endIndex,\r
616                         out textChange\r
617                     );\r
618                 }\r
619             }\r
620 \r
621             // シンクの OnSelectionChange() をコール。\r
622             NotifySelectionChanged();\r
623             NotifyTextChanged(textChange);\r
624         }\r
625 \r
626         public void InsertEmbeddedAtSelection(\r
627             InsertAtSelectionFlags flags,\r
628             object obj,\r
629             out int start,\r
630             out int end,\r
631             out TS_TEXTCHANGE change\r
632         )\r
633         {\r
634 #if TSF_DEBUG_OUTPUT\r
635             using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )\r
636 #endif\r
637             {\r
638                 throw new NotImplementedException();\r
639             }\r
640         }\r
641 \r
642         public void AdviseSink(ref Guid i_riid, object i_unknown, AdviseFlags i_mask)\r
643         {\r
644 #if TSF_DEBUG_OUTPUT\r
645             using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )\r
646 #endif\r
647             {\r
648                 if (i_riid != new Guid("22d44c94-a419-4542-a272-ae26093ececf")) //ITextStoreACPSinkの定義より\r
649                 {\r
650                     throw new COMException(\r
651                         "ITextStoreACPSink 以外のIIDが渡されました。",\r
652                         UnmanagedAPI.WinError.HRESULT.E_INVALIDARG\r
653                     );\r
654                 }\r
655 \r
656                 // 既存のシンクのマスクのみを更新\r
657                 if (_sink == i_unknown)\r
658                 {\r
659                     _adviseFlags = i_mask;\r
660                 }\r
661                 // シンクを複数登録しようとした\r
662                 else if (_sink != null)\r
663                 {\r
664                     throw new COMException(\r
665                         "既にシンクを登録済みです。",\r
666                         UnmanagedAPI.TSF.TextStore.TsResult.CONNECT_E_ADVISELIMIT\r
667                     );\r
668                 }\r
669                 else\r
670                 {\r
671                     // 各種値を保存\r
672                     _services = (ITextStoreACPServices)i_unknown;\r
673                     _sink = (ITextStoreACPSink)i_unknown;\r
674                     _adviseFlags = i_mask;\r
675                 }\r
676             }\r
677         }\r
678 \r
679         public void UnadviseSink(object i_unknown)\r
680         {\r
681 #if TSF_DEBUG_OUTPUT\r
682             using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )\r
683 #endif\r
684             {\r
685                 if (_sink == null || _sink != i_unknown)\r
686                 {\r
687                     throw new COMException(\r
688                         "シンクは登録されていません。",\r
689                         UnmanagedAPI.TSF.TextStore.TsResult.CONNECT_E_NOCONNECTION\r
690                     );\r
691                 }\r
692 \r
693                 _services = null;\r
694                 _sink = null;\r
695                 _adviseFlags = 0;\r
696             }\r
697         }\r
698 \r
699         public void RequestLock(LockFlags i_lockFlags, out int o_sessionResult)\r
700         {\r
701 #if TSF_DEBUG_OUTPUT\r
702             using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )\r
703 #endif\r
704             {\r
705                 o_sessionResult = UnmanagedAPI.WinError.HRESULT.E_FAIL;\r
706 \r
707                 if (_sink == null)\r
708                 {\r
709                     throw new COMException(\r
710                         "シンクが登録されていません。",\r
711                         UnmanagedAPI.TSF.TextStore.TsResult.CONNECT_E_NOCONNECTION\r
712                     );\r
713                 }\r
714 \r
715                 if (_lockFlags != 0)   // すでにロックされた状態の場合。\r
716                 {\r
717                     if ((i_lockFlags & LockFlags.TS_LF_SYNC) != 0)\r
718                     {\r
719                         o_sessionResult = TsResult.TS_E_SYNCHRONOUS;\r
720                         return;\r
721                     }\r
722                     else\r
723                         if ((_lockFlags & LockFlags.TS_LF_READWRITE) == LockFlags.TS_LF_READ\r
724                         && (i_lockFlags & LockFlags.TS_LF_READWRITE) == LockFlags.TS_LF_READWRITE)\r
725                         {\r
726                             _pendingLockUpgrade = true;\r
727                             o_sessionResult = TsResult.TS_S_ASYNC;\r
728                             return;\r
729                         }\r
730 \r
731                     throw new COMException();\r
732                 }\r
733 \r
734                 using (var unlocker = LockDocument(i_lockFlags))\r
735                 {\r
736                     // ロックに失敗した場合は TS_E_SYNCHRONOUS をセットして S_OK を返す。\r
737                     if (unlocker == null)\r
738                     {\r
739                         o_sessionResult = TsResult.TS_E_SYNCHRONOUS;\r
740                     }\r
741                     // ロックに成功した場合は OnLockGranted() を呼び出す。\r
742                     else\r
743                     {\r
744                         try\r
745                         {\r
746                             o_sessionResult = _sink.OnLockGranted(i_lockFlags);\r
747                         }\r
748                         catch (COMException comException)\r
749                         {\r
750                             Debug.WriteLine("OnLockGranted() 呼び出し中に例外が発生。");\r
751                             Debug.WriteLine("  " + comException.Message);\r
752                             o_sessionResult = comException.HResult;\r
753                         }\r
754                         catch (Exception exception)\r
755                         {\r
756                             Debug.WriteLine("OnLockGranted() 呼び出し中に例外が発生。");\r
757                             Debug.WriteLine("  " + exception.Message);\r
758                         }\r
759                     }\r
760                 }\r
761             }\r
762         }\r
763 \r
764         public void GetStatus(out TS_STATUS o_documentStatus)\r
765         {\r
766 #if TSF_DEBUG_OUTPUT\r
767             using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )\r
768 #endif\r
769             {\r
770                 if (IsReadOnly != null && IsReadOnly())\r
771                     o_documentStatus.dynamicFlags = DynamicStatusFlags.TS_SD_READONLY;\r
772                 if (IsLoading != null && IsLoading())\r
773                     o_documentStatus.dynamicFlags = DynamicStatusFlags.TS_SD_LOADING;\r
774                 else\r
775                     o_documentStatus.dynamicFlags = 0;\r
776                 o_documentStatus.staticFlags = StaticStatusFlags.TS_SS_REGIONS;\r
777             }\r
778         }\r
779 \r
780         public void QueryInsert(\r
781             int i_startIndex,\r
782             int i_endIndex,\r
783             int i_length,\r
784             out int o_startIndex,\r
785             out int o_endIndex\r
786         )\r
787         {\r
788 #if TSF_DEBUG_OUTPUT\r
789             using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )\r
790 #endif\r
791             {\r
792                 if (GetStringLength == null)\r
793                     throw new NotImplementedException();\r
794 \r
795                 int documentLength = GetStringLength();\r
796 \r
797                 if (i_startIndex < 0\r
798                 || i_startIndex > i_endIndex\r
799                 || i_endIndex > documentLength)\r
800                 {\r
801                     throw new COMException(\r
802                         "インデックスが無効です。",\r
803                         UnmanagedAPI.WinError.HRESULT.E_INVALIDARG\r
804                     );\r
805                 }\r
806 \r
807                 o_startIndex = i_startIndex;\r
808                 o_endIndex = i_endIndex;\r
809             }\r
810         }\r
811 \r
812         public void GetSelection(\r
813             int i_index,\r
814             int i_selectionBufferLength,\r
815             TS_SELECTION_ACP[] o_selections,\r
816             out int o_fetchedLength\r
817         )\r
818         {\r
819 #if TSF_DEBUG_OUTPUT\r
820             using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )\r
821 #endif\r
822             {\r
823                 if (GetSelectionIndex == null)\r
824                     throw new NotImplementedException();\r
825 \r
826                 o_fetchedLength = 0;\r
827 \r
828                 if (IsLocked(LockFlags.TS_LF_READ) == false)\r
829                 {\r
830                     throw new COMException(\r
831                         "読取用ロックがされていません。",\r
832                         TsResult.TS_E_NOLOCK\r
833                     );\r
834                 }\r
835 \r
836                 // -1 は TF_DEFAULT_SELECTION。選択は1つだけしかサポートしないので、\r
837                 // TF_DEFAULT_SELECTION でもなく、0 を超える数値が指定された場合はエラー。\r
838                 if (i_index != -1 && i_index > 0)\r
839                 {\r
840                     throw new COMException(\r
841                         "選択は1つだけしかサポートしていません。",\r
842                         UnmanagedAPI.WinError.HRESULT.E_INVALIDARG\r
843                     );\r
844                 }\r
845 \r
846                 if (i_selectionBufferLength > 0)\r
847                 {\r
848                     int start = 0, end = 0;\r
849                     GetSelectionIndex(out start, out end);\r
850                     if (start <= end)\r
851                     {\r
852                         o_selections[0].start = start;\r
853                         o_selections[0].end = end;\r
854                         o_selections[0].style.ase = TsActiveSelEnd.TS_AE_END;\r
855                         o_selections[0].style.interimChar = false;\r
856                     }\r
857                     else\r
858                     {\r
859                         o_selections[0].start = end;\r
860                         o_selections[0].end = start;\r
861                         o_selections[0].style.ase = TsActiveSelEnd.TS_AE_START;\r
862                         o_selections[0].style.interimChar = false;\r
863                     }\r
864 \r
865                     o_fetchedLength = 1;\r
866                 }\r
867             }\r
868         }\r
869 \r
870         public void SetSelection(int i_count, TS_SELECTION_ACP[] i_selections)\r
871         {\r
872 #if TSF_DEBUG_OUTPUT\r
873             using(var dbgout = new DebugOut("{0}({1}, {2})",\r
874                                             DebugOut.GetCaller(),\r
875                                             i_selections[0].start,\r
876                                             i_selections[0].end))\r
877 #endif\r
878             {\r
879                 if (SetSelectionIndex == null)\r
880                     throw new NotImplementedException();\r
881 \r
882                 if (i_count != 1)\r
883                 {\r
884                     throw new COMException(\r
885                         "選択は1つだけしかサポートしていません。",\r
886                         UnmanagedAPI.WinError.HRESULT.E_INVALIDARG\r
887                     );\r
888                 }\r
889 \r
890                 if (IsLocked(LockFlags.TS_LF_READWRITE) == false)\r
891                 {\r
892                     throw new COMException(\r
893                         "ロックされていません。",\r
894                         TsResult.TS_E_NOLOCK\r
895                     );\r
896                 }\r
897 \r
898                 SetSelectionIndex(i_selections[0].start, i_selections[0].end);\r
899             }\r
900         }\r
901 \r
902         public void GetText(\r
903             int i_startIndex,\r
904             int i_endIndex,\r
905             char[] o_plainText,\r
906             int i_plainTextLength,\r
907             out int o_plainTextLength,\r
908             TS_RUNINFO[] o_runInfos,\r
909             int i_runInfoLength,\r
910             out int o_runInfoLength,\r
911             out int o_nextUnreadCharPos\r
912         )\r
913         {\r
914 #if TSF_DEBUG_OUTPUT\r
915             using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )\r
916 #endif\r
917             {\r
918                 if (GetStringLength == null || GetString == null)\r
919                     throw new NotImplementedException();\r
920 \r
921                 if (IsLocked(LockFlags.TS_LF_READ) == false)\r
922                 {\r
923                     throw new COMException(\r
924                         "読取用ロックがされていません。",\r
925                         TsResult.TS_E_NOLOCK\r
926                     );\r
927                 }\r
928 \r
929                 if ((i_endIndex != -1 && i_startIndex > i_endIndex)\r
930                 || i_startIndex < 0 || i_startIndex > GetStringLength()\r
931                 || i_endIndex > GetStringLength())\r
932                 {\r
933                     throw new COMException(\r
934                         "インデックスが無効です。",\r
935                         UnmanagedAPI.WinError.HRESULT.E_INVALIDARG\r
936                     );\r
937                 }\r
938 \r
939                 var textLength = 0;\r
940                 var copyLength = 0;\r
941 \r
942                 if (i_endIndex == -1)\r
943                     textLength = GetStringLength() - i_startIndex;\r
944                 else\r
945                     textLength = i_endIndex - i_startIndex;\r
946                 copyLength = Math.Min(i_plainTextLength, textLength);\r
947 \r
948                 // 文字列を格納。\r
949                 var text = GetString(i_startIndex, copyLength);\r
950                 for (int i = 0; i < copyLength; i++)\r
951                 {\r
952                     o_plainText[i] = text[i];\r
953                 }\r
954 \r
955                 // 文字数を格納。\r
956                 o_plainTextLength = copyLength;\r
957                 // RUNINFO を格納。\r
958                 if (i_runInfoLength > 0)\r
959                 {\r
960                     o_runInfos[0].type = TsRunType.TS_RT_PLAIN;\r
961                     o_runInfos[0].length = copyLength;\r
962                 }\r
963                 o_runInfoLength = 1;\r
964 \r
965                 // 次の文字の位置を格納。\r
966                 o_nextUnreadCharPos = i_startIndex + copyLength;\r
967             }\r
968         }\r
969 \r
970         public void SetText(\r
971             SetTextFlags i_flags,\r
972             int i_startIndex,\r
973             int i_endIndex,\r
974             char[] i_text,\r
975             int i_length,\r
976             out TS_TEXTCHANGE o_textChange\r
977         )\r
978         {\r
979 #if TSF_DEBUG_OUTPUT\r
980             using(var dbgout = new DebugOut("{0}({1}, {2})",\r
981                                             DebugOut.GetCaller(),\r
982                                             i_startIndex, i_endIndex) )\r
983 #endif\r
984             {\r
985                 var selections = new TS_SELECTION_ACP[]\r
986                 {\r
987                     new TS_SELECTION_ACP\r
988                     {\r
989                         start = i_startIndex,\r
990                         end   = i_endIndex,\r
991                         style = new TS_SELECTIONSTYLE\r
992                         {\r
993                             ase = TsActiveSelEnd.TS_AE_END,\r
994                             interimChar = false\r
995                         }\r
996                     }\r
997                 };\r
998 \r
999                 int startIndex = 0, endIndex = 0;\r
1000                 SetSelection(1, selections);\r
1001                 InsertTextAtSelection(\r
1002                     InsertAtSelectionFlags.TF_IAS_NOQUERY,\r
1003                     i_text,\r
1004                     i_length,\r
1005                     out startIndex,\r
1006                     out endIndex,\r
1007                     out o_textChange\r
1008                 );\r
1009             }\r
1010         }\r
1011 \r
1012         public void GetFormattedText(int i_start, int i_end, out object o_obj)\r
1013         {\r
1014 #if TSF_DEBUG_OUTPUT\r
1015             using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )\r
1016 #endif\r
1017             {\r
1018                 throw new NotImplementedException();\r
1019             }\r
1020         }\r
1021 \r
1022         public void GetEmbedded(\r
1023             int i_position,\r
1024             ref Guid i_guidService,\r
1025             ref Guid i_riid,\r
1026             out object o_obj\r
1027         )\r
1028         {\r
1029 #if TSF_DEBUG_OUTPUT\r
1030             using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )\r
1031 #endif\r
1032             {\r
1033                 throw new NotImplementedException();\r
1034             }\r
1035         }\r
1036 \r
1037         public void QueryInsertEmbedded(\r
1038             ref Guid i_guidService,\r
1039             int i_formatEtc,\r
1040             out bool o_insertable\r
1041         )\r
1042         {\r
1043 #if TSF_DEBUG_OUTPUT\r
1044             using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )\r
1045 #endif\r
1046             {\r
1047                 throw new NotImplementedException();\r
1048             }\r
1049         }\r
1050 \r
1051         public void InsertEmbedded(\r
1052             InsertEmbeddedFlags i_flags,\r
1053             int i_start,\r
1054             int i_end,\r
1055             object i_obj,\r
1056             out TS_TEXTCHANGE o_textChange\r
1057         )\r
1058         {\r
1059 #if TSF_DEBUG_OUTPUT\r
1060             using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )\r
1061 #endif\r
1062             {\r
1063                 throw new NotImplementedException();\r
1064             }\r
1065         }\r
1066 \r
1067         public void InsertTextAtSelection(\r
1068             InsertAtSelectionFlags i_flags,\r
1069             char[] i_text,\r
1070             int i_length,\r
1071             out int o_startIndex,\r
1072             out int o_endIndex,\r
1073             out TS_TEXTCHANGE o_textChange\r
1074         )\r
1075         {\r
1076 #if TSF_DEBUG_OUTPUT\r
1077             using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )\r
1078 #endif\r
1079             {\r
1080                 if (GetSelectionIndex == null || InsertAtSelection == null)\r
1081                     throw new NotImplementedException();\r
1082 \r
1083                 int selectionStart = 0, selectionEnd = 0;\r
1084                 GetSelectionIndex(out selectionStart, out selectionEnd);\r
1085 \r
1086                 // 問い合わせのみで実際には操作を行わない\r
1087                 if ((i_flags & InsertAtSelectionFlags.TF_IAS_QUERYONLY) != 0)\r
1088                 {\r
1089                     o_startIndex = Math.Min(selectionStart, selectionEnd);\r
1090                     o_endIndex = Math.Max(selectionStart, selectionEnd);//o_startIndex + i_length;\r
1091 \r
1092                     o_textChange.start = o_startIndex;\r
1093                     o_textChange.oldEnd = o_endIndex;\r
1094                     o_textChange.newEnd = o_startIndex + i_length;\r
1095                 }\r
1096                 else\r
1097                 {\r
1098                     var start = Math.Min(selectionStart, selectionEnd);\r
1099                     var end = Math.Max(selectionStart, selectionEnd);\r
1100 \r
1101 #if TSF_DEBUG_OUTPUT\r
1102                         Debug.WriteLine(string.Format(\r
1103                             "start: {0}, end: {1}, text: {2}",\r
1104                             start, end, new string(i_text)\r
1105                         ));\r
1106 #endif\r
1107 \r
1108                     InsertAtSelection(new string(i_text));\r
1109 \r
1110                     o_startIndex = start;\r
1111                     o_endIndex = start + i_length;\r
1112 \r
1113                     o_textChange.start = start;\r
1114                     o_textChange.oldEnd = end;\r
1115                     o_textChange.newEnd = start + i_length;\r
1116 \r
1117                     // InsertAtSelection() 内でカーソル位置を更新しているため、ここでは不要。\r
1118                     // 改行した時に位置が狂う。\r
1119                     // SetSelectionIndex(start, start + i_length);\r
1120                 }\r
1121             }\r
1122         }\r
1123 \r
1124         public void GetEndACP(out int o_length)\r
1125         {\r
1126 #if TSF_DEBUG_OUTPUT\r
1127             using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )\r
1128 #endif\r
1129             {\r
1130                 if (GetStringLength == null)\r
1131                     throw new NotImplementedException();\r
1132 \r
1133                 if (IsLocked(LockFlags.TS_LF_READ) == false)\r
1134                 {\r
1135                     throw new COMException(\r
1136                         "読取用ロックがされていません。",\r
1137                         TsResult.TS_E_NOLOCK\r
1138                     );\r
1139                 }\r
1140 \r
1141                 o_length = GetStringLength();\r
1142             }\r
1143         }\r
1144 \r
1145         public void GetActiveView(out int o_viewCookie)\r
1146         {\r
1147 #if TSF_DEBUG_OUTPUT\r
1148             using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )\r
1149 #endif\r
1150             {\r
1151                 o_viewCookie = 1;\r
1152             }\r
1153         }\r
1154 \r
1155         public void GetACPFromPoint(\r
1156     int i_viewCookie,\r
1157     ref POINT i_point,\r
1158     GetPositionFromPointFlags i_flags,\r
1159     out int o_index\r
1160 )\r
1161         {\r
1162 #if TSF_DEBUG_OUTPUT\r
1163             using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )\r
1164 #endif\r
1165             {\r
1166                 throw new NotImplementedException();\r
1167             }\r
1168         }\r
1169 \r
1170         public void GetTextExt(\r
1171             int i_viewCookie,\r
1172             int i_startIndex,\r
1173             int i_endIndex,\r
1174             out RECT o_rect,\r
1175             out bool o_isClipped\r
1176         )\r
1177         {\r
1178 #if TSF_DEBUG_OUTPUT\r
1179             using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )\r
1180 #endif\r
1181             {\r
1182                 if (GetStringLength == null)\r
1183                     throw new NotImplementedException();\r
1184 \r
1185                 // 読取用ロックの確認。\r
1186                 if (IsLocked(LockFlags.TS_LF_READ) == false)\r
1187                 {\r
1188                     throw new COMException(\r
1189                         "読取用ロックがされていません。",\r
1190                         TsResult.TS_E_NOLOCK\r
1191                     );\r
1192                 }\r
1193 \r
1194                 if ((i_endIndex != -1 && i_startIndex > i_endIndex)\r
1195                 || i_startIndex < 0 || i_startIndex > GetStringLength()\r
1196                 || i_endIndex > GetStringLength())\r
1197                 {\r
1198                     throw new COMException(\r
1199                         "インデックスが無効です。",\r
1200                         UnmanagedAPI.WinError.HRESULT.E_INVALIDARG\r
1201                     );\r
1202                 }\r
1203 \r
1204                 if (i_endIndex == -1)\r
1205                     i_endIndex = GetStringLength();\r
1206 \r
1207                 var pointTopLeft = new POINT();\r
1208                 var pointBotttomRight = new POINT();\r
1209                 GetStringExtent(i_startIndex, i_endIndex, out pointTopLeft, out pointBotttomRight);\r
1210 \r
1211                 o_rect.left = (int)pointTopLeft.x;\r
1212                 o_rect.top = (int)pointTopLeft.y;\r
1213                 o_rect.bottom = (int)pointBotttomRight.y;//startFormattedText.Height);\r
1214                 o_rect.right = (int)pointBotttomRight.x;\r
1215                 o_isClipped = false;\r
1216             }\r
1217         }\r
1218 \r
1219         public void GetScreenExt(int i_viewCookie, out RECT o_rect)\r
1220         {\r
1221 #if TSF_DEBUG_OUTPUT\r
1222             using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )\r
1223 #endif\r
1224             {\r
1225                 if (GetScreenExtent == null)\r
1226                     throw new NotImplementedException();\r
1227 \r
1228                 POINT pointTopLeft, pointBottomRight;\r
1229 \r
1230                 GetScreenExtent(out pointTopLeft, out pointBottomRight);\r
1231 \r
1232                 o_rect.left = (int)pointTopLeft.x;\r
1233                 o_rect.top = (int)pointTopLeft.y;\r
1234                 o_rect.right = (int)pointBottomRight.x;\r
1235                 o_rect.bottom = (int)pointBottomRight.y;\r
1236             }\r
1237         }\r
1238 \r
1239         public void RequestSupportedAttrs(\r
1240             AttributeFlags i_flags,\r
1241             int i_length,\r
1242             Guid[] i_filterAttributes\r
1243         )\r
1244         {\r
1245 #if TSF_DEBUG_OUTPUT\r
1246             using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )\r
1247 #endif\r
1248             {\r
1249                 for (int i = 0; i < i_length; i++)\r
1250                 {\r
1251                     if (i_filterAttributes[i].Equals(_attributeInfo[0].attrID))\r
1252                     {\r
1253                         _attributeInfo[0].flags = AttributeInfoFlags.Requested;\r
1254                         if ((i_flags & AttributeFlags.TS_ATTR_FIND_WANT_VALUE) != 0)\r
1255                         {\r
1256                             _attributeInfo[0].flags |= AttributeInfoFlags.Default;\r
1257                         }\r
1258                         else\r
1259                         {\r
1260                             _attributeInfo[0].currentValue = _attributeInfo[0].defaultValue;\r
1261                         }\r
1262                     }\r
1263                 }\r
1264             }\r
1265         }\r
1266 \r
1267         public void RequestAttrsAtPosition(\r
1268             int i_position,\r
1269             int i_length,\r
1270             Guid[] i_filterAttributes,\r
1271             AttributeFlags i_flags\r
1272         )\r
1273         {\r
1274 #if TSF_DEBUG_OUTPUT\r
1275             using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )\r
1276 #endif\r
1277             {\r
1278                 for (int i = 0; i < i_length; i++)\r
1279                 {\r
1280                     if (i_filterAttributes[i].Equals(_attributeInfo[0].attrID))\r
1281                     {\r
1282                         _attributeInfo[0].flags = AttributeInfoFlags.Requested;\r
1283                         if ((i_flags & AttributeFlags.TS_ATTR_FIND_WANT_VALUE) != 0)\r
1284                         {\r
1285                             _attributeInfo[0].flags |= AttributeInfoFlags.Default;\r
1286                         }\r
1287                         else\r
1288                         {\r
1289                             _attributeInfo[0].currentValue = _attributeInfo[0].defaultValue;\r
1290                         }\r
1291                     }\r
1292                 }\r
1293             }\r
1294         }\r
1295 \r
1296         public void RequestAttrsTransitioningAtPosition(\r
1297             int i_position,\r
1298             int i_length,\r
1299             Guid[] i_filterAttributes,\r
1300             AttributeFlags i_flags\r
1301         )\r
1302         {\r
1303 #if TSF_DEBUG_OUTPUT\r
1304             using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()))\r
1305 #endif\r
1306             {\r
1307                 // 何もしない。\r
1308             }\r
1309         }\r
1310 \r
1311         public void FindNextAttrTransition(\r
1312             int i_start,\r
1313             int i_halt,\r
1314             int i_length,\r
1315             Guid[] i_filterAttributes,\r
1316             AttributeFlags i_flags,\r
1317             out int o_nextIndex,\r
1318             out bool o_found,\r
1319             out int o_foundOffset\r
1320         )\r
1321         {\r
1322 #if TSF_DEBUG_OUTPUT\r
1323             using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )\r
1324 #endif\r
1325             {\r
1326                 throw new NotImplementedException();\r
1327             }\r
1328         }\r
1329 \r
1330         public void RetrieveRequestedAttrs(\r
1331             int i_length,\r
1332             TS_ATTRVAL[] o_attributeVals,\r
1333             out int o_fetchedLength\r
1334         )\r
1335         {\r
1336 #if TSF_DEBUG_OUTPUT\r
1337             using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )\r
1338 #endif\r
1339             {\r
1340                 o_fetchedLength = 0;\r
1341                 for (int i = 0; i < _attributeInfo.Length && o_fetchedLength < i_length; i++)\r
1342                 {\r
1343                     if ((_attributeInfo[i].flags & AttributeInfoFlags.Requested) != 0)\r
1344                     {\r
1345                         o_attributeVals[o_fetchedLength].overlappedId = 0;\r
1346                         o_attributeVals[o_fetchedLength].attributeId = _attributeInfo[i].attrID;\r
1347                         o_attributeVals[o_fetchedLength].val = _attributeInfo[i].currentValue;\r
1348 \r
1349                         if ((_attributeInfo[i].flags & AttributeInfoFlags.Default) != 0)\r
1350                             _attributeInfo[i].currentValue = _attributeInfo[i].defaultValue;\r
1351 \r
1352                         o_fetchedLength++;\r
1353                         _attributeInfo[i].flags = AttributeInfoFlags.None;\r
1354                     }\r
1355                 }\r
1356             }\r
1357         }\r
1358         #endregion\r
1359 \r
1360         #region "ITfContextOwnerCompositionSink インターフェイスの実装"\r
1361         /// <summary>コンポジション入力が開始された時の処理。</summary>\r
1362         public void OnStartComposition(ITfCompositionView view, out bool ok)\r
1363         {\r
1364             #if TSF_DEBUG_OUTPUT\r
1365             using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )\r
1366             #endif\r
1367             {\r
1368                 if( CompositionStarted != null )\r
1369                     ok = CompositionStarted();\r
1370                 else\r
1371                     ok = true;\r
1372             }\r
1373         }\r
1374 \r
1375 \r
1376         //========================================================================================\r
1377 \r
1378 \r
1379         /// <summary>コンポジションが変更された時の処理。</summary>\r
1380         public void OnUpdateComposition(ITfCompositionView view, ITfRange rangeNew)\r
1381         {\r
1382             #if TSF_DEBUG_OUTPUT\r
1383             using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )\r
1384             #endif\r
1385             {\r
1386                 if (rangeNew == null)\r
1387                     return;\r
1388 \r
1389                 int start, count;\r
1390                 \r
1391                 ITfRangeACP rangeAcp = (ITfRangeACP)rangeNew;\r
1392                 \r
1393                 rangeAcp.GetExtent(out start, out count);\r
1394                 \r
1395                 if (this.CompositionUpdated != null)\r
1396                     this.CompositionUpdated(start, start + count);\r
1397             }\r
1398         }\r
1399 \r
1400         \r
1401         //========================================================================================\r
1402 \r
1403 \r
1404         /// <summary>コンポジション入力が終了した時の処理。</summary>\r
1405         public void OnEndComposition(ITfCompositionView view)\r
1406         {\r
1407             #if TSF_DEBUG_OUTPUT\r
1408             using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )\r
1409             #endif\r
1410             {\r
1411                 if( CompositionEnded != null )\r
1412                     CompositionEnded();\r
1413             }\r
1414         }\r
1415         #endregion "ITfContextOwnerCompositionSink インターフェイスの実装"\r
1416 \r
1417         #region 表示属性\r
1418         /// <summary>表示属性の取得</summary>\r
1419         public IEnumerable<TextDisplayAttribute> EnumAttributes(int start, int end)\r
1420         {\r
1421             ITfRangeACP allRange;\r
1422             _services.CreateRange(start, end, out allRange);\r
1423 \r
1424             foreach (TextDisplayAttribute attr in this.EnumAttributes((ITfRange)allRange))\r
1425                 yield return attr;\r
1426 \r
1427             ReleaseComObject("allRange", ref allRange);\r
1428         }\r
1429 \r
1430         IEnumerable<TextDisplayAttribute> EnumAttributes(ITfRange range)\r
1431         {\r
1432 #if TSF_DEBUG_OUTPUT\r
1433             using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()))\r
1434 #endif\r
1435             {\r
1436                 ITfProperty property = null;    // プロパティインターフェイス\r
1437                 IEnumTfRanges enumRanges;         // 範囲の列挙子\r
1438                 Guid guidPropAttribute = TfDeclarations.GUID_PROP_ATTRIBUTE;\r
1439 \r
1440                 if (_context == null || _services == null)\r
1441                     yield break;\r
1442 \r
1443                 // GUID_PROP_ATTRIBUTE プロパティを取得。\r
1444                 _context.GetProperty(ref guidPropAttribute, out property);\r
1445                 if (property == null)\r
1446                     yield break;\r
1447 \r
1448                 // 全範囲の中で表示属性プロパティをもつ範囲を列挙する。\r
1449                 property.EnumRanges((int)_editCookie, out enumRanges, range);\r
1450 \r
1451                 ITfRange[] ranges = new ITfRange[1];\r
1452                 int fetchedLength = 0;\r
1453                 while (HRESULT.Succeeded(enumRanges.Next(1, ranges, out fetchedLength))\r
1454                     && fetchedLength > 0)\r
1455                 {\r
1456                     // ItfRange から ItfRangeACP を取得。\r
1457                     ITfRangeACP rangeACP = ranges[0] as ITfRangeACP;\r
1458                     if (rangeACP == null)\r
1459                         continue;   // 普通はあり得ない\r
1460 \r
1461                     // 範囲の開始位置と文字数を取得。\r
1462                     int start, count;\r
1463                     rangeACP.GetExtent(out start, out count);\r
1464 \r
1465                     // VARIANT 値としてプロパティ値を取得。VT_I4 の GUID ATOM がとれる。\r
1466                     VARIANT value = new VARIANT();\r
1467                     property.GetValue((int)_editCookie, ranges[0], ref value);\r
1468                     if (value.vt == (short)VarEnum.VT_I4)\r
1469                     {\r
1470                         Guid guid, clsid;\r
1471                         ITfDisplayAttributeInfo info;\r
1472                         TF_DISPLAYATTRIBUTE attribute;\r
1473 \r
1474                         // GUID ATOM から GUID を取得する。\r
1475                         _categoryMgr.GetGUID((int)value.data1, out guid);\r
1476                         // その GUID から IDisplayAttributeInfo インターフェイスを取得。\r
1477                         _displayAttributeMgr.GetDisplayAttributeInfo(\r
1478                             ref guid,\r
1479                             out info,\r
1480                             out clsid\r
1481                         );\r
1482                         // さらに IDisplayAttributeInfo インターフェイスから表示属性を取得する。\r
1483                         info.GetAttributeInfo(out attribute);\r
1484                         ReleaseComObject("info", ref info);\r
1485 \r
1486                         yield return new TextDisplayAttribute\r
1487                         {\r
1488                             startIndex = start,\r
1489                             endIndex = start + count,\r
1490                             attribute = attribute\r
1491                         };\r
1492 \r
1493 #if TSF_DEBUG_OUTPUT\r
1494                             Debug.WriteLine(\r
1495                                 "*******:::: DisplayAttribute: {0} ~ {1} :::::: *********",\r
1496                                 start, start + count\r
1497                             );\r
1498                             Debug.WriteLine(attribute.bAttr);\r
1499                             Debug.WriteLine(\r
1500                                 "LineColorType: {0}, {1}",\r
1501                                 attribute.crLine.type, attribute.crLine.indexOrColorRef\r
1502                             );\r
1503                             Debug.WriteLine(\r
1504                                 "TextColorType: {0}, {1}",\r
1505                                 attribute.crText.type, attribute.crText.indexOrColorRef\r
1506                             );\r
1507                             Debug.WriteLine(\r
1508                                 "BackColorType: {0}, {1}",\r
1509                                 attribute.crBk.type, attribute.crBk.indexOrColorRef\r
1510                             );\r
1511                             Debug.WriteLine(\r
1512                                 "Bold, Style  : {0}, {1}",\r
1513                                 attribute.fBoldLine, attribute.lsStyle\r
1514                             );\r
1515 #endif\r
1516                     }\r
1517 \r
1518                     ReleaseComObject("rangeACP", ref rangeACP);\r
1519                 }\r
1520 \r
1521                 ReleaseComObject("ranges[0]", ref ranges[0]);\r
1522                 ReleaseComObject("enumRanges", ref enumRanges);\r
1523                 ReleaseComObject("property", ref property);\r
1524             }\r
1525         }\r
1526         #endregion\r
1527 \r
1528 #if METRO\r
1529         protected ITfThreadMgr2 _threadMgr;\r
1530 #else\r
1531         protected ITfThreadMgr _threadMgr;\r
1532 #endif\r
1533         protected ITfDocumentMgr _documentMgr;\r
1534         protected ITfFunctionProvider _functionProvider;\r
1535         protected ITfFnReconversion _reconversion;\r
1536         protected ITfContext _context;\r
1537         protected ITfCategoryMgr _categoryMgr;\r
1538         protected ITfDisplayAttributeMgr _displayAttributeMgr;\r
1539         protected ITextStoreACPSink _sink;\r
1540         protected uint _editCookie = 0;\r
1541         protected ITextStoreACPServices _services;\r
1542         protected AdviseFlags               _adviseFlags = 0;\r
1543         protected LockFlags                 _lockFlags = 0;\r
1544         protected bool                      _pendingLockUpgrade = false;\r
1545 \r
1546         /// <summary>\r
1547         /// AttributeInfo で使用されるフラグ。各属性の状態を示す。\r
1548         /// </summary>\r
1549         protected enum AttributeInfoFlags\r
1550         {\r
1551             /// <summary>何もない。</summary>\r
1552             None        = 0,\r
1553             /// <summary>デフォルト値の要求。</summary>\r
1554             Default     = 1 << 0,\r
1555             /// <summary>要求された。</summary>\r
1556             Requested   = 1 << 1\r
1557         }\r
1558 \r
1559         protected struct AttributeInfo\r
1560         {\r
1561             public Guid                 attrID;\r
1562             public AttributeInfoFlags   flags;\r
1563             public VARIANT              currentValue;\r
1564             public VARIANT              defaultValue;\r
1565         }\r
1566 \r
1567         protected AttributeInfo[]       _attributeInfo = new AttributeInfo[1];\r
1568 \r
1569     }\r
1570 }\r