OSDN Git Service

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