Как я могу легко использовать COM-компонент в Native Visual C ++ - PullRequest
7 голосов
/ 18 июля 2009

Я пытаюсь создать приложение, которое использует COM-компонент в VisualStudio ´05 на родном C ++. Сочетание нативных и управляемых описаний вещей в MSDN полностью разрушило мой мозг. (Я думаю, что MSDN - полный беспорядок в этом отношении) Мне нужен короткий и простой нативный пример кода C ++ для загрузки моего компонента и сделать его пригодным для использования. Я в порядке с компилятором, создающим обертки и тому подобное.

Пожалуйста, не советуйте мне использовать пример MFC на основе диалога, потому что он не работает с этим компонентом и сам по себе огромный стопка кодов ...

Может ли это быть проблема нативной комы с управляемой ком?

Я полностью потерян, пожалуйста, дайте мне несколько ориентиров ...

РЕДАКТИРОВАТЬ: Спасибо за всю помощь. Моя проблема в том, что все, что у меня есть, это зарегистрированный DLL (на самом деле OCX, см. Ниже) , Я (лично) знаю как должен выглядеть интерфейс, но как мне узнать мою программу? Там нет заголовков, которые определяют Идентификаторы для интерфейсов, которые я мог бы использовать. Но я читал, что компилятор c ++ может извлечь и обернуть это для меня. Кто-нибудь знает, как это делается?

РАЗЪЯСНЕНИЕ: у меня есть только OCX и подсказка из документации компонента, какие методы он должен предоставлять.

Ответы [ 6 ]

3 голосов
/ 22 декабря 2016

Полностью рабочий пример (именно то, что вам нужно) из моей статьи в блоге: Как вызвать COM-объект из Visual Studio C ++?

// https://helloacm.com/how-to-call-com-object-from-visual-studio-c/
#include <iostream>
#include <objbase.h>
#include <unknwn.h>
#include <Propvarutil.h>
#import "wshom.ocx" no_namespace, raw_interfaces_only  

using namespace std;

int main() {
    HRESULT hr;
    CLSID clsid;
    CoInitializeEx(nullptr, COINIT_MULTITHREADED);  
    CLSIDFromProgID(OLESTR("WScript.Shell"), &clsid);   
    IWshShell *pApp = nullptr;
    hr = CoCreateInstance(clsid, nullptr, CLSCTX_INPROC_SERVER, __uuidof(IWshShell), reinterpret_cast<LPVOID *>(&pApp));
    if (FAILED(hr) || pApp == nullptr) {
        throw "Cannot Create COM Object";
    }
    int out;
    VARIANT s;
    InitVariantFromInt32(0, &s);
    VARIANT title;
    InitVariantFromString(PCWSTR(L"title"), &title);
    VARIANT type;
    InitVariantFromInt32(4096, &type);
    BSTR msg = ::SysAllocString(L"Hello from https://helloacm.com");
    pApp->Popup(msg, &s, &title, &type, &out);
    CoUninitialize();
    cout << "Out = " << out;
    return 0;
}
2 голосов
/ 18 июля 2009

Минимальные значения для создания экземпляра COM-объекта следующие:

1) Должна быть в наличии квартира COM.

Это достигается большинством приложений, вызывая CoInitialize / CoInitializeEx, чтобы настроить библиотеку COM и начальную квартиру COM, если это первый раз для процесса.

2) Вызовите CoCreateInstance / CoCreateInstanceEx, чтобы создать объект, и укажите флаги, чтобы указать, как он будет создан.

3) Правильно сбалансировать вызовы AddRef и Release на интерфейсах любых созданных вами COM-компонентов, вызывая последний Release () после завершения использования COM-компонента.

-

В управляемом приложении # 1 почти всегда обрабатывается для вас. № 2 абстрагируется, если вы импортируете ссылку на библиотеку COM, и вы можете просто использовать импортированные имена, как если бы они были определениями класса .NET и тому подобное. № 3 автоматически обрабатывается для вас, но ваши потребности могут отличаться. К сожалению, иногда возникают странности в том, как обрабатываются ссылки в управляемых приложениях, что может привести к тому, что COM-объекты будут задерживаться дольше, чем предполагалось. Вспомогательный класс Marshal в System.Runtime имеет методы, которые могут помочь вам, если у вас возникнут проблемы.

-

В неуправляемом приложении вам придется немного поработать, если вы создаете приложение с нуля.

  1. Вызовите CoInitialize / CoInitializeEx в начале основного потока вашего приложения, чтобы настроить квартиру.
  2. Когда основной поток вашего приложения собирается завершить работу, вызовите CoUninitialize (), чтобы закрыть квартиру.
  3. Для дополнительных потоков, которые вы создаете, вы также должны вызывать CoInitialize / CoInitializeEx при их запуске, если вам нужно использовать COM-объекты из этих потоков. Кроме того, в зависимости от вашего приложения вы можете установить параметры квартиры.
  4. Для этих потоков также вызывайте CoUninitialize (), когда они выходят для правильной очистки.
2 голосов
/ 18 июля 2009

Я приветствую ваши усилия по переходу на нативный C ++ для работы с COM - вам нужно испытать боль, чтобы по-настоящему оценить сегодняшнюю роскошную (управляемую) среду разработки:)

Когда мир (и я) был моложе, книга Крейга Брокшмидта " Inside OLE " была томом для понимания СОМ (до того, как СОМ даже стал СОМ). Эта книга предшествует управляемому коду, поэтому здесь нет шансов на путаницу. Есть и второе издание.

Книги Дона Бокса " Essential COM " и " Effective COM " были позже, но приветствуются добавления в хранилище (неуправляемых) знаний COM.

Однако, если ваш кошелек не распространяется на приобретение этих пыльных старых книг, учебный материал Microsoft COM здесь может помочь вам встать на правильный путь.

Счастливого взлома.

1 голос
/ 18 июля 2009

Я использую комбинацию интеллектуальных COM-указателей ATL и класса ATL :: CAxWindow для COM-объектов и компонентов. Я нахожу умные указатели особенно простыми в использовании.

http://www.murrayc.com/learning/windows/usecomfromatl.shtml

http://76.105.92.243/notes/atlcom.html#import

http://msdn.microsoft.com/en-us/library/yx242b61%28VS.80%29.aspx

1 голос
/ 18 июля 2009

Было бы полезно, если бы вы дали немного больше информации о том, что именно вы делаете. Знаете ли вы, какие интерфейсы реализует объект и т. Д.?

В общем, API, который вы можете использовать в Google для более конкретной помощи, это CoCreateInstance. Вам нужно будет передать ему GUID объекта, с которым вы хотите играть. Все COM-объекты реализуют интерфейс IUnknown, и вы можете запрашивать любые другие, которые у него могут быть. Таким образом, некоторый пример псевдокода для начала может выглядеть примерно так:

CoInitializeEx( NULL, COINIT_APARTMENTTHREADED );
CoCreateInstance( CLSID,
                       ptrIUnknown,
                       ClassCxt, // generally CLSCTX_INPROC_SERVER,
                       riid , // reference id
                       (void **)&pRequest); // the interface that corresponds to the riid

Здесь вы можете запрашивать дополнительные интерфейсы, используя интерфейс IUnknown, который вы получили от ptrIUnknown.

Затем очистите с помощью

CoUninitialize()

Essential COM от Don Box - отличная книга на эту тему. Кроме того, просто для проверки того, как работает ваш COM-объект, использование чего-то вроде VBScript делает это очень просто. Кроме того, вероятно, стоит отметить, что GUID идентификатора класса хранится несколько необычным образом, поэтому, если вы просто извлекаете GUID из реестра, у вас могут возникнуть проблемы с определением порядка. Это, вероятно, для другого вопроса.

0 голосов
/ 18 июля 2009

Попробуйте использовать #import из Visual C ++. Это создаст интеллектуальные оболочки указателей для интерфейсов.

...