对 Word 加载项公开的对象调用方法会引发 RemotingException
我正在用 C# 编写一个(共享)Word 加载项,并希望通过 COMAddIn 类的 Object 属性公开对象来与其进行通信。
因为我希望我的代码在 UI 线程上执行,所以我从 StandardOleMarshalObject 类派生我的外接程序和公开对象。这应该按照此处 和此处。
但是通过这样做,当我针对 .NET 2.0 或 .NET 4.0 进行编译时,我会得到不同的行为。当针对 .NET 4.0 进行编译时,我公开的对象是 __ComObject 类型,并且可以将其自身强制转换为我公开定义的接口。这反过来又让我可以调用对象的方法并且工作得很好。
针对 .NET 2.0 进行编译时,公开的对象属于 __TransparentProxy 类型。这也可以转换为我的接口,但是当我尝试调用方法时,它会抛出 System.Runtime.Remoting.RemotingException 并显示以下消息:
此远程处理代理没有通道接收器,这意味着服务器没有正在侦听的注册服务器通道,或者此应用程序没有合适的客户端通道来与服务器通信。
当我不从 StandardOleMarshalObject 继承时,它似乎可以工作,但随后我的代码将在任意 RPC 线程上执行,这不是我想要的。
我已经在互联网上搜索过,但无法找到解决方案或无法在 .NET 2.0 中工作的原因。我确实发现了一些类似的问题,但它们似乎都解决了 Excel。
目前我还不能切换到 .NET 4.0,所以我真的希望 .NET 2.0 可以解决这个问题。
有没有人有这个问题的解决方案,或者至少有一个解释?
这是我的测试代码:
[ComVisible(true)][Guid("...")]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface IService
{
void Hello();
}
[ComVisible(true)][Guid("...")]
[ClassInterface(ClassInterfaceType.None)]
public class MyService : StandardOleMarshalObject, IService
{
public void Hello()
{
MessageBox.Show("Hello");
}
}
public class MyAddIn : StandardOleMarshalObject, IDTExtensibility2
{
public void OnConnection(object application, ext_ConnectMode connectMode,
object addInInst, ref Array custom)
{
_service = new MyService();
((COMAddIn)addInInst).Object = _service;
}
//Rest of the IDTExtensibility2 implementation
}
public class Test
{
public static void Main(string[] args)
{
Application app = new Application();
app.Visible = true;
COMAddIn addIn = app.COMAddIns.Item("MyAddin");
IService service = addIn.Object as IService;
if (service != null)
service.Hello(); // <-- RemotingException happening here
}
}
I am writing a (Shared) Word Add-In in C# and want to communicate with it by exposing an object through the Object property of the COMAddIn class.
Because I want my code to be executed on the UI thread I derive my add-in and exposed object from the StandardOleMarshalObject class. This should take care of the marshaling as described here and here.
But by doing this I get different behavior when i compile against .NET 2.0 or.NET 4.0. When compiling against .NET 4.0 my exposed object is of type __ComObject and lets itself be cast to my publicly comvisible defined interface. This in turn lets me call methods on the object and works perfectly.
When compiling against .NET 2.0 the exposed object is of type __TransparentProxy. This can also be cast to my interface but when i try to call a method it wil throw a System.Runtime.Remoting.RemotingException with the message:
This remoting proxy has no channel sink which means either the server has no registered server channels that are listening, or this application has no suitable client channel to talk to the server.
When I do not inherit from StandardOleMarshalObject it does seem to work but then my code would execute on an arbitrary RPC thread which is not what i'm looking for.
I have searched the internet but was not able to find a solution or reason why this is not working in .NET 2.0. I did find some similar problems, but they all seem to address Excel.
At this moment I'm not in the position of switching to .NET 4.0 so i'm really hoping this can be solved for .NET 2.0.
Does anyone have a solution for this problem, or at least an explanation?
Here is my test code :
[ComVisible(true)][Guid("...")]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface IService
{
void Hello();
}
[ComVisible(true)][Guid("...")]
[ClassInterface(ClassInterfaceType.None)]
public class MyService : StandardOleMarshalObject, IService
{
public void Hello()
{
MessageBox.Show("Hello");
}
}
public class MyAddIn : StandardOleMarshalObject, IDTExtensibility2
{
public void OnConnection(object application, ext_ConnectMode connectMode,
object addInInst, ref Array custom)
{
_service = new MyService();
((COMAddIn)addInInst).Object = _service;
}
//Rest of the IDTExtensibility2 implementation
}
public class Test
{
public static void Main(string[] args)
{
Application app = new Application();
app.Visible = true;
COMAddIn addIn = app.COMAddIns.Item("MyAddin");
IService service = addIn.Object as IService;
if (service != null)
service.Hello(); // <-- RemotingException happening here
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
所以我找到了一个可以接受并且与.NET2.0完美配合的解决方法来解决我的问题。我觉得它并不那么优雅,但它确实有效。我正在使用一个隐藏的小“代理”窗口,它可以让我将从进程外客户端发出的调用编组到 Word 的 UI 线程。我不打算通过 COM 公开许多方法,因此额外的代码行不会成为问题。我在下面添加了重要的代码片段。
在 Window 7、Office 2007 上测试。希望这对其他人有帮助。
我仍然想知道为什么它在 .NET4.0 而不是 .NET2.0 中工作。因此,如果有人对此有答案,我们仍然不胜感激。
So I found a workaround for my problem that is acceptable and works perfectly with .NET2.0. I don't find it as elegant as it could have been, but it works. I'm using a little hidden "proxy" window that lets me marshal calls made from an out-of-proc client to the UI thread of Word. I'm not planning to have many methods exposed through COM so the extra lines of code won't be a problem. I've added the important pieces of code below.
Tested on Window 7, Office 2007. Hope this helps others.
I do still like to know WHY it's working in .NET4.0 and not .NET2.0. So if anyone has a answer to this, it is still appreciated.