RichTextBox での OLE オブジェクトの管理に関する質問があります。
これまでに見つけた情報はたくさんありますが、正確には必要なものではないので、最初に簡単な紹介を行います (また、誰かがこれを参考にしてくれることを願っています)。
1.これまでに知っていること
まず、画像 (または任意の ActiveX) を RichTextBox に挿入するために OLE を使用しています。クリップボードがなく、任意の ActiveX コントロールを挿入できるため、これが「正しい方法」であるはずです。CodeProject ( MyExtRichTextBox )に関する記事があり、それを行う方法 (完全なソース コードを使用) を説明していますが、簡潔にするために:
P/Invoke を使用しOleCreateFromFile
て、ole32.dll から関数をインポートし、イメージ ファイルから OLE オブジェクトを作成します。
int hresult = OleCreateFromFile(...);
関数はIOleObject
インスタンスを返します。これは、REOBJECT
構造体によって参照される必要があります。
REOBJECT reoObject = new REOBJECT();
reoObject.cp = 0; // charated index for insertion
reoObject.clsid = guid; // iOleObject class guid
reoObject.poleobj = Marshal.GetIUnknownForObject(pOleObject); // actual object
// etc. (set other fields
// Then we set the flags. We can, for example, make the image resizable
// by adding a flag. I found this question to be asked frequently
// (how to enable or disable image drag handles).
reoObject.dwFlags = (uint)
(REOOBJECTFLAGS.REO_BELOWBASELINE | REOOBJECTFLAGS.REO_RESIZABLE);
// and I use the `dwUser` property to set the object's unique id
// (it's a 32-bit word, and it will be sufficient to identify it)
reoObject.dwUser = id;
最後に、構造体が を使用して RichTextBox に渡されIRichEditOle.InsertObject
ます。IRichEditOle
P/Invoke を使用してインポートされた COM インターフェイスです。
オブジェクトの「id」により、挿入されたオブジェクトのリストを繰り返し処理し、「何かを行う」ことができます。I を使用IRichEditOle.GetObject
すると、挿入された各オブジェクトを取得し、dwUser
フィールドをチェックして ID が一致するかどうかを確認できます。
2. 問題
では、次の質問に移ります。
a)最初の問題は、挿入された画像の更新です。特定の画像をオンデマンドで「更新」(または変更) できるようにしたい。私が今やっている方法は次のようなものです:
if (reoObject.dwUser == id)
{
// get the char index for the "old" image
oldImageIndex = reoObject.cp;
// insert the new image (I added this overload for testing,
// it does the thing described above)
InsertImageFromFile(oldImageIndex, id, filename);
// and now I select the old image (which has now moved by one "character"
// position to the right), and delete it by setting the selection to ""
_richEdit.SelectionStart = oldImageIndex + 1;
_richEdit.SelectionLength = 1;
_richEdit.SelectedText = "";
}
私は Gui スレッドから更新しているので、OLE 挿入がスレッドをブロックし、アプリが STA で実行されているため、このメソッド中にユーザーが選択を変更することを心配する必要はないと思います。
しかし、それを行うためのより良い/安全な方法があるのではないかと感じていますか? このメソッドは、[DirtyHack]
属性でマークする必要があるようです。
b) もう 1 つの問題は、挿入の瞬間 ( IRichEditOle.InsertObject
) に未処理の例外が発生することです (Paint Shop Pro が動作を停止しました)。Open または Edit シェル コマンドに対するファイルの関連付けは存在しませんが、OLE オブジェクトを挿入すると何らかの方法でこのアプリが起動するようです。
これを引き起こしている可能性のあるものと、それを防ぐ方法を知っている人はいますか?
[編集]
別のアイデアが浮かびました。イメージの更新を処理するカスタム ActiveX コントロールを作成できます。その場合、RichTextBox のその部分を無効にするだけで済みます (CodeProject の記事の著者と同様)。しかし、これでは展開が少し複雑になります (.Net クラスを COM に公開し、埋め込む前に登録する必要があります)。