2011-02-08 4 views
1

У меня есть ServerCom DLL, которая поставляется с Fortran. Я автоматически генерирую tlbimp файл MyFortran.dll из ServerCom.dll, на который можно ссылаться непосредственно с C#.Тест NUnit с Fortran DLL

В библиотеке классов C# я ссылался на MyFortran.dll.

Я создал консольное приложение, в котором используется MyFortran.dll, и сгенерировал правильный манифест (чтобы иметь COM-среду с свободным взаимодействием).

Он отлично работает в консольном приложении.

Теперь я написал простой тест NUnit, и у меня есть COM Exception.

System.Runtime.InteropServices.COMException : Retrieving the COM class factory for component with CLSID {0FB0F699-4EF8-4732-B98E-C088825E3912} failed due to the following error: 80040154 Class not registered (Exception from HRESULT: 0x80040154 (REGDB_E_CLASSNOTREG)).

Как это решить?

Thanks, Adrien.

ответ

3

Да, это не работает. Диспетчер COM без регистрации должен быть встроен в EXE, который использует COM-сервер. Достаточно легко для консольного приложения. Нелегко, когда вы используете NUnit, потому что EXE теперь является тестирующим устройством. Вы не можете/не должны возиться с ним. Трудно сделать так или иначе, потому что есть куча их.

Просто не беспокойтесь, это деталь развертывания, которая не относится к тестированию, которое вы хотите сделать. Просто зарегистрируйте сервер с помощью regsvr32.exe на машине, которая выполняет тесты и будет выполнена с ней.

0

Заканчивать этот ответ:
How to do registration-free COM in a plug-in architecture

Евгений указывает на то, что это возможно в одном из двух способов:
1. встроить манифест в DLL и скомпилировать с ISOLATION_AWARE_ENABLED
2. использование API для активации контекста

4

Для этого вы можете использовать API контекста активации. Это blog post дает все подробности.

Вот резюме.

Вставьте следующий код в свой проект (благодаря Spike McLarty для этого):

/// <remarks> 
/// Code from http://www.atalasoft.com/blogs/spikemclarty/february-2012/dynamically-testing-an-activex-control-from-c-and 
/// </remarks> 
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 в данном примере), обернуть вызов, который создает его в лямбда-функции, и передать это в UsingManifestDo, например:

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

Это сработало отлично! Спасибо, Самуил! :) –

Смежные вопросы