Тест NUnit с Фортран DLL - PullRequest
       13

Тест NUnit с Фортран DLL

1 голос
/ 08 февраля 2011

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

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

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

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

Теперь я написал простой тест NUnit и получил исключение COM.

System.Runtime.InteropServices.COMException : Получение фабрики класса COM для компонент с CLSID {0FB0F699-4EF8-4732-B98E-C088825E3912} не удалось из-за следующей ошибки: 80040154 Класс не зарегистрирован (Исключение из HRESULT: 0x80040154 (REGDB_E_CLASSNOTREG)).

Как я могу решить эту проблему?

Спасибо, Adrien.

Ответы [ 3 ]

4 голосов
/ 27 сентября 2012

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

Вот краткое изложение.

Вставьте следующий код в ваш проект (спасибо 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;
}
3 голосов
/ 08 февраля 2011

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

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

0 голосов
/ 17 июня 2011

Проверьте этот ответ:
Как сделать COM без регистрации в архитектуре плагина

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...