как вызвать dll С# из неуправляемого С++ с помощью IDispatch?

У меня есть dll С#, которую мне нужно вызвать из неуправляемого С++. Основная проблема, с которой я столкнулся, заключается в том, что мой код C++ соответствует надстройке Excel, которую можно установить для Excel 2003 и Excel 2007, когда я устанавливаю свою надстройку в Excel 2007 и пытаюсь вызвать свою C# dll, он работает просто отлично, но по какой-то причине, которую я до сих пор не смог найти, в excel 2003 происходит сбой, excel показывает мне сообщение об ошибке выполнения, и при отладке моего кода на С++ я вижу, что код терпит неудачу при попытке создайте экземпляр моей dll С#, он говорит, что класс не зарегистрирован, даже если я зарегистрировался с помощью regasm.

это мой код С#:


namespace ManagedDLL
{
    [
        Guid("3C80EE60-D9B8-4daf-89BE-6C7B748F613C"),
        InterfaceType( ComInterfaceType.InterfaceIsDual),
        ComVisible(true)
    ]
    public interface ICalculator
    {
        [DispId(1)]
        int main(string args, IntPtr _handle);
    };


    [
        Guid("5134F342-5B7F-4db2-94F0-F450610419CF"),
        ProgId("myapp.CCOMEntryPoint"),
        ClassInterface(ClassInterfaceType.None),
        ComDefaultInterface(typeof(ICalculator)),
        ComVisible(true)
    ]
    public class COMEntryPoint : ICalculator
    {
        public int main(string args, IntPtr _handle)
        {
            string[] _args = args.Split(new char[] { ':' });

            Program.handle = _handle;
            return Program.Main(_args);
        }
    }
}

а в С++ я импортирую файл .tlb, который создается, когда я использую regasm для регистрации моей dll C#, например:


\#import "..\bin\release\ManagedDLL.tlb" raw_interfaces_only
using namespace ManagedDLL;
.
.
.
int callMyDll()
{
    long handle = 0, result = 0;
    BSTR args;

    HRESULT hr = CoInitialize(NULL);

    ICalculatorPtr pICalc(__uuidof(COMEntryPoint));

    pICalc->main(bstrStr, handle, &result);

    return result;
}

Но, как я уже упоминал ранее, этот код не работает для Excel 2003, поэтому мои вопросы:

  1. Я делаю что-то неправильно в том, как я объявляю свою dll С#, которая вызывает у меня проблемы в excel 2003?
  2. Как и сейчас, может ли моя C# dll считаться объектом ActiveX?
  3. Как я могу назвать свою dll С# по-другому из С++? например, с помощью IDIspatch

Спасибо


person Vic    schedule 24.09.2009    source источник


Ответы (2)


У меня была похожая проблема раньше. Я не вызывал С# из С++, но концепция та же.

Мне пришлось загрузить .NET dll в хост-приложение через COM, что похоже на то, что вы пытаетесь сделать. Проблема заключалась в том, что хост-приложение (в вашем случае excel) загружало среду выполнения .NET 1.1. Наша dll была скомпилирована для .NET 2.0.

Возможно, Excel 2003 загружает среду выполнения 1.1, а 2007 загружает более позднюю версию. Посетите этот форум: Excel выбирает неправильную среду выполнения .NET.

Вы также можете проверить это, используя MSBee для среды выполнения 1.1 и затем попробуйте загрузить свою dll в Excel 2003.

person ParmesanCodice    schedule 24.09.2009
comment
да, проблема была именно в том, о чем вы подозревали, Excel загружал среду выполнения 1.1, поэтому исправление, предложенное в той статье, которую вы мне показали, сработало хорошо, или есть также другая статья, в которой говорится о той же проблеме mcfunley.com/331/ может быть полезно для кого-то. - person Vic; 25.09.2009

Я не кодер С++, поэтому я не могу комментировать эту часть, но ответить на нее со стороны С#:

«Я делаю что-то неправильно, когда объявляю свою dll C#, которая вызывает у меня проблемы в Excel 2003?»

Нет, использование вашего атрибута выглядит совершенно правильно. Отличная работа.

«Может ли мой C# dll считаться объектом ActiveX, как и сейчас?»

Скомпилировав с показанными атрибутами, а затем зарегистрировавшись с помощью RegAsm, вы создали и правильно представили свою сборку COM, что вам и нужно. (Термин "ActiveX" обычно используется в отношении элементов управления COM, и ваш класс не является элементом управления.)

«Как я могу вызвать свою dll C# по-другому из C++? Например, с помощью IDIspatch».

Вы используете атрибут [InterfaceType(ComInterfaceType.InterfaceIsDual)], что означает, что интерфейс доступен как для раннего, так и для позднего связывания через IDispatch.

Короче говоря, я не знаю, что здесь не так, поэтому я бы попробовал идею dequadin, чтобы проверить, что загружаемая версия .NET Framework соответствует или выше той платформы, на которой вы строите.

Если это не так, единственное, о чем я могу думать, это тот факт, что вы получаете прямой сбой без исправимой ошибки, что предполагает, что может быть какое-то несоответствие между зарегистрированным интерфейсом и интерфейсом. интерфейс, на котором была скомпилирована вызывающая программа. Это может произойти из-за того, что GUID не изменится, если вы измените интерфейс — вы явно установили GUID через атрибут — поэтому, если интерфейс вообще изменится без перестроения и перерегистрации всего снизу вверх , весь ад разверзся. Таким образом, если вы каким-либо образом изменили свой интерфейс, вам необходимо повторно собрать сборку C#, повторно зарегистрировать с помощью RegAsm, а затем повторно скомпилировать надстройку C++, которая на нее ссылается.

Это всего лишь мое лучшее предположение. И не объясняет проблему Excel 2003 и 2007, если вы используете одну и ту же сборку для каждого из них. Короче говоря, трудно понять, что не так, потому что ваш код C# выглядит на 100% чистым.

-- Майк

person Mike Rosenblum    schedule 24.09.2009