OSDN Git Service

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