从RichTextBox中删除(或更新)图像

时间:2009-07-17 11:05:07

标签: .net com pinvoke richtextbox ole

我有一个与在RichTextBox中管理OLE对象相关的问题。

到目前为止我发现了很多信息,但不完全是我需要的信息,所以我先做一个快速介绍(我也希望有人会觉得这很有用)。

1。到目前为止我所知道的

首先,我使用OLE将图像(或任何ActiveX)插入RichTextBox。这应该是“正确的方法”,因为没有涉及剪贴板,你可以插入任何你想要的ActiveX控件。有一篇关于CodeProject(MyExtRichTextBox)的文章,它解释了如何做到这一点(完整的源代码),但要简短说明:

使用P / Invoke,从ole32.dll导入OleCreateFromFile函数,从图像文件创建一个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;

最后使用IRichEditOle.InsertObject将结构传递给RichTextBox。 IRichEditOle是一个COM接口,也使用P / Invoke导入。

对象的“id”使我能够遍历插入的对象列表,并“执行东西”。使用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)另一个问题是,在插入的那一刻(IRichEditOle.InsertObject),我得到一个未处理的异常(Paint Shop Pro已经停止工作)。似乎插入OLE对象以某种方式启动此应用程序,尽管Open或Edit shell命令不存在文件关联。

有人知道可能导致这种情况的原因以及如何预防吗?

[编辑]

我有一个不同的想法 - 我可以创建我的自定义ActiveX控件,它将负责更新图像。在这种情况下,我只需要使RichTextBox的那部分无效(类似于CodeProject文章的作者所做的那样)。但这会使部署更加复杂(我需要将.Net类暴露给COM,然后在嵌入之前注册它)。

1 个答案:

答案 0 :(得分:0)

我对.NET / OLE / ActiveX等知之甚少,但在编程GUI时,应避免从线程修改/刷新窗口。

我有类似的C ++经验。而不是使用线程来修改窗口,你应该使用类似计时器的东西。