使用Fortran DLL进行NUnit测试

我有一个来自Fortran的ServerCom DLL。 我使用tlbimp自动生成一个来自ServerCom.dll的MyFortran.dll,可以直接从C#引用。

在C#类库中,我引用了MyFortran.dll。

我创建了一个使用MyFortran.dll并生成正确清单的控制台应用程序(为了拥有一个自由交互的COM环境)。

它在控制台应用程序中完美运行。

现在,我写了一个简单的NUnit测试,我得到了一个COMexception。

System.Runtime.InteropServices.COMException:由于以下错误,检索具有CLSID {0FB0F699-4EF8-4732-B98E-C088825E3912}的组件的COM类工厂失败:80040154未注册类(HRESULTexception:0x80040154(REGDB_E_CLASSNOTREG))。

我怎么解决这个问题?

谢谢,阿德里安。

您可以使用Activation Context API来实现此目的。 这篇博客文章提供了所有细节。

这是一个总结。

将以下代码粘贴到您的项目中(感谢Spike McLarty ):

///  /// Code from http://www.atalasoft.com/blogs/spikemclarty/february-2012/dynamically-testing-an-activex-control-from-c-and ///  class ActivationContext { static public void UsingManifestDo(string manifest, Action action) { UnsafeNativeMethods.ACTCTX context = new UnsafeNativeMethods.ACTCTX(); context.cbSize = Marshal.SizeOf(typeof(UnsafeNativeMethods.ACTCTX)); if (context.cbSize != 0x20) { throw new Exception("ACTCTX.cbSize is wrong"); } context.lpSource = manifest; IntPtr hActCtx = UnsafeNativeMethods.CreateActCtx(ref context); if (hActCtx == (IntPtr)(-1)) { throw new Win32Exception(Marshal.GetLastWin32Error()); } try // with valid hActCtx { IntPtr cookie = IntPtr.Zero; if (!UnsafeNativeMethods.ActivateActCtx(hActCtx, out cookie)) { throw new Win32Exception(Marshal.GetLastWin32Error()); } try // with activated context { action(); } finally { UnsafeNativeMethods.DeactivateActCtx(0, cookie); } } finally { UnsafeNativeMethods.ReleaseActCtx(hActCtx); } } [SuppressUnmanagedCodeSecurity] internal static class UnsafeNativeMethods { // Activation Context API Functions [DllImport("Kernel32.dll", SetLastError = true, EntryPoint = "CreateActCtxW")] internal extern static IntPtr CreateActCtx(ref ACTCTX actctx); [DllImport("Kernel32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool ActivateActCtx(IntPtr hActCtx, out IntPtr lpCookie); [DllImport("kernel32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool DeactivateActCtx(int dwFlags, IntPtr lpCookie); [DllImport("Kernel32.dll", SetLastError = true)] internal static extern void ReleaseActCtx(IntPtr hActCtx); // Activation context structure [StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Unicode)] internal struct ACTCTX { public Int32 cbSize; public UInt32 dwFlags; public string lpSource; public UInt16 wProcessorArchitecture; public UInt16 wLangId; public string lpAssemblyDirectory; public string lpResourceName; public string lpApplicationName; public IntPtr hModule; } } } 

每次需要创建COM对象(在此示例中为COMObject)时,将在lambda函数中创建它的调用包装起来,并将其传递给UsingManifestDo,如下所示:

 object CreateManifestDependantCOMObject() { object myCOMObject = null; ActivationContext.UsingManifestDo(pathToManifestFile, () => myCOMObject = new COMObject()); return myCOMObject; } 

是的,这不起作用。 无需注册表的COM清单需要嵌入使用COM服务器的EXE中。 足够简单的控制台应用程序。 使用NUnit时不容易,因为EXE现在是unit testing运行器。 你不能/不应该搞乱它。 很难做到,因为有很多。

只是不要打扰,这是一个与您想要进行的测试无关的部署细节。 只需在执行测试的计算机上使用regsvr32.exe注册服务器并完成测试。

看看这个答案:
如何在插件架构中进行免注册COM

Eugene表示这可以通过以下两种方式之一实现:
1.将清单嵌入到DLL中并使用ISOLATION_AWARE_ENABLED进行编译
2.使用上下文激活API