1 // TSF のデバッグ表示を行うかどうか?
\r
2 //#define TSF_DEBUG_OUTPUT
\r
4 using System.Collections.Generic;
\r
7 using System.Diagnostics;
\r
8 using System.Reflection;
\r
9 using System.Runtime.CompilerServices;
\r
10 using System.Runtime.InteropServices;
\r
11 using System.Globalization;
\r
13 using DotNetTextStore.UnmanagedAPI.TSF;
\r
14 using DotNetTextStore.UnmanagedAPI.TSF.TextStore;
\r
15 using DotNetTextStore.UnmanagedAPI.WinDef;
\r
16 using DotNetTextStore.UnmanagedAPI.WinError;
\r
18 namespace DotNetTextStore
\r
20 #if TSF_DEBUG_OUTPUT
\r
21 /// <summary>コールスタックの階層にあわせてインデントしてデバッグ表示するクラス。</summary>
\r
22 public class DebugOut : IDisposable
\r
24 public DebugOut(string i_string, params object[] i_params)
\r
26 _text = string.Format(i_string, i_params);
\r
29 Debug.WriteLine("");
\r
30 Debug.WriteLine(string.Format("{0, 4} : ↓↓↓ ", s_callCount) + _text);
\r
33 public void Dispose()
\r
36 Debug.WriteLine(string.Format("{0, 4} : ↑↑↑ ", s_callCount) + _text);
\r
39 public static string GetCaller([CallerMemberName] string caller="")
\r
45 static int s_callCount = 0;
\r
49 //=============================================================================================
\r
52 public struct TextDisplayAttribute
\r
54 public int startIndex;
\r
55 public int endIndex;
\r
56 public TF_DISPLAYATTRIBUTE attribute;
\r
59 //========================================================================================
\r
62 /// <summary>Dispose() で TextStore のロック解除を行うクラス。</summary>
\r
63 public class Unlocker : IDisposable
\r
65 /// <summary>コンストラクタ</summary>
\r
66 public Unlocker(TextStoreBase io_textStore)
\r
68 _textStore = io_textStore;
\r
70 /// <summary>ロックが成功したかどうか調べる。</summary>
\r
71 public bool IsLocked
\r
73 get { return _textStore != null; }
\r
75 /// <summary>アンロックを行う。</summary>
\r
76 void IDisposable.Dispose()
\r
78 if (_textStore != null)
\r
80 _textStore.UnlockDocument();
\r
85 /// <summary>アンロックを行うテキストストア</summary>
\r
86 TextStoreBase _textStore;
\r
89 public abstract class TextStoreBase
\r
91 public delegate bool IsReadOnlyHandler();
\r
92 public event IsReadOnlyHandler IsReadOnly;
\r
94 public delegate bool IsLoadingHandler();
\r
95 public event IsLoadingHandler IsLoading;
\r
97 public delegate int GetStringLengthHandler();
\r
98 public event GetStringLengthHandler GetStringLength;
\r
100 public delegate void GetSelectionIndexHandler(out int o_start, out int o_end);
\r
101 public event GetSelectionIndexHandler GetSelectionIndex;
\r
103 public delegate void SetSelectionIndexHandler(int i_start, int i_end);
\r
104 public event SetSelectionIndexHandler SetSelectionIndex;
\r
106 public delegate string GetStringHandler(int start, int length);
\r
107 public event GetStringHandler GetString;
\r
109 public delegate void InsertAtSelectionHandler(string i_value);
\r
110 public event InsertAtSelectionHandler InsertAtSelection;
\r
112 public delegate void GetScreenExtentHandler(
\r
113 out POINT o_pointTopLeft,
\r
114 out POINT o_pointBottomRight
\r
116 public event GetScreenExtentHandler GetScreenExtent;
\r
118 public delegate void GetStringExtentHandler(
\r
121 out POINT o_pointTopLeft,
\r
122 out POINT o_pointBottomRight
\r
124 public event GetStringExtentHandler GetStringExtent;
\r
126 public delegate bool CompositionStartedHandler();
\r
127 public event CompositionStartedHandler CompositionStarted;
\r
129 public delegate void CompostionUpdateHandler(int start, int end);
\r
130 public event CompostionUpdateHandler CompositionUpdated;
\r
132 public delegate void CompositionEndedHandler();
\r
133 public event CompositionEndedHandler CompositionEnded;
\r
136 public TextStoreBase()
\r
138 #if TSF_DEBUG_OUTPUT
\r
139 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
\r
147 CreateCategoryMgr();
\r
149 CreateDisplayAttributeMgr();
\r
152 _threadMgr.CreateDocumentMgr(out _documentMgr);
\r
154 // スレッドマネージャのアクティブ化
\r
156 _threadMgr.Activate(out clientId);
\r
159 _documentMgr.CreateContext(clientId, 0, this, out _context, out _editCookie);
\r
162 _documentMgr.Push(_context);
\r
164 // ファンクションプロバイダーを取得する。
\r
165 Guid guid = TfDeclarations.GUID_SYSTEM_FUNCTIONPROVIDER;
\r
166 _threadMgr.GetFunctionProvider(ref guid, out _functionProvider);
\r
168 // ITfReconversion オブジェクトを取得する。
\r
169 var guidNull = new Guid();
\r
170 var guidReconversion = new Guid("4cea93c0-0a58-11d3-8df0-00105a2799b5"); //ITfFnReconversionの定義から
\r
171 object reconversion = null;
\r
172 _functionProvider.GetFunction(
\r
174 ref guidReconversion,
\r
177 _reconversion = reconversion as ITfFnReconversion;
\r
181 Guid guidModebiasNone = TfDeclarations.GUID_MODEBIAS_NONE;
\r
182 _categoryMgr.RegisterGUID(ref guidModebiasNone, out guidAtom);
\r
183 _attributeInfo[0].attrID = TfDeclarations.GUID_PROP_MODEBIAS;
\r
184 _attributeInfo[0].flags = AttributeInfoFlags.None;
\r
185 _attributeInfo[0].currentValue.vt = (short)VarEnum.VT_EMPTY;
\r
186 _attributeInfo[0].defaultValue.vt = (short)VarEnum.VT_I4;
\r
187 _attributeInfo[0].defaultValue.data1 = (IntPtr)guidAtom;
\r
189 catch (Exception exception)
\r
191 Debug.WriteLine(exception.Message);
\r
198 /// オブジェクトの破棄を行う。このメソッドは必ず呼び出す必要があります
\r
200 /// <param name="flag"></param>
\r
201 protected void Dispose(bool flag)
\r
205 #if TSF_DEBUG_OUTPUT
\r
206 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
\r
209 ReleaseComObject("_reconversion", ref _reconversion);
\r
210 ReleaseComObject("_functionProvider", ref _functionProvider);
\r
211 ReleaseComObject("_context", ref _context);
\r
212 DestroyDocumentMgr();
\r
213 DestroyDisplayAttributeMgr();
\r
214 DestroyCategoryMgr();
\r
215 DestroyThreadMgr();
\r
217 GC.SuppressFinalize(this);
\r
222 /// スレッドマネージャの生成。このメソッドの実装は必須です
\r
225 /// <exception cref="COMException">
\r
226 /// スレッドマネージャーの生成に失敗した場合。
\r
228 protected virtual void CreateThreadMgr()
\r
230 throw new NotImplementedException();
\r
236 void DestroyThreadMgr()
\r
238 if (_threadMgr != null)
\r
240 try { _threadMgr.Deactivate(); }
\r
241 catch (Exception) { }
\r
243 ReleaseComObject("_threadMgr", ref _threadMgr);
\r
251 /// <exception cref="COMException">
\r
252 /// カテゴリマネージャーの生成に失敗した場合。
\r
254 void CreateCategoryMgr()
\r
256 if (_categoryMgr == null)
\r
258 var clsid = Marshal.GetTypeFromCLSID(TfDeclarations.CLSID_TF_CategoryMgr);
\r
259 _categoryMgr = Activator.CreateInstance(clsid) as ITfCategoryMgr;
\r
261 if (_categoryMgr == null)
\r
263 const string message = "カテゴリマネージャーの生成に失敗しました。";
\r
264 Debug.WriteLine(message);
\r
265 throw new COMException(message, HRESULT.E_NOTIMPL);
\r
273 void DestroyCategoryMgr()
\r
275 ReleaseComObject("_categoryMgr", ref _categoryMgr);
\r
282 /// <exception cref="COMException">
\r
283 /// 表示属性マネージャーの生成に失敗した場合。
\r
285 void CreateDisplayAttributeMgr()
\r
287 if (_displayAttributeMgr == null)
\r
289 var clsid = Marshal.GetTypeFromCLSID(TfDeclarations.CLSID_TF_DisplayAttributeMgr);
\r
290 _displayAttributeMgr = Activator.CreateInstance(clsid) as ITfDisplayAttributeMgr;
\r
292 if (_displayAttributeMgr == null)
\r
294 const string message = "表示属性マネージャーの生成に失敗しました。";
\r
295 Debug.WriteLine(message);
\r
296 throw new COMException(message, HRESULT.E_NOTIMPL);
\r
304 void DestroyDisplayAttributeMgr()
\r
306 ReleaseComObject("_displayAttributeMgr", ref _displayAttributeMgr);
\r
310 /// ドキュメントマネージャーの解放
\r
312 void DestroyDocumentMgr()
\r
314 if (_documentMgr != null)
\r
316 try { _documentMgr.Pop(PopFlags.TF_POPF_ALL); }
\r
317 catch (Exception) { }
\r
319 ReleaseComObject("_documentMgr", ref _documentMgr);
\r
324 /// COM オブジェクトのリリースとデバッグメッセージ出力。
\r
326 protected static void ReleaseComObject<ComObject>(
\r
327 string i_objectName,
\r
328 ref ComObject io_comObject
\r
331 if (io_comObject != null)
\r
333 var refCount = Marshal.ReleaseComObject(io_comObject);
\r
334 #if TSF_DEBUG_OUTPUT
\r
336 "Marshal.ReleaseComObject({0}) returns {1}.",
\r
342 io_comObject = default(ComObject);
\r
347 #region "コントロール側が状況に応じて呼び出さなければいけない TSF に通知を送るメソッド"
\r
349 /// 選択領域が変更されたことをTSFに伝える。各種ハンドラ内からコールしてはいけない。
\r
351 public void NotifySelectionChanged()
\r
353 if( _sink != null )
\r
355 if( (_adviseFlags & AdviseFlags.TS_AS_SEL_CHANGE) != 0 )
\r
356 _sink.OnSelectionChange();
\r
361 //=========================================================================================
\r
365 /// テキストが変更されたことをTSFに伝える。各種ハンドラ内からコールしてはいけない。
\r
367 public void NotifyTextChanged(TS_TEXTCHANGE textChange)
\r
369 if( _sink != null )
\r
371 if( (_adviseFlags & AdviseFlags.TS_AS_TEXT_CHANGE) != 0 )
\r
372 _sink.OnTextChange(0, ref textChange);
\r
373 _sink.OnLayoutChange(TsLayoutCode.TS_LC_CHANGE, 1);
\r
378 //=========================================================================================
\r
381 /// テキストが変更されたことをTSFに伝える。各種ハンドラ内からコールしてはいけない。
\r
383 /// <param name="start">開始位置</param>
\r
384 /// <param name="oldend">更新前の終了位置</param>
\r
385 /// <param name="newend">更新後の終了位置</param>
\r
387 /// 詳しいことはITextStoreACPSink::OnTextChangeを参照してください
\r
389 public void NotifyTextChanged(int start,int oldend,int newend)
\r
393 if ((_adviseFlags & AdviseFlags.TS_AS_TEXT_CHANGE) != 0)
\r
395 var textChange = new TS_TEXTCHANGE();
\r
396 textChange.start = start;
\r
397 textChange.oldEnd = oldend;
\r
398 textChange.newEnd = newend;
\r
400 _sink.OnTextChange(0, ref textChange);
\r
402 _sink.OnLayoutChange(TsLayoutCode.TS_LC_CHANGE, 1);
\r
407 /// テキストが変更されたことをTSFに伝える。各種ハンドラ内からコールしてはいけない。
\r
409 /// <param name="i_oldLength"></param>
\r
410 /// <param name="i_newLength"></param>
\r
411 public void NotifyTextChanged(int i_oldLength, int i_newLength)
\r
413 if( _sink != null )
\r
415 if( (_adviseFlags & AdviseFlags.TS_AS_TEXT_CHANGE) != 0 )
\r
417 var textChange = new TS_TEXTCHANGE();
\r
418 textChange.start = 0;
\r
419 textChange.oldEnd = i_oldLength;
\r
420 textChange.newEnd = i_newLength;
\r
422 _sink.OnTextChange(0, ref textChange);
\r
424 _sink.OnLayoutChange(TsLayoutCode.TS_LC_CHANGE, 1);
\r
430 //=========================================================================================
\r
433 /// <summary>コントロールがフォーカスを取得した時に呼び出さなければいけない。</summary>
\r
434 public void SetFocus()
\r
436 if (_threadMgr != null)
\r
437 _threadMgr.SetFocus(_documentMgr);
\r
439 #endregion "コントロール側が状況に応じて呼び出さなければいけない TSF に通知を送るメソッド"
\r
445 /// <param name="i_writable">読み書き両用ロックか?false の場合、読み取り専用。</param>
\r
446 /// <returns>Unlocker のインスタンスを返す。失敗した場合 null を返す。</returns>
\r
447 public Unlocker LockDocument(bool i_writable)
\r
449 #if TSF_DEBUG_OUTPUT
\r
450 using(var dbgout = new DebugOut("{0}({1})", DebugOut.GetCaller(),
\r
456 if( this._lockFlags == 0 )
\r
459 this._lockFlags = LockFlags.TS_LF_READWRITE;
\r
461 this._lockFlags = LockFlags.TS_LF_READ;
\r
463 #if TSF_DEBUG_OUTPUT
\r
464 Debug.WriteLine("LockDocument is succeeded.");
\r
467 return new Unlocker(this);
\r
471 #if TSF_DEBUG_OUTPUT
\r
472 Debug.WriteLine("LockDocument is failed. {0}", _lockFlags);
\r
482 //========================================================================================
\r
488 /// <param name="i_writable">読み書き両用ロックか?false の場合、読み取り専用。</param>
\r
489 /// <returns>Unlocker のインスタンスを返す。失敗した場合 null を返す。</returns>
\r
490 public Unlocker LockDocument(LockFlags i_flags)
\r
492 #if TSF_DEBUG_OUTPUT
\r
493 using(var dbgout = new DebugOut("{0}({1})", DebugOut.GetCaller(),
\r
499 if( this._lockFlags == 0 )
\r
501 this._lockFlags = i_flags;
\r
503 #if TSF_DEBUG_OUTPUT
\r
504 Debug.WriteLine("LockDocument is succeeded.");
\r
507 return new Unlocker(this);
\r
511 #if TSF_DEBUG_OUTPUT
\r
512 Debug.WriteLine("LockDocument is failed. {0}", _lockFlags);
\r
522 //========================================================================================
\r
526 /// ドキュメントのアンロックを行う。
\r
528 public void UnlockDocument()
\r
530 #if TSF_DEBUG_OUTPUT
\r
531 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
\r
539 if( _pendingLockUpgrade )
\r
541 _pendingLockUpgrade = false;
\r
543 RequestLock(LockFlags.TS_LF_READWRITE, out sessionResult);
\r
549 //========================================================================================
\r
553 /// 指定されたフラグでロックしている状態かどうか調べる。
\r
555 /// <param name="i_lockFlags"></param>
\r
556 /// <returns>ロックされている場合は true, されていない場合は false を返す。</returns>
\r
557 public bool IsLocked(LockFlags i_lockFlags)
\r
559 #if TSF_DEBUG_OUTPUT
\r
560 using(var dbgout = new DebugOut("{0}({1})",
\r
561 DebugOut.GetCaller(), i_lockFlags) )
\r
564 #if TSF_DEBUG_OUTPUT
\r
566 "IsLocked() returns " + ((this._lockFlags & i_lockFlags) == i_lockFlags)
\r
569 return (this._lockFlags & i_lockFlags) == i_lockFlags;
\r
576 /// <returns>ロックされているなら真、そうでなければ偽を返す</returns>
\r
577 public bool IsLocked()
\r
579 #if TSF_DEBUG_OUTPUT
\r
580 using(var dbgout = new DebugOut("{0}",
\r
581 DebugOut.GetCaller()) )
\r
584 bool retval = this._lockFlags != 0;
\r
585 #if TSF_DEBUG_OUTPUT
\r
587 "IsLocked() returns " + retval
\r
595 #region ITextStroeACP,ITextStoreACP2の共通部分
\r
600 public void InsertTextAtSelection(string s)
\r
602 TS_TEXTCHANGE textChange = new TS_TEXTCHANGE();
\r
604 using (var unlocker = LockDocument(true))
\r
606 if (unlocker != null)
\r
608 int startIndex, endIndex;
\r
610 InsertTextAtSelection(
\r
611 UnmanagedAPI.TSF.TextStore.InsertAtSelectionFlags.TF_IAS_NOQUERY,
\r
621 // シンクの OnSelectionChange() をコール。
\r
622 NotifySelectionChanged();
\r
623 NotifyTextChanged(textChange);
\r
626 public void InsertEmbeddedAtSelection(
\r
627 InsertAtSelectionFlags flags,
\r
631 out TS_TEXTCHANGE change
\r
634 #if TSF_DEBUG_OUTPUT
\r
635 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
\r
638 throw new NotImplementedException();
\r
642 public void AdviseSink(ref Guid i_riid, object i_unknown, AdviseFlags i_mask)
\r
644 #if TSF_DEBUG_OUTPUT
\r
645 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
\r
648 if (i_riid != new Guid("22d44c94-a419-4542-a272-ae26093ececf")) //ITextStoreACPSinkの定義より
\r
650 throw new COMException(
\r
651 "ITextStoreACPSink 以外のIIDが渡されました。",
\r
652 UnmanagedAPI.WinError.HRESULT.E_INVALIDARG
\r
657 if (_sink == i_unknown)
\r
659 _adviseFlags = i_mask;
\r
662 else if (_sink != null)
\r
664 throw new COMException(
\r
666 UnmanagedAPI.TSF.TextStore.TsResult.CONNECT_E_ADVISELIMIT
\r
672 _services = (ITextStoreACPServices)i_unknown;
\r
673 _sink = (ITextStoreACPSink)i_unknown;
\r
674 _adviseFlags = i_mask;
\r
679 public void UnadviseSink(object i_unknown)
\r
681 #if TSF_DEBUG_OUTPUT
\r
682 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
\r
685 if (_sink == null || _sink != i_unknown)
\r
687 throw new COMException(
\r
689 UnmanagedAPI.TSF.TextStore.TsResult.CONNECT_E_NOCONNECTION
\r
699 public void RequestLock(LockFlags i_lockFlags, out int o_sessionResult)
\r
701 #if TSF_DEBUG_OUTPUT
\r
702 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
\r
705 o_sessionResult = UnmanagedAPI.WinError.HRESULT.E_FAIL;
\r
709 throw new COMException(
\r
711 UnmanagedAPI.TSF.TextStore.TsResult.CONNECT_E_NOCONNECTION
\r
715 if (_lockFlags != 0) // すでにロックされた状態の場合。
\r
717 if ((i_lockFlags & LockFlags.TS_LF_SYNC) != 0)
\r
719 o_sessionResult = TsResult.TS_E_SYNCHRONOUS;
\r
723 if ((_lockFlags & LockFlags.TS_LF_READWRITE) == LockFlags.TS_LF_READ
\r
724 && (i_lockFlags & LockFlags.TS_LF_READWRITE) == LockFlags.TS_LF_READWRITE)
\r
726 _pendingLockUpgrade = true;
\r
727 o_sessionResult = TsResult.TS_S_ASYNC;
\r
731 throw new COMException();
\r
734 using (var unlocker = LockDocument(i_lockFlags))
\r
736 // ロックに失敗した場合は TS_E_SYNCHRONOUS をセットして S_OK を返す。
\r
737 if (unlocker == null)
\r
739 o_sessionResult = TsResult.TS_E_SYNCHRONOUS;
\r
741 // ロックに成功した場合は OnLockGranted() を呼び出す。
\r
746 o_sessionResult = _sink.OnLockGranted(i_lockFlags);
\r
748 catch (COMException comException)
\r
750 Debug.WriteLine("OnLockGranted() 呼び出し中に例外が発生。");
\r
751 Debug.WriteLine(" " + comException.Message);
\r
752 o_sessionResult = comException.HResult;
\r
754 catch (Exception exception)
\r
756 Debug.WriteLine("OnLockGranted() 呼び出し中に例外が発生。");
\r
757 Debug.WriteLine(" " + exception.Message);
\r
764 public void GetStatus(out TS_STATUS o_documentStatus)
\r
766 #if TSF_DEBUG_OUTPUT
\r
767 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
\r
770 if (IsReadOnly != null && IsReadOnly())
\r
771 o_documentStatus.dynamicFlags = DynamicStatusFlags.TS_SD_READONLY;
\r
772 if (IsLoading != null && IsLoading())
\r
773 o_documentStatus.dynamicFlags = DynamicStatusFlags.TS_SD_LOADING;
\r
775 o_documentStatus.dynamicFlags = 0;
\r
776 o_documentStatus.staticFlags = StaticStatusFlags.TS_SS_REGIONS;
\r
780 public void QueryInsert(
\r
784 out int o_startIndex,
\r
788 #if TSF_DEBUG_OUTPUT
\r
789 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
\r
792 if (GetStringLength == null)
\r
793 throw new NotImplementedException();
\r
795 if (i_startIndex < 0
\r
796 || i_startIndex > i_endIndex
\r
797 || i_endIndex > GetStringLength())
\r
799 throw new COMException(
\r
801 UnmanagedAPI.WinError.HRESULT.E_INVALIDARG
\r
805 o_startIndex = i_startIndex;
\r
806 o_endIndex = i_endIndex;
\r
810 public void GetSelection(
\r
812 int i_selectionBufferLength,
\r
813 TS_SELECTION_ACP[] o_selections,
\r
814 out int o_fetchedLength
\r
817 #if TSF_DEBUG_OUTPUT
\r
818 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
\r
821 if (GetSelectionIndex == null)
\r
822 throw new NotImplementedException();
\r
824 o_fetchedLength = 0;
\r
826 if (IsLocked(LockFlags.TS_LF_READ) == false)
\r
828 throw new COMException(
\r
830 TsResult.TS_E_NOLOCK
\r
834 // -1 は TF_DEFAULT_SELECTION。選択は1つだけしかサポートしないので、
\r
835 // TF_DEFAULT_SELECTION でもなく、0 を超える数値が指定された場合はエラー。
\r
836 if (i_index != -1 && i_index > 0)
\r
838 throw new COMException(
\r
839 "選択は1つだけしかサポートしていません。",
\r
840 UnmanagedAPI.WinError.HRESULT.E_INVALIDARG
\r
844 if (i_selectionBufferLength > 0)
\r
846 int start = 0, end = 0;
\r
847 GetSelectionIndex(out start, out end);
\r
850 o_selections[0].start = start;
\r
851 o_selections[0].end = end;
\r
852 o_selections[0].style.ase = TsActiveSelEnd.TS_AE_END;
\r
853 o_selections[0].style.interimChar = false;
\r
857 o_selections[0].start = end;
\r
858 o_selections[0].end = start;
\r
859 o_selections[0].style.ase = TsActiveSelEnd.TS_AE_START;
\r
860 o_selections[0].style.interimChar = false;
\r
863 o_fetchedLength = 1;
\r
868 public void SetSelection(int i_count, TS_SELECTION_ACP[] i_selections)
\r
870 #if TSF_DEBUG_OUTPUT
\r
871 using(var dbgout = new DebugOut("{0}({1}, {2})",
\r
872 DebugOut.GetCaller(),
\r
873 i_selections[0].start,
\r
874 i_selections[0].end))
\r
877 if (SetSelectionIndex == null)
\r
878 throw new NotImplementedException();
\r
882 throw new COMException(
\r
883 "選択は1つだけしかサポートしていません。",
\r
884 UnmanagedAPI.WinError.HRESULT.E_INVALIDARG
\r
888 if (IsLocked(LockFlags.TS_LF_READWRITE) == false)
\r
890 throw new COMException(
\r
892 TsResult.TS_E_NOLOCK
\r
896 SetSelectionIndex(i_selections[0].start, i_selections[0].end);
\r
900 public void GetText(
\r
903 char[] o_plainText,
\r
904 int i_plainTextLength,
\r
905 out int o_plainTextLength,
\r
906 TS_RUNINFO[] o_runInfos,
\r
907 int i_runInfoLength,
\r
908 out int o_runInfoLength,
\r
909 out int o_nextUnreadCharPos
\r
912 #if TSF_DEBUG_OUTPUT
\r
913 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
\r
916 if (GetStringLength == null || GetString == null)
\r
917 throw new NotImplementedException();
\r
919 if (IsLocked(LockFlags.TS_LF_READ) == false)
\r
921 throw new COMException(
\r
923 TsResult.TS_E_NOLOCK
\r
927 if ((i_endIndex != -1 && i_startIndex > i_endIndex)
\r
928 || i_startIndex < 0 || i_startIndex > GetStringLength()
\r
929 || i_endIndex > GetStringLength())
\r
931 throw new COMException(
\r
933 UnmanagedAPI.WinError.HRESULT.E_INVALIDARG
\r
937 var textLength = 0;
\r
938 var copyLength = 0;
\r
940 if (i_endIndex == -1)
\r
941 textLength = GetStringLength() - i_startIndex;
\r
943 textLength = i_endIndex - i_startIndex;
\r
944 copyLength = Math.Min(i_plainTextLength, textLength);
\r
947 var text = GetString(i_startIndex, copyLength);
\r
948 for (int i = 0; i < copyLength; i++)
\r
950 o_plainText[i] = text[i];
\r
954 o_plainTextLength = copyLength;
\r
956 if (i_runInfoLength > 0)
\r
958 o_runInfos[0].type = TsRunType.TS_RT_PLAIN;
\r
959 o_runInfos[0].length = copyLength;
\r
961 o_runInfoLength = 1;
\r
964 o_nextUnreadCharPos = i_startIndex + copyLength;
\r
968 public void SetText(
\r
969 SetTextFlags i_flags,
\r
974 out TS_TEXTCHANGE o_textChange
\r
977 #if TSF_DEBUG_OUTPUT
\r
978 using(var dbgout = new DebugOut("{0}({1}, {2})",
\r
979 DebugOut.GetCaller(),
\r
980 i_startIndex, i_endIndex) )
\r
983 var selections = new TS_SELECTION_ACP[]
\r
985 new TS_SELECTION_ACP
\r
987 start = i_startIndex,
\r
989 style = new TS_SELECTIONSTYLE
\r
991 ase = TsActiveSelEnd.TS_AE_END,
\r
992 interimChar = false
\r
997 int startIndex = 0, endIndex = 0;
\r
998 SetSelection(1, selections);
\r
999 InsertTextAtSelection(
\r
1000 InsertAtSelectionFlags.TF_IAS_NOQUERY,
\r
1010 public void GetFormattedText(int i_start, int i_end, out object o_obj)
\r
1012 #if TSF_DEBUG_OUTPUT
\r
1013 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
\r
1016 throw new NotImplementedException();
\r
1020 public void GetEmbedded(
\r
1022 ref Guid i_guidService,
\r
1027 #if TSF_DEBUG_OUTPUT
\r
1028 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
\r
1031 throw new NotImplementedException();
\r
1035 public void QueryInsertEmbedded(
\r
1036 ref Guid i_guidService,
\r
1038 out bool o_insertable
\r
1041 #if TSF_DEBUG_OUTPUT
\r
1042 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
\r
1045 throw new NotImplementedException();
\r
1049 public void InsertEmbedded(
\r
1050 InsertEmbeddedFlags i_flags,
\r
1054 out TS_TEXTCHANGE o_textChange
\r
1057 #if TSF_DEBUG_OUTPUT
\r
1058 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
\r
1061 throw new NotImplementedException();
\r
1065 public void InsertTextAtSelection(
\r
1066 InsertAtSelectionFlags i_flags,
\r
1069 out int o_startIndex,
\r
1070 out int o_endIndex,
\r
1071 out TS_TEXTCHANGE o_textChange
\r
1074 #if TSF_DEBUG_OUTPUT
\r
1075 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
\r
1078 if (GetSelectionIndex == null || InsertAtSelection == null)
\r
1079 throw new NotImplementedException();
\r
1081 int selectionStart = 0, selectionEnd = 0;
\r
1082 GetSelectionIndex(out selectionStart, out selectionEnd);
\r
1084 // 問い合わせのみで実際には操作を行わない
\r
1085 if ((i_flags & InsertAtSelectionFlags.TF_IAS_QUERYONLY) != 0)
\r
1087 o_startIndex = Math.Min(selectionStart, selectionEnd);
\r
1088 o_endIndex = Math.Max(selectionStart, selectionEnd);//o_startIndex + i_length;
\r
1090 o_textChange.start = o_startIndex;
\r
1091 o_textChange.oldEnd = o_endIndex;
\r
1092 o_textChange.newEnd = o_startIndex + i_length;
\r
1096 var start = Math.Min(selectionStart, selectionEnd);
\r
1097 var end = Math.Max(selectionStart, selectionEnd);
\r
1099 #if TSF_DEBUG_OUTPUT
\r
1100 Debug.WriteLine(string.Format(
\r
1101 "start: {0}, end: {1}, text: {2}",
\r
1102 start, end, new string(i_text)
\r
1106 InsertAtSelection(new string(i_text));
\r
1108 o_startIndex = start;
\r
1109 o_endIndex = start + i_length;
\r
1111 o_textChange.start = start;
\r
1112 o_textChange.oldEnd = end;
\r
1113 o_textChange.newEnd = start + i_length;
\r
1115 // InsertAtSelection() 内でカーソル位置を更新しているため、ここでは不要。
\r
1117 // SetSelectionIndex(start, start + i_length);
\r
1122 public void GetEndACP(out int o_length)
\r
1124 #if TSF_DEBUG_OUTPUT
\r
1125 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
\r
1128 if (GetStringLength == null)
\r
1129 throw new NotImplementedException();
\r
1131 if (IsLocked(LockFlags.TS_LF_READ) == false)
\r
1133 throw new COMException(
\r
1134 "読取用ロックがされていません。",
\r
1135 TsResult.TS_E_NOLOCK
\r
1139 o_length = GetStringLength();
\r
1143 public void GetActiveView(out int o_viewCookie)
\r
1145 #if TSF_DEBUG_OUTPUT
\r
1146 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
\r
1153 public void GetACPFromPoint(
\r
1155 ref POINT i_point,
\r
1156 GetPositionFromPointFlags i_flags,
\r
1160 #if TSF_DEBUG_OUTPUT
\r
1161 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
\r
1164 throw new NotImplementedException();
\r
1168 public void GetTextExt(
\r
1173 out bool o_isClipped
\r
1176 #if TSF_DEBUG_OUTPUT
\r
1177 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
\r
1180 if (GetStringLength == null)
\r
1181 throw new NotImplementedException();
\r
1184 if (IsLocked(LockFlags.TS_LF_READ) == false)
\r
1186 throw new COMException(
\r
1187 "読取用ロックがされていません。",
\r
1188 TsResult.TS_E_NOLOCK
\r
1192 if ((i_endIndex != -1 && i_startIndex > i_endIndex)
\r
1193 || i_startIndex < 0 || i_startIndex > GetStringLength()
\r
1194 || i_endIndex > GetStringLength())
\r
1196 throw new COMException(
\r
1198 UnmanagedAPI.WinError.HRESULT.E_INVALIDARG
\r
1202 if (i_endIndex == -1)
\r
1203 i_endIndex = GetStringLength();
\r
1205 var pointTopLeft = new POINT();
\r
1206 var pointBotttomRight = new POINT();
\r
1207 GetStringExtent(i_startIndex, i_endIndex, out pointTopLeft, out pointBotttomRight);
\r
1209 o_rect.left = (int)pointTopLeft.x;
\r
1210 o_rect.top = (int)pointTopLeft.y;
\r
1211 o_rect.bottom = (int)pointBotttomRight.y;//startFormattedText.Height);
\r
1212 o_rect.right = (int)pointBotttomRight.x;
\r
1213 o_isClipped = false;
\r
1217 public void GetScreenExt(int i_viewCookie, out RECT o_rect)
\r
1219 #if TSF_DEBUG_OUTPUT
\r
1220 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
\r
1223 if (GetScreenExtent == null)
\r
1224 throw new NotImplementedException();
\r
1226 POINT pointTopLeft, pointBottomRight;
\r
1228 GetScreenExtent(out pointTopLeft, out pointBottomRight);
\r
1230 o_rect.left = (int)pointTopLeft.x;
\r
1231 o_rect.top = (int)pointTopLeft.y;
\r
1232 o_rect.right = (int)pointBottomRight.x;
\r
1233 o_rect.bottom = (int)pointBottomRight.y;
\r
1237 public void RequestSupportedAttrs(
\r
1238 AttributeFlags i_flags,
\r
1240 Guid[] i_filterAttributes
\r
1243 #if TSF_DEBUG_OUTPUT
\r
1244 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
\r
1247 for (int i = 0; i < i_length; i++)
\r
1249 if (i_filterAttributes[i].Equals(_attributeInfo[0].attrID))
\r
1251 _attributeInfo[0].flags = AttributeInfoFlags.Requested;
\r
1252 if ((i_flags & AttributeFlags.TS_ATTR_FIND_WANT_VALUE) != 0)
\r
1254 _attributeInfo[0].flags |= AttributeInfoFlags.Default;
\r
1258 _attributeInfo[0].currentValue = _attributeInfo[0].defaultValue;
\r
1265 public void RequestAttrsAtPosition(
\r
1268 Guid[] i_filterAttributes,
\r
1269 AttributeFlags i_flags
\r
1272 #if TSF_DEBUG_OUTPUT
\r
1273 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
\r
1276 for (int i = 0; i < i_length; i++)
\r
1278 if (i_filterAttributes[i].Equals(_attributeInfo[0].attrID))
\r
1280 _attributeInfo[0].flags = AttributeInfoFlags.Requested;
\r
1281 if ((i_flags & AttributeFlags.TS_ATTR_FIND_WANT_VALUE) != 0)
\r
1283 _attributeInfo[0].flags |= AttributeInfoFlags.Default;
\r
1287 _attributeInfo[0].currentValue = _attributeInfo[0].defaultValue;
\r
1294 public void RequestAttrsTransitioningAtPosition(
\r
1297 Guid[] i_filterAttributes,
\r
1298 AttributeFlags i_flags
\r
1301 #if TSF_DEBUG_OUTPUT
\r
1302 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()))
\r
1309 public void FindNextAttrTransition(
\r
1313 Guid[] i_filterAttributes,
\r
1314 AttributeFlags i_flags,
\r
1315 out int o_nextIndex,
\r
1317 out int o_foundOffset
\r
1320 #if TSF_DEBUG_OUTPUT
\r
1321 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
\r
1324 throw new NotImplementedException();
\r
1328 public void RetrieveRequestedAttrs(
\r
1330 TS_ATTRVAL[] o_attributeVals,
\r
1331 out int o_fetchedLength
\r
1334 #if TSF_DEBUG_OUTPUT
\r
1335 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
\r
1338 o_fetchedLength = 0;
\r
1339 for (int i = 0; i < _attributeInfo.Length && o_fetchedLength < i_length; i++)
\r
1341 if ((_attributeInfo[i].flags & AttributeInfoFlags.Requested) != 0)
\r
1343 o_attributeVals[o_fetchedLength].overlappedId = 0;
\r
1344 o_attributeVals[o_fetchedLength].attributeId = _attributeInfo[i].attrID;
\r
1345 o_attributeVals[o_fetchedLength].val = _attributeInfo[i].currentValue;
\r
1347 if ((_attributeInfo[i].flags & AttributeInfoFlags.Default) != 0)
\r
1348 _attributeInfo[i].currentValue = _attributeInfo[i].defaultValue;
\r
1350 o_fetchedLength++;
\r
1351 _attributeInfo[i].flags = AttributeInfoFlags.None;
\r
1358 #region "ITfContextOwnerCompositionSink インターフェイスの実装"
\r
1359 /// <summary>コンポジション入力が開始された時の処理。</summary>
\r
1360 public void OnStartComposition(ITfCompositionView view, out bool ok)
\r
1362 #if TSF_DEBUG_OUTPUT
\r
1363 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
\r
1366 if( CompositionStarted != null )
\r
1367 ok = CompositionStarted();
\r
1374 //========================================================================================
\r
1377 /// <summary>コンポジションが変更された時の処理。</summary>
\r
1378 public void OnUpdateComposition(ITfCompositionView view, ITfRange rangeNew)
\r
1380 #if TSF_DEBUG_OUTPUT
\r
1381 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
\r
1384 if (rangeNew == null)
\r
1389 ITfRangeACP rangeAcp = (ITfRangeACP)rangeNew;
\r
1391 rangeAcp.GetExtent(out start, out count);
\r
1393 if (this.CompositionUpdated != null)
\r
1394 this.CompositionUpdated(start, start + count);
\r
1399 //========================================================================================
\r
1402 /// <summary>コンポジション入力が終了した時の処理。</summary>
\r
1403 public void OnEndComposition(ITfCompositionView view)
\r
1405 #if TSF_DEBUG_OUTPUT
\r
1406 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
\r
1409 if( CompositionEnded != null )
\r
1410 CompositionEnded();
\r
1413 #endregion "ITfContextOwnerCompositionSink インターフェイスの実装"
\r
1416 /// <summary>表示属性の取得</summary>
\r
1417 public IEnumerable<TextDisplayAttribute> EnumAttributes(int start, int end)
\r
1419 ITfRangeACP allRange;
\r
1420 _services.CreateRange(start, end, out allRange);
\r
1422 foreach (TextDisplayAttribute attr in this.EnumAttributes((ITfRange)allRange))
\r
1423 yield return attr;
\r
1425 ReleaseComObject("allRange", ref allRange);
\r
1428 IEnumerable<TextDisplayAttribute> EnumAttributes(ITfRange range)
\r
1430 #if TSF_DEBUG_OUTPUT
\r
1431 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()))
\r
1434 ITfProperty property = null; // プロパティインターフェイス
\r
1435 IEnumTfRanges enumRanges; // 範囲の列挙子
\r
1436 Guid guidPropAttribute = TfDeclarations.GUID_PROP_ATTRIBUTE;
\r
1438 if (_context == null || _services == null)
\r
1441 // GUID_PROP_ATTRIBUTE プロパティを取得。
\r
1442 _context.GetProperty(ref guidPropAttribute, out property);
\r
1443 if (property == null)
\r
1446 // 全範囲の中で表示属性プロパティをもつ範囲を列挙する。
\r
1447 property.EnumRanges((int)_editCookie, out enumRanges, range);
\r
1449 ITfRange[] ranges = new ITfRange[1];
\r
1450 int fetchedLength = 0;
\r
1451 while (HRESULT.Succeeded(enumRanges.Next(1, ranges, out fetchedLength))
\r
1452 && fetchedLength > 0)
\r
1454 // ItfRange から ItfRangeACP を取得。
\r
1455 ITfRangeACP rangeACP = ranges[0] as ITfRangeACP;
\r
1456 if (rangeACP == null)
\r
1457 continue; // 普通はあり得ない
\r
1459 // 範囲の開始位置と文字数を取得。
\r
1461 rangeACP.GetExtent(out start, out count);
\r
1463 // VARIANT 値としてプロパティ値を取得。VT_I4 の GUID ATOM がとれる。
\r
1464 VARIANT value = new VARIANT();
\r
1465 property.GetValue((int)_editCookie, ranges[0], ref value);
\r
1466 if (value.vt == (short)VarEnum.VT_I4)
\r
1469 ITfDisplayAttributeInfo info;
\r
1470 TF_DISPLAYATTRIBUTE attribute;
\r
1472 // GUID ATOM から GUID を取得する。
\r
1473 _categoryMgr.GetGUID((int)value.data1, out guid);
\r
1474 // その GUID から IDisplayAttributeInfo インターフェイスを取得。
\r
1475 _displayAttributeMgr.GetDisplayAttributeInfo(
\r
1480 // さらに IDisplayAttributeInfo インターフェイスから表示属性を取得する。
\r
1481 info.GetAttributeInfo(out attribute);
\r
1482 ReleaseComObject("info", ref info);
\r
1484 yield return new TextDisplayAttribute
\r
1486 startIndex = start,
\r
1487 endIndex = start + count,
\r
1488 attribute = attribute
\r
1491 #if TSF_DEBUG_OUTPUT
\r
1493 "*******:::: DisplayAttribute: {0} ~ {1} :::::: *********",
\r
1494 start, start + count
\r
1496 Debug.WriteLine(attribute.bAttr);
\r
1498 "LineColorType: {0}, {1}",
\r
1499 attribute.crLine.type, attribute.crLine.indexOrColorRef
\r
1502 "TextColorType: {0}, {1}",
\r
1503 attribute.crText.type, attribute.crText.indexOrColorRef
\r
1506 "BackColorType: {0}, {1}",
\r
1507 attribute.crBk.type, attribute.crBk.indexOrColorRef
\r
1510 "Bold, Style : {0}, {1}",
\r
1511 attribute.fBoldLine, attribute.lsStyle
\r
1516 ReleaseComObject("rangeACP", ref rangeACP);
\r
1519 ReleaseComObject("ranges[0]", ref ranges[0]);
\r
1520 ReleaseComObject("enumRanges", ref enumRanges);
\r
1521 ReleaseComObject("property", ref property);
\r
1527 protected ITfThreadMgr2 _threadMgr;
\r
1529 protected ITfThreadMgr _threadMgr;
\r
1531 protected ITfDocumentMgr _documentMgr;
\r
1532 protected ITfFunctionProvider _functionProvider;
\r
1533 protected ITfFnReconversion _reconversion;
\r
1534 protected ITfContext _context;
\r
1535 protected ITfCategoryMgr _categoryMgr;
\r
1536 protected ITfDisplayAttributeMgr _displayAttributeMgr;
\r
1537 protected ITextStoreACPSink _sink;
\r
1538 protected uint _editCookie = 0;
\r
1539 protected ITextStoreACPServices _services;
\r
1540 protected AdviseFlags _adviseFlags = 0;
\r
1541 protected LockFlags _lockFlags = 0;
\r
1542 protected bool _pendingLockUpgrade = false;
\r
1545 /// AttributeInfo で使用されるフラグ。各属性の状態を示す。
\r
1547 protected enum AttributeInfoFlags
\r
1549 /// <summary>何もない。</summary>
\r
1551 /// <summary>デフォルト値の要求。</summary>
\r
1553 /// <summary>要求された。</summary>
\r
1554 Requested = 1 << 1
\r
1557 protected struct AttributeInfo
\r
1559 public Guid attrID;
\r
1560 public AttributeInfoFlags flags;
\r
1561 public VARIANT currentValue;
\r
1562 public VARIANT defaultValue;
\r
1565 protected AttributeInfo[] _attributeInfo = new AttributeInfo[1];
\r