Как подключить COM объект в Visual C++ MFC
CObject MyObj=CreateObject("comobj.mycom.1");
Но компилятор ругается что функция CreateObject не имеет 1 параметр.
Что не правильно делаю, или может надо подключать дополнительно какой то файл?
CObject MyObj=CreateObject("comobj.mycom.1");
Но компилятор ругается что функция CreateObject не имеет 1 параметр.
Что не правильно делаю, или может надо подключать дополнительно какой то файл?
Вообще-то COM объекты создаются через CoCreateInstance и клиент получает указатель на интерфейс, а не сам объект.
Советую почитать нормально про COM. Потому как знания, как мне кажется, не просто поверхностные, они вообще отсутствуют :)
COM объекты не нужно создавать через LoadLibrary... COM объект создается только через CLSID или через ProgID... В реестре прописано, где лежит dll-ка в которой лежит COM объект с таким CLSID-ом.
Но если его нету или нельзя подключить, так как в 1С.
IUnknown* pUnk;
CLSID clsid;
HRESULT hr=::CLSIDFromProgID(L"PROKSREADER.CARD.1",&clsid);
hr = CoGetClassObject( clsid, CLSCTX_INPROC, NULL,IID_IClassFactory, (void**) &pCF );
hr = pCF->CreateInstance( NULL, IID_IUnknown, (void**) &pUnk );
pCF->Release();
Но если его нету или нельзя подключить, так как в 1С.
В 1С наверное он создается через как ты говорил CreateObject в которую передается ProgID. При этом ты этот ProgID просто должен знать... Я ни разу не программировал в 1C поэтому не знаю точно...
ProgID я программисту сообщил. И получается. Написал, отослал, получил от него результат, и переделуеш то что у него не работает.
Я думал что может так же можно и в С++ так как клас CObject и функция CreateObject существуют, что бы приблизить проверку к похожей на 1С.
ProgID я программисту сообщил. И получается. Написал, отослал, получил от него результат, и переделуеш то что у него не работает.
Я думал что может так же можно и в С++ так как клас CObject и функция CreateObject существуют, что бы приблизить проверку к похожей на 1С.
Попробуй не в C++, а скажем в VB, VBA и т.д.
И компиляторов сейчас нету.
Но если его нету или нельзя подключить, так как в 1С.
IUnknown* pUnk;
CLSID clsid;
HRESULT hr=::CLSIDFromProgID(L"PROKSREADER.CARD.1",&clsid);
hr = CoGetClassObject( clsid, CLSCTX_INPROC, NULL,IID_IClassFactory, (void**) &pCF );
hr = pCF->CreateInstance( NULL, IID_IUnknown, (void**) &pUnk );
pCF->Release();
Первое что ты должен сделать для клиета это инитиализировать СОМ библиотеку
с помощью
...........................................................
CoUninitialize();
Если уж сильно хочется использовать указатель на фабрику классов то
HRESULT hr;
IClassFartory *pFac = NULL;
//точно также создаешь и указатель на нужный интерфейс
hr = CoGetClassObject(/*CLSID - твоего класса*/,CLSCTX_INPROC_SERVER,NULL,IID_IClassFactory,(void**)&pFac);
hr = pFac->CreateInstance(NULL,/*IID интерфейса и (void**)указатель на интерфейс*/);
//потом только через QueryInterface
...............................................................................
//освобождаешь ресурсы
if(pFac)
pFac->Release();
...................................
CoUninitialize();
а h- файл должен быть по любому.
там должны храниться IID и CLSID
Function CheckSpelling(Word As String, [CustomDictionary], [IgnoreUppercase], [MainDictionary], [CustomDictionary2], [CustomDictionary3], [CustomDictionary4], [CustomDictionary5], [CustomDictionary6], [CustomDictionary7], [CustomDictionary8], [CustomDictionary9], [CustomDictionary10]) As Boolean
т.е. как бы только первый параметр - проверяемое слово - является обязательным. Сначала хочу взять ID имени метода и параметра через GetIDsOfNames, потом вызываю через Invoke
CLSID clsid;
HRESULT hr = CLSIDFromProgID(L"Word.Application", &clsid);
IDispatch *pWApp;
DISPID dispid[2];
if(SUCCEEDED(hr))
{
hr = CoCreateInstance(clsid, NULL, CLSCTX_LOCAL_SERVER, IID_IDispatch, (void **)&pWApp);
if(SUCCEEDED(hr))
{
LCID lcid = GetSystemDefaultLCID();
lcid = 1033;
LPOLESTR rgszNames[2];
rgszNames[0] = L"CheckSpelling";
rgszNames[1] = L"Word";
pWApp->GetIDsOfNames(IID_NULL,rgszNames,2,lcid,dispid);
WORD wFlags = DISPATCH_METHOD;
CComVariant varResult;
EXCEPINFO excepInfo;
ZeroMemory(&excepInfo, sizeof(excepInfo));
UINT uArgErr;
DISPPARAMS dp = {NULL,NULL,0,0};
dp.cArgs = 1;
dp.cNamedArgs = 1;
dp.rgdispidNamedArgs = &dispid[1];
dp.rgvarg = new VARIANT[dp.cArgs];
dp.rgvarg[0].vt = VT_BSTR;
dp.rgvarg[0].bstrVal = SysAllocString(OLESTR("Hello"));
//LOCALE_SYSTEM_DEFAULT
hr = pWApp->Invoke(dispid[0],IID_NULL, lcid, wFlags, &dp, &varResult, &excepInfo, &uArgErr);
SysFreeString(dp.rgvarg[0].bstrVal);
pWApp->Release();
delete [] dp.rgvarg;
}
Экземпляр Ворда создается, GetIdsOfNames работает без ошибок, возвращает первый ID (сам метод) равным 0х144, второй (параметр Word) почему-то нуль. Может так и должно быть? Потом передаю всего один параметр - строку "Hello" для примера, вызываю Invoke, он не выдает ошибок, эксепшинов, результат S_OK, в параметре varResult должен быть результат функции CheckSpelling - boolean (типа орфографически правильно или нет). Но какое бы я слово ни задавал (орфографически верное или нет), он всегда возвращает один параметр {False VT_BOOL}. От кода локали это не зависит, ставил LOCALE_SYSTEM_DEFAULT, 1033 (United States), всё одинаково
Во всяком случае, данный код на слово "Привет" вернул true, а на слово "Прапвет" вернул false. Т.е у меня по умолчанию для проверки используется русский словарь.
Set dict = Application.Languages(wdEnglishUS).ActiveSpellingDictionary
где wdEnglishUS = 1033, но как это представить в С++ в СОМ? Как обратиться к элементу коллекции и получить его свойство через тот же Invoke?
{
if(app == NULL || ppd == NULL) return E_INVALIDARG;
HRESULT hr = S_OK;
DISPID dispid = 0;
CComBSTR bstr = _T("Languages");
if(SUCCEEDED(hr=app->GetIDsOfNames(IID_NULL,&bstr,1,0,&dispid)))
{
EXCEPINFO excepInfo = {0};
VARIANT varResult;
VariantInit(&varResult);
DISPPARAMS dispparams;
memset(&dispparams,0,sizeof(dispparams));
UINT uArgErr = -1;
hr = app->Invoke(dispid,IID_NULL, 0, DISPATCH_PROPERTYGET, &dispparams, &varResult, &excepInfo, &uArgErr);
if(SUCCEEDED(hr))
{
LPDISPATCH pLanguages = NULL;
hr = varResult.pdispVal->QueryInterface(IID_IDispatch, (void**)&pLanguages);
VariantClear(&varResult);
if(SUCCEEDED(hr))
{
DISPID dispid = 0;
CComBSTR bstr = _T("Item");
if(SUCCEEDED(hr=pLanguages->GetIDsOfNames(IID_NULL,&bstr,1,0,&dispid)))
{
dispparams.cArgs = 1;
dispparams.rgvarg = new VARIANT[dispparams.cArgs];
dispparams.rgvarg[0].vt = VT_I4;
dispparams.rgvarg[0].lVal = id;
hr = pLanguages->Invoke(dispid,IID_NULL, 0, DISPATCH_METHOD, &dispparams, &varResult, &excepInfo, &uArgErr);
delete [] dispparams.rgvarg;
if(SUCCEEDED(hr))
{
LPDISPATCH pDictionary = NULL;
hr = varResult.pdispVal->QueryInterface(IID_IDispatch, (void**)&pDictionary);
VariantClear(&varResult);
if(SUCCEEDED(hr))
{
DISPID dispid = 0;
CComBSTR bstr = _T("ActiveSpellingDictionary");
if(SUCCEEDED(hr=pDictionary->GetIDsOfNames(IID_NULL,&bstr,1,0,&dispid)))
{
memset(&dispparams,0,sizeof(dispparams));
uArgErr = -1;
hr = pDictionary->Invoke(dispid,IID_NULL, 0, DISPATCH_PROPERTYGET, &dispparams, &varResult, &excepInfo, &uArgErr);
if(SUCCEEDED(hr)){
hr = varResult.pdispVal->QueryInterface(IID_IDispatch, (void**)ppd);
VariantClear(&varResult);
}
}
pDictionary->Release();
}
}
}
pLanguages->Release();
}
}
}
return hr;
}
.......
::CoInitialize(NULL);
CLSID clsid;
HRESULT hr = CLSIDFromProgID(L"Word.Application", &clsid);
IDispatch *pWApp;
if(SUCCEEDED(hr))
{
hr = CoCreateInstance(clsid, NULL, CLSCTX_LOCAL_SERVER, IID_IDispatch, (void **)&pWApp);
if(SUCCEEDED(hr))
{
LPDISPATCH pd = NULL;
if(SUCCEEDED(hr=getDictionary(pWApp, 1033 /*wdEnglishUS*/, &pd)))
{
DISPID dispid = 0;
CComBSTR bstr = _T("CheckSpelling");
pWApp->GetIDsOfNames(IID_NULL,&bstr,1,0,&dispid);
DISPPARAMS dp = {0};
dp.cNamedArgs = 4;
dp.cArgs = 4;
dp.rgdispidNamedArgs = new DISPID[dp.cNamedArgs];
dp.rgvarg = new VARIANT[dp.cArgs];
dp.rgdispidNamedArgs[0] = 0;
CComBSTR text = _T("hello");
dp.rgvarg[0].vt = VT_BSTR;
dp.rgvarg[0].bstrVal = text;
VARIANT CustomDictionary;
CustomDictionary.vt = VT_EMPTY;
CustomDictionary.bstrVal = NULL;
dp.rgdispidNamedArgs[1] = 1;
dp.rgvarg[1].vt = VT_VARIANT|VT_BYREF;
dp.rgvarg[1].pvarVal = &CustomDictionary;
VARIANT varIgnoreUppercase;
varIgnoreUppercase.vt = VT_BOOL;
varIgnoreUppercase.boolVal = VARIANT_TRUE;
dp.rgdispidNamedArgs[2] = 2;
dp.rgvarg[2].vt = VT_VARIANT|VT_BYREF;
dp.rgvarg[2].pvarVal = &varIgnoreUppercase;
VARIANT varMainDictionary;
varMainDictionary.pdispVal = pd;
varMainDictionary.vt = VT_DISPATCH;
dp.rgdispidNamedArgs[3] = 3;
dp.rgvarg[3].vt = VT_VARIANT|VT_BYREF;
dp.rgvarg[3].pvarVal = &varMainDictionary;
UINT uArgErr = -1;
CComVariant varResult;
EXCEPINFO excepInfo = {0};
hr = pWApp->Invoke(dispid, IID_NULL, 0, DISPATCH_METHOD, &dp, &varResult, &excepInfo, &uArgErr);
delete [] dp.rgvarg;
}
pWApp->Release();
}
}
Но проверка английского всё равно не работает.
Не знаю, из-за чего, но уже нет ни времени, ни желания разбираться дальше...
применил этот вариант, и сначала результат возвращал "true" на "Hello" и других словах, но потом снова "false" , потом снова "true", и от чего это может зависеть так и не понял, на русские слова всегда теперь возвращает true. Однако главное, что приложение отказывается выгружать WINWORD.exe после Release(), также заметил, что CInitialize возвращает S_FALSE, как будто СОМ уже инициализирован(это возможно, часть кода писал не я), поэтому как бы нельзя вызывать CoUninitialize.