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 int documentLength = GetStringLength();
\r
797 if (i_startIndex < 0
\r
798 || i_startIndex > i_endIndex
\r
799 || i_endIndex > documentLength)
\r
801 throw new COMException(
\r
803 UnmanagedAPI.WinError.HRESULT.E_INVALIDARG
\r
807 o_startIndex = i_startIndex;
\r
808 o_endIndex = i_endIndex;
\r
812 public void GetSelection(
\r
814 int i_selectionBufferLength,
\r
815 TS_SELECTION_ACP[] o_selections,
\r
816 out int o_fetchedLength
\r
819 #if TSF_DEBUG_OUTPUT
\r
820 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
\r
823 if (GetSelectionIndex == null)
\r
824 throw new NotImplementedException();
\r
826 o_fetchedLength = 0;
\r
828 if (IsLocked(LockFlags.TS_LF_READ) == false)
\r
830 throw new COMException(
\r
832 TsResult.TS_E_NOLOCK
\r
836 // -1 は TF_DEFAULT_SELECTION。選択は1つだけしかサポートしないので、
\r
837 // TF_DEFAULT_SELECTION でもなく、0 を超える数値が指定された場合はエラー。
\r
838 if (i_index != -1 && i_index > 0)
\r
840 throw new COMException(
\r
841 "選択は1つだけしかサポートしていません。",
\r
842 UnmanagedAPI.WinError.HRESULT.E_INVALIDARG
\r
846 if (i_selectionBufferLength > 0)
\r
848 int start = 0, end = 0;
\r
849 GetSelectionIndex(out start, out end);
\r
852 o_selections[0].start = start;
\r
853 o_selections[0].end = end;
\r
854 o_selections[0].style.ase = TsActiveSelEnd.TS_AE_END;
\r
855 o_selections[0].style.interimChar = false;
\r
859 o_selections[0].start = end;
\r
860 o_selections[0].end = start;
\r
861 o_selections[0].style.ase = TsActiveSelEnd.TS_AE_START;
\r
862 o_selections[0].style.interimChar = false;
\r
865 o_fetchedLength = 1;
\r
870 public void SetSelection(int i_count, TS_SELECTION_ACP[] i_selections)
\r
872 #if TSF_DEBUG_OUTPUT
\r
873 using(var dbgout = new DebugOut("{0}({1}, {2})",
\r
874 DebugOut.GetCaller(),
\r
875 i_selections[0].start,
\r
876 i_selections[0].end))
\r
879 if (SetSelectionIndex == null)
\r
880 throw new NotImplementedException();
\r
884 throw new COMException(
\r
885 "選択は1つだけしかサポートしていません。",
\r
886 UnmanagedAPI.WinError.HRESULT.E_INVALIDARG
\r
890 if (IsLocked(LockFlags.TS_LF_READWRITE) == false)
\r
892 throw new COMException(
\r
894 TsResult.TS_E_NOLOCK
\r
898 SetSelectionIndex(i_selections[0].start, i_selections[0].end);
\r
902 public void GetText(
\r
905 char[] o_plainText,
\r
906 int i_plainTextLength,
\r
907 out int o_plainTextLength,
\r
908 TS_RUNINFO[] o_runInfos,
\r
909 int i_runInfoLength,
\r
910 out int o_runInfoLength,
\r
911 out int o_nextUnreadCharPos
\r
914 #if TSF_DEBUG_OUTPUT
\r
915 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
\r
918 if (GetStringLength == null || GetString == null)
\r
919 throw new NotImplementedException();
\r
921 if (IsLocked(LockFlags.TS_LF_READ) == false)
\r
923 throw new COMException(
\r
925 TsResult.TS_E_NOLOCK
\r
929 if ((i_endIndex != -1 && i_startIndex > i_endIndex)
\r
930 || i_startIndex < 0 || i_startIndex > GetStringLength()
\r
931 || i_endIndex > GetStringLength())
\r
933 throw new COMException(
\r
935 UnmanagedAPI.WinError.HRESULT.E_INVALIDARG
\r
939 var textLength = 0;
\r
940 var copyLength = 0;
\r
942 if (i_endIndex == -1)
\r
943 textLength = GetStringLength() - i_startIndex;
\r
945 textLength = i_endIndex - i_startIndex;
\r
946 copyLength = Math.Min(i_plainTextLength, textLength);
\r
949 var text = GetString(i_startIndex, copyLength);
\r
950 for (int i = 0; i < copyLength; i++)
\r
952 o_plainText[i] = text[i];
\r
956 o_plainTextLength = copyLength;
\r
958 if (i_runInfoLength > 0)
\r
960 o_runInfos[0].type = TsRunType.TS_RT_PLAIN;
\r
961 o_runInfos[0].length = copyLength;
\r
963 o_runInfoLength = 1;
\r
966 o_nextUnreadCharPos = i_startIndex + copyLength;
\r
970 public void SetText(
\r
971 SetTextFlags i_flags,
\r
976 out TS_TEXTCHANGE o_textChange
\r
979 #if TSF_DEBUG_OUTPUT
\r
980 using(var dbgout = new DebugOut("{0}({1}, {2})",
\r
981 DebugOut.GetCaller(),
\r
982 i_startIndex, i_endIndex) )
\r
985 var selections = new TS_SELECTION_ACP[]
\r
987 new TS_SELECTION_ACP
\r
989 start = i_startIndex,
\r
991 style = new TS_SELECTIONSTYLE
\r
993 ase = TsActiveSelEnd.TS_AE_END,
\r
994 interimChar = false
\r
999 int startIndex = 0, endIndex = 0;
\r
1000 SetSelection(1, selections);
\r
1001 InsertTextAtSelection(
\r
1002 InsertAtSelectionFlags.TF_IAS_NOQUERY,
\r
1012 public void GetFormattedText(int i_start, int i_end, out object o_obj)
\r
1014 #if TSF_DEBUG_OUTPUT
\r
1015 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
\r
1018 throw new NotImplementedException();
\r
1022 public void GetEmbedded(
\r
1024 ref Guid i_guidService,
\r
1029 #if TSF_DEBUG_OUTPUT
\r
1030 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
\r
1033 throw new NotImplementedException();
\r
1037 public void QueryInsertEmbedded(
\r
1038 ref Guid i_guidService,
\r
1040 out bool o_insertable
\r
1043 #if TSF_DEBUG_OUTPUT
\r
1044 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
\r
1047 throw new NotImplementedException();
\r
1051 public void InsertEmbedded(
\r
1052 InsertEmbeddedFlags i_flags,
\r
1056 out TS_TEXTCHANGE o_textChange
\r
1059 #if TSF_DEBUG_OUTPUT
\r
1060 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
\r
1063 throw new NotImplementedException();
\r
1067 public void InsertTextAtSelection(
\r
1068 InsertAtSelectionFlags i_flags,
\r
1071 out int o_startIndex,
\r
1072 out int o_endIndex,
\r
1073 out TS_TEXTCHANGE o_textChange
\r
1076 #if TSF_DEBUG_OUTPUT
\r
1077 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
\r
1080 if (GetSelectionIndex == null || InsertAtSelection == null)
\r
1081 throw new NotImplementedException();
\r
1083 int selectionStart = 0, selectionEnd = 0;
\r
1084 GetSelectionIndex(out selectionStart, out selectionEnd);
\r
1086 // 問い合わせのみで実際には操作を行わない
\r
1087 if ((i_flags & InsertAtSelectionFlags.TF_IAS_QUERYONLY) != 0)
\r
1089 o_startIndex = Math.Min(selectionStart, selectionEnd);
\r
1090 o_endIndex = Math.Max(selectionStart, selectionEnd);//o_startIndex + i_length;
\r
1092 o_textChange.start = o_startIndex;
\r
1093 o_textChange.oldEnd = o_endIndex;
\r
1094 o_textChange.newEnd = o_startIndex + i_length;
\r
1098 var start = Math.Min(selectionStart, selectionEnd);
\r
1099 var end = Math.Max(selectionStart, selectionEnd);
\r
1101 #if TSF_DEBUG_OUTPUT
\r
1102 Debug.WriteLine(string.Format(
\r
1103 "start: {0}, end: {1}, text: {2}",
\r
1104 start, end, new string(i_text)
\r
1108 InsertAtSelection(new string(i_text));
\r
1110 o_startIndex = start;
\r
1111 o_endIndex = start + i_length;
\r
1113 o_textChange.start = start;
\r
1114 o_textChange.oldEnd = end;
\r
1115 o_textChange.newEnd = start + i_length;
\r
1117 // InsertAtSelection() 内でカーソル位置を更新しているため、ここでは不要。
\r
1119 // SetSelectionIndex(start, start + i_length);
\r
1124 public void GetEndACP(out int o_length)
\r
1126 #if TSF_DEBUG_OUTPUT
\r
1127 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
\r
1130 if (GetStringLength == null)
\r
1131 throw new NotImplementedException();
\r
1133 if (IsLocked(LockFlags.TS_LF_READ) == false)
\r
1135 throw new COMException(
\r
1136 "読取用ロックがされていません。",
\r
1137 TsResult.TS_E_NOLOCK
\r
1141 o_length = GetStringLength();
\r
1145 public void GetActiveView(out int o_viewCookie)
\r
1147 #if TSF_DEBUG_OUTPUT
\r
1148 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
\r
1155 public void GetACPFromPoint(
\r
1157 ref POINT i_point,
\r
1158 GetPositionFromPointFlags i_flags,
\r
1162 #if TSF_DEBUG_OUTPUT
\r
1163 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
\r
1166 throw new NotImplementedException();
\r
1170 public void GetTextExt(
\r
1175 out bool o_isClipped
\r
1178 #if TSF_DEBUG_OUTPUT
\r
1179 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
\r
1182 if (GetStringLength == null)
\r
1183 throw new NotImplementedException();
\r
1186 if (IsLocked(LockFlags.TS_LF_READ) == false)
\r
1188 throw new COMException(
\r
1189 "読取用ロックがされていません。",
\r
1190 TsResult.TS_E_NOLOCK
\r
1194 if ((i_endIndex != -1 && i_startIndex > i_endIndex)
\r
1195 || i_startIndex < 0 || i_startIndex > GetStringLength()
\r
1196 || i_endIndex > GetStringLength())
\r
1198 throw new COMException(
\r
1200 UnmanagedAPI.WinError.HRESULT.E_INVALIDARG
\r
1204 if (i_endIndex == -1)
\r
1205 i_endIndex = GetStringLength();
\r
1207 var pointTopLeft = new POINT();
\r
1208 var pointBotttomRight = new POINT();
\r
1209 GetStringExtent(i_startIndex, i_endIndex, out pointTopLeft, out pointBotttomRight);
\r
1211 o_rect.left = (int)pointTopLeft.x;
\r
1212 o_rect.top = (int)pointTopLeft.y;
\r
1213 o_rect.bottom = (int)pointBotttomRight.y;//startFormattedText.Height);
\r
1214 o_rect.right = (int)pointBotttomRight.x;
\r
1215 o_isClipped = false;
\r
1219 public void GetScreenExt(int i_viewCookie, out RECT o_rect)
\r
1221 #if TSF_DEBUG_OUTPUT
\r
1222 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
\r
1225 if (GetScreenExtent == null)
\r
1226 throw new NotImplementedException();
\r
1228 POINT pointTopLeft, pointBottomRight;
\r
1230 GetScreenExtent(out pointTopLeft, out pointBottomRight);
\r
1232 o_rect.left = (int)pointTopLeft.x;
\r
1233 o_rect.top = (int)pointTopLeft.y;
\r
1234 o_rect.right = (int)pointBottomRight.x;
\r
1235 o_rect.bottom = (int)pointBottomRight.y;
\r
1239 public void RequestSupportedAttrs(
\r
1240 AttributeFlags i_flags,
\r
1242 Guid[] i_filterAttributes
\r
1245 #if TSF_DEBUG_OUTPUT
\r
1246 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
\r
1249 for (int i = 0; i < i_length; i++)
\r
1251 if (i_filterAttributes[i].Equals(_attributeInfo[0].attrID))
\r
1253 _attributeInfo[0].flags = AttributeInfoFlags.Requested;
\r
1254 if ((i_flags & AttributeFlags.TS_ATTR_FIND_WANT_VALUE) != 0)
\r
1256 _attributeInfo[0].flags |= AttributeInfoFlags.Default;
\r
1260 _attributeInfo[0].currentValue = _attributeInfo[0].defaultValue;
\r
1267 public void RequestAttrsAtPosition(
\r
1270 Guid[] i_filterAttributes,
\r
1271 AttributeFlags i_flags
\r
1274 #if TSF_DEBUG_OUTPUT
\r
1275 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
\r
1278 for (int i = 0; i < i_length; i++)
\r
1280 if (i_filterAttributes[i].Equals(_attributeInfo[0].attrID))
\r
1282 _attributeInfo[0].flags = AttributeInfoFlags.Requested;
\r
1283 if ((i_flags & AttributeFlags.TS_ATTR_FIND_WANT_VALUE) != 0)
\r
1285 _attributeInfo[0].flags |= AttributeInfoFlags.Default;
\r
1289 _attributeInfo[0].currentValue = _attributeInfo[0].defaultValue;
\r
1296 public void RequestAttrsTransitioningAtPosition(
\r
1299 Guid[] i_filterAttributes,
\r
1300 AttributeFlags i_flags
\r
1303 #if TSF_DEBUG_OUTPUT
\r
1304 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()))
\r
1311 public void FindNextAttrTransition(
\r
1315 Guid[] i_filterAttributes,
\r
1316 AttributeFlags i_flags,
\r
1317 out int o_nextIndex,
\r
1319 out int o_foundOffset
\r
1322 #if TSF_DEBUG_OUTPUT
\r
1323 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
\r
1326 throw new NotImplementedException();
\r
1330 public void RetrieveRequestedAttrs(
\r
1332 TS_ATTRVAL[] o_attributeVals,
\r
1333 out int o_fetchedLength
\r
1336 #if TSF_DEBUG_OUTPUT
\r
1337 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
\r
1340 o_fetchedLength = 0;
\r
1341 for (int i = 0; i < _attributeInfo.Length && o_fetchedLength < i_length; i++)
\r
1343 if ((_attributeInfo[i].flags & AttributeInfoFlags.Requested) != 0)
\r
1345 o_attributeVals[o_fetchedLength].overlappedId = 0;
\r
1346 o_attributeVals[o_fetchedLength].attributeId = _attributeInfo[i].attrID;
\r
1347 o_attributeVals[o_fetchedLength].val = _attributeInfo[i].currentValue;
\r
1349 if ((_attributeInfo[i].flags & AttributeInfoFlags.Default) != 0)
\r
1350 _attributeInfo[i].currentValue = _attributeInfo[i].defaultValue;
\r
1352 o_fetchedLength++;
\r
1353 _attributeInfo[i].flags = AttributeInfoFlags.None;
\r
1360 #region "ITfContextOwnerCompositionSink インターフェイスの実装"
\r
1361 /// <summary>コンポジション入力が開始された時の処理。</summary>
\r
1362 public void OnStartComposition(ITfCompositionView view, out bool ok)
\r
1364 #if TSF_DEBUG_OUTPUT
\r
1365 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
\r
1368 if( CompositionStarted != null )
\r
1369 ok = CompositionStarted();
\r
1376 //========================================================================================
\r
1379 /// <summary>コンポジションが変更された時の処理。</summary>
\r
1380 public void OnUpdateComposition(ITfCompositionView view, ITfRange rangeNew)
\r
1382 #if TSF_DEBUG_OUTPUT
\r
1383 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
\r
1386 if (rangeNew == null)
\r
1391 ITfRangeACP rangeAcp = (ITfRangeACP)rangeNew;
\r
1393 rangeAcp.GetExtent(out start, out count);
\r
1395 if (this.CompositionUpdated != null)
\r
1396 this.CompositionUpdated(start, start + count);
\r
1401 //========================================================================================
\r
1404 /// <summary>コンポジション入力が終了した時の処理。</summary>
\r
1405 public void OnEndComposition(ITfCompositionView view)
\r
1407 #if TSF_DEBUG_OUTPUT
\r
1408 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()) )
\r
1411 if( CompositionEnded != null )
\r
1412 CompositionEnded();
\r
1415 #endregion "ITfContextOwnerCompositionSink インターフェイスの実装"
\r
1418 /// <summary>表示属性の取得</summary>
\r
1419 public IEnumerable<TextDisplayAttribute> EnumAttributes(int start, int end)
\r
1421 ITfRangeACP allRange;
\r
1422 _services.CreateRange(start, end, out allRange);
\r
1424 foreach (TextDisplayAttribute attr in this.EnumAttributes((ITfRange)allRange))
\r
1425 yield return attr;
\r
1427 ReleaseComObject("allRange", ref allRange);
\r
1430 IEnumerable<TextDisplayAttribute> EnumAttributes(ITfRange range)
\r
1432 #if TSF_DEBUG_OUTPUT
\r
1433 using(var dbgout = new DebugOut("{0}()", DebugOut.GetCaller()))
\r
1436 ITfProperty property = null; // プロパティインターフェイス
\r
1437 IEnumTfRanges enumRanges; // 範囲の列挙子
\r
1438 Guid guidPropAttribute = TfDeclarations.GUID_PROP_ATTRIBUTE;
\r
1440 if (_context == null || _services == null)
\r
1443 // GUID_PROP_ATTRIBUTE プロパティを取得。
\r
1444 _context.GetProperty(ref guidPropAttribute, out property);
\r
1445 if (property == null)
\r
1448 // 全範囲の中で表示属性プロパティをもつ範囲を列挙する。
\r
1449 property.EnumRanges((int)_editCookie, out enumRanges, range);
\r
1451 ITfRange[] ranges = new ITfRange[1];
\r
1452 int fetchedLength = 0;
\r
1453 while (HRESULT.Succeeded(enumRanges.Next(1, ranges, out fetchedLength))
\r
1454 && fetchedLength > 0)
\r
1456 // ItfRange から ItfRangeACP を取得。
\r
1457 ITfRangeACP rangeACP = ranges[0] as ITfRangeACP;
\r
1458 if (rangeACP == null)
\r
1459 continue; // 普通はあり得ない
\r
1461 // 範囲の開始位置と文字数を取得。
\r
1463 rangeACP.GetExtent(out start, out count);
\r
1465 // VARIANT 値としてプロパティ値を取得。VT_I4 の GUID ATOM がとれる。
\r
1466 VARIANT value = new VARIANT();
\r
1467 property.GetValue((int)_editCookie, ranges[0], ref value);
\r
1468 if (value.vt == (short)VarEnum.VT_I4)
\r
1471 ITfDisplayAttributeInfo info;
\r
1472 TF_DISPLAYATTRIBUTE attribute;
\r
1474 // GUID ATOM から GUID を取得する。
\r
1475 _categoryMgr.GetGUID((int)value.data1, out guid);
\r
1476 // その GUID から IDisplayAttributeInfo インターフェイスを取得。
\r
1477 _displayAttributeMgr.GetDisplayAttributeInfo(
\r
1482 // さらに IDisplayAttributeInfo インターフェイスから表示属性を取得する。
\r
1483 info.GetAttributeInfo(out attribute);
\r
1484 ReleaseComObject("info", ref info);
\r
1486 yield return new TextDisplayAttribute
\r
1488 startIndex = start,
\r
1489 endIndex = start + count,
\r
1490 attribute = attribute
\r
1493 #if TSF_DEBUG_OUTPUT
\r
1495 "*******:::: DisplayAttribute: {0} ~ {1} :::::: *********",
\r
1496 start, start + count
\r
1498 Debug.WriteLine(attribute.bAttr);
\r
1500 "LineColorType: {0}, {1}",
\r
1501 attribute.crLine.type, attribute.crLine.indexOrColorRef
\r
1504 "TextColorType: {0}, {1}",
\r
1505 attribute.crText.type, attribute.crText.indexOrColorRef
\r
1508 "BackColorType: {0}, {1}",
\r
1509 attribute.crBk.type, attribute.crBk.indexOrColorRef
\r
1512 "Bold, Style : {0}, {1}",
\r
1513 attribute.fBoldLine, attribute.lsStyle
\r
1518 ReleaseComObject("rangeACP", ref rangeACP);
\r
1521 ReleaseComObject("ranges[0]", ref ranges[0]);
\r
1522 ReleaseComObject("enumRanges", ref enumRanges);
\r
1523 ReleaseComObject("property", ref property);
\r
1529 protected ITfThreadMgr2 _threadMgr;
\r
1531 protected ITfThreadMgr _threadMgr;
\r
1533 protected ITfDocumentMgr _documentMgr;
\r
1534 protected ITfFunctionProvider _functionProvider;
\r
1535 protected ITfFnReconversion _reconversion;
\r
1536 protected ITfContext _context;
\r
1537 protected ITfCategoryMgr _categoryMgr;
\r
1538 protected ITfDisplayAttributeMgr _displayAttributeMgr;
\r
1539 protected ITextStoreACPSink _sink;
\r
1540 protected uint _editCookie = 0;
\r
1541 protected ITextStoreACPServices _services;
\r
1542 protected AdviseFlags _adviseFlags = 0;
\r
1543 protected LockFlags _lockFlags = 0;
\r
1544 protected bool _pendingLockUpgrade = false;
\r
1547 /// AttributeInfo で使用されるフラグ。各属性の状態を示す。
\r
1549 protected enum AttributeInfoFlags
\r
1551 /// <summary>何もない。</summary>
\r
1553 /// <summary>デフォルト値の要求。</summary>
\r
1555 /// <summary>要求された。</summary>
\r
1556 Requested = 1 << 1
\r
1559 protected struct AttributeInfo
\r
1561 public Guid attrID;
\r
1562 public AttributeInfoFlags flags;
\r
1563 public VARIANT currentValue;
\r
1564 public VARIANT defaultValue;
\r
1567 protected AttributeInfo[] _attributeInfo = new AttributeInfo[1];
\r