这是核心问题:我有一个在单独的AppDomain中使用COM互操作的.NET应用程序.COM的东西似乎是将程序集加载回默认域,而不是从中调用COM内容的AppDomain.
我想知道的是:这是预期的行为,还是我做错了导致这些COM相关程序集被加载到错误的AppDomain中?请参阅以下情况的更详细说明......
该应用程序由3个程序集组成: - 主EXE,应用程序的入口点. - common.dll,只包含一个接口IController(采用IPlugin风格) - controller.dll,包含一个实现IController和MarshalByRefObject的Controller类.此类完成所有工作并使用COM interop与另一个应用程序进行交互.
主要EXE的相关部分如下所示:
AppDomain controller_domain = AppDomain.CreateDomain("Controller Domain");
IController c = (IController)controller_domain.CreateInstanceFromAndUnwrap("controller.dll", "MyNamespace.Controller");
result = c.Run();
AppDomain.Unload(controller_domain);
Run Code Online (Sandbox Code Playgroud)
common.dll只包含以下两件事:
public enum ControllerRunResult{FatalError, Finished, NonFatalError, NotRun}
public interface IController
{
ControllerRunResult Run();
}
Run Code Online (Sandbox Code Playgroud)
controller.dll包含这个类(也调用COM互操作的东西):
public class Controller: IController, MarshalByRefObject
Run Code Online (Sandbox Code Playgroud)
首次运行应用程序时,Assembly.GetAssemblies()看起来像预期的那样,在两个AppDomain中都加载了common.dll,并且只将controller.dll加载到控制器域中.在调用c.Run()之后,我看到与COM互操作内容相关的程序集已加载到默认的AppDomain中,而不是在发生COM互操作的AppDomain中.
为什么会发生这种情况?
如果你有兴趣,这里有一些背景知识:
最初这是一个AppDomain应用程序.它与之接口的COM东西是一个服务器API,它在长时间使用时不稳定.当COM东西发生COMException(没有关于其原因的有用诊断信息)时,整个应用程序必须重新启动才能再次使用COM连接.只需重新连接到COM应用服务器,就会再次导致COM异常.为了解决这个问题,我试图将COM互操作内容移动到一个单独的AppDomain中,这样当神秘的COMExceptions出现时,我可以卸载发生它的AppDomain,创建一个新的并再次启动,所有这些都无需手动重启应用程序.无论如何,这就是理论......
可能重复:
如何在C#中正确清理Excel互操作对象
我在这里阅读了许多关于管理COM引用的其他线程,同时使用.Net-Excel互操作来确保Excel进程在退出时正确退出,到目前为止,这些技术已经运行良好,但我最近遇到了一个将新工作表添加到现有工作簿文件时出现问题.
下面的代码留下了僵尸Excel进程.
如果我将工作表添加到新创建的工作簿文件,它将退出正常.如果我运行除.Add()行之外的代码,它会退出.(我正在读取的现有文件是由注释掉的代码创建的空文件)
有任何想法吗?
//using Excel = Microsoft.Office.Interop.Excel;
//using System.Runtime.InteropServices;
public static void AddTest()
{
string filename = @"C:\addtest.xls";
object m = Type.Missing;
Excel.Application excelapp = new Excel.Application();
if (excelapp == null) throw new Exception("Can't start Excel");
Excel.Workbooks wbs = excelapp.Workbooks;
//if I create a new file and then add a worksheet,
//it will exit normally (i.e. if you uncomment the next two lines
//and comment out the .Open() line below):
//Excel.Workbook wb = wbs.Add(Excel.XlWBATemplate.xlWBATWorksheet);
//wb.SaveAs(filename, …Run Code Online (Sandbox Code Playgroud) 我有一个COM类在一个应用程序中CMyCOMServer实现IMyInterface,两个都具有正确的GUID.CMyCOMServer::QueryInterface如果请求IUnknown或IMyInterface,则返回S_OK(并将其自身转换为正确的类型),否则返回E_NOINTERFACE.
在同一台PC上的另一个应用程序中,我打电话给:
HRESULT hr = ::CoCreateInstance(__uuidof(CMyCOMServer), 0, CLSCTX_SERVER,
__uuidof(IMyInterface ),(void **)&pInterface);
Run Code Online (Sandbox Code Playgroud)
它返回E_NOINTERFACE.所以我认为我做错了什么并添加了一个断点CMyCOMServer::QueryInterface.我发现在CoCreateInstance调用时,QueryInterface会针对不同的接口多次触发:
(IMyInterface *)this预期设置为接口指针所以我的困惑是为什么调用CoCreateInstance给我留下一个NULL指针并返回E_NOINTERFACE代码,当COM服务器应用程序显然返回我要求的接口?
编辑:我的客户端应用程序在启动时调用CoInitialize(NULL),这没有任何区别.
应该是一个简单的问题,但搜索文档让我疯了.假设我有一个coclass或接口的ITypeInfo指针.如何获取该类或接口的名称?
我用来regsvr32 MyCOM.dll为我的应用程序注册我的com对象.这在我的管理员帐户下工作正常.如果将用户切换为非管理员,则程序失败.似乎没有为非管理员用户加载COM对象.关于为什么会这样或可能的解决方案的任何想法?
我有来自第三方的Inproc COM服务器.如果它捕获特定类型的错误,我调用的函数之一将显示错误消息对话框.问题是我正在尝试批量处理数据,而我使用的数据源导致错误对话框弹出很多.如果它生成了1000个对话框,这不会成为问题,而是它会阻塞,直到您按OK才会返回该功能.

如何禁止显示对话框,或以编程方式按OK?
这是一个调用堆栈的副本,因为它正在等待我按OK
[Managed to Native Transition]
> System.Windows.Forms.dll!System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(System.IntPtr dwComponentID, int reason, int pvLoopData) Line 2198 + 0x1e bytes C#
System.Windows.Forms.dll!System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(int reason, System.Windows.Forms.ApplicationContext context) Line 3422 + 0x1b bytes C#
System.Windows.Forms.dll!System.Windows.Forms.Application.ThreadContext.RunMessageLoop(int reason, System.Windows.Forms.ApplicationContext context) Line 3306 + 0xc bytes C#
System.Windows.Forms.dll!System.Windows.Forms.Application.Run(System.Windows.Forms.Form mainForm) Line 1495 + 0x31 bytes C#
UniversalDataImporter.exe!UniversalDataImporter.Program.Main() Line 18 + 0x1d bytes C#
[Native to Managed Transition]
[Managed to Native Transition]
mscorlib.dll!System.AppDomain.ExecuteAssembly(string assemblyFile, System.Security.Policy.Evidence assemblySecurity, string[] args) Line 2023 + 0x18 bytes C#
Microsoft.VisualStudio.HostingProcess.Utilities.dll!Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() + 0x27 bytes
mscorlib.dll!System.Threading.ThreadHelper.ThreadStart_Context(object … 在Watin的源代码中,有这段代码:
public void NavigateToNoWait(Uri url)
{
var thread = new Thread(GoToNoWaitInternal);
thread.SetApartmentState(ApartmentState.STA);
thread.Start(url);
thread.Join(500);
}
[STAThread]
private void GoToNoWaitInternal(object uriIn)
{
var uri = (Uri)uriIn;
NavigateTo(uri);
}
Run Code Online (Sandbox Code Playgroud)
由于创建的线程设置了其单元状态,为什么该[STAThread]属性被添加到方法中?我对特定的代码段不感兴趣,但我想知道是否STAThread需要属性.
笔记:
GoToNoWaitInternal不在别处使用.我正在将一些用C#编写的代码翻译成Java.此代码使用COM对象与第三方应用程序进行交互.我设法使用com4j库处理COM对象,但其中一个方法需要System.DBNull.value传递给它,这是一个C#对象.
如何从Java应用程序处理它?
我有一对使用相同COM接口的库.在一个库中,我有一个实现该接口的类.另一个库需要一个实现接口的对象.
但是两个库都有自己的接口定义.两者略有不同,但基本上是相同的界面.
所以我尝试将它们放在如下:
Library2.Interface intf = (Library2.Interface)impl;
Run Code Online (Sandbox Code Playgroud)
但这引起了例外.如果我执行以下操作:
Library1.Interface intf = (Library1.Interface)impl;
Run Code Online (Sandbox Code Playgroud)
然后它没有问题,但我不能再将类传递给Library2.
我天真地假设两个具有相同GUID的接口都可以防止这是一个问题,但我似乎错了.有谁知道如何在两个库之间进行转换?也许是通过某种元帅?
com ×10
c# ×6
com-interop ×4
.net ×2
interop ×2
java ×2
windows ×2
.net-4.0 ×1
appdomain ×1
automation ×1
c++ ×1
casting ×1
com+ ×1
excel ×1
jacob ×1
messagebox ×1
permissions ×1
pia ×1
privileges ×1
sta ×1
visual-c++ ×1
watin ×1