Skip to content

Instantly share code, notes, and snippets.

@Alexhuszagh
Last active June 26, 2022 01:21
Show Gist options
  • Save Alexhuszagh/c231052cb6e51868215608305fe4e797 to your computer and use it in GitHub Desktop.
Save Alexhuszagh/c231052cb6e51868215608305fe4e797 to your computer and use it in GitHub Desktop.
Example Using COM IDispatch Interface
/** Example using the COM interface without AutoCOM. The entire
* file can be automated with AutoCOM in under 15-lines of code.
*
* #include "autocom.hpp"
* int main(int argc, char *argv[])
* {
* com::Bstr text;
* com::Dispatch dispatch("VBScript.RegExp");
* dispatch.put("Pattern", L"\\w+");
* for (auto match: dispatch.iter("Execute", L"A(b) c35 d_[x] yyy")) {
* match.get("Value", text);
* printf("Match is %S\n", text);
* }
* return 0;
* }
*/
#include <cassert>
#include <cstdio>
#include <dispex.h>
#include <oaidl.h>
#include <wtypes.h>
void putPattern(IDispatch *dispatch)
{
// initialize parameters
DISPPARAMS dp = {nullptr, nullptr, 0, 0};
VARIANT *args = new VARIANT[1];
DISPID named = DISPID_PROPERTYPUT;
VariantInit(&args[0]);
args[0].vt = VT_BSTR;
args[0].bstrVal = SysAllocString(L"\\w+");
dp.rgvarg = args;
dp.cArgs = 1;
dp.rgdispidNamedArgs = &named;
dp.cNamedArgs = 1;
// get function ID
DISPID id;
LPOLESTR string = L"Pattern";
if (FAILED(dispatch->GetIDsOfNames(IID_NULL, &string, DISPATCH_METHOD, LOCALE_USER_DEFAULT, &id))) {
assert(false);
}
// call method
VARIANT result;
VariantInit(&result);
if (FAILED(dispatch->Invoke(id, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYPUT, &dp, &result, nullptr, nullptr))) {
assert(false);
}
// cleanup
VariantClear(&args[0]);
VariantClear(&result);
delete[] args;
}
IDispatch * callExecute(IDispatch *dispatch)
{
// initialize parameters
DISPPARAMS dp = {nullptr, nullptr, 0, 0};
VARIANT *args = new VARIANT[1];
VariantInit(&args[0]);
args[0].vt = VT_BSTR;
args[0].bstrVal = SysAllocString(L"A(b) c35 d_[x] yyy");
dp.rgvarg = args;
dp.cArgs = 1;
// get function ID
DISPID id;
LPOLESTR string = L"Execute";
if (FAILED(dispatch->GetIDsOfNames(IID_NULL, &string, DISPATCH_METHOD, LOCALE_USER_DEFAULT, &id))) {
assert(false);
}
// call method
VARIANT result;
if (FAILED(dispatch->Invoke(id, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET | DISPATCH_METHOD, &dp, &result, nullptr, nullptr))) {
assert(false);
}
// cleanup
VariantClear(&args[0]);
delete[] args;
return result.pdispVal;
}
IEnumVARIANT * requestEnumVariant(IDispatch *dispatch)
{
// initialize parameters
DISPPARAMS dp = {nullptr, nullptr, 0, 0};
VARIANT result;
// call method
auto hr = dispatch->Invoke(DISPID_NEWENUM, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET | DISPATCH_METHOD, &dp, &result, nullptr, nullptr);
if (FAILED(hr)) {
assert(false);
}
IEnumVARIANT *ev = nullptr;
if (result.vt == VT_DISPATCH) {
hr = result.pdispVal->QueryInterface(IID_IEnumVARIANT, (void**) &ev);
} else if (result.vt == VT_UNKNOWN) {
hr = result.punkVal->QueryInterface(IID_IEnumVARIANT, (void**) &ev);
} else {
hr = E_NOINTERFACE;
}
VariantClear(&result);
if (FAILED(hr)) {
assert(false);
}
return ev;
}
void printMatch(IDispatch *match)
{
// initialize parameters
DISPPARAMS dp = {nullptr, nullptr, 0, 0};
VARIANT result;
VariantInit(&result);
// get function ID
DISPID id;
LPOLESTR string = L"Value";
if (FAILED(match->GetIDsOfNames(IID_NULL, &string, DISPATCH_METHOD, LOCALE_USER_DEFAULT, &id))) {
assert(false);
}
// call method
if (FAILED(match->Invoke(id, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET | DISPATCH_METHOD, &dp, &result, nullptr, nullptr))) {
assert(false);
}
// get value
printf("Match is %S\n", result.bstrVal);
VariantClear(&result);
}
int main(int argc, char *argv[])
{
CoInitializeEx(nullptr, COINIT_MULTITHREADED);
// create our dispatcher
GUID guid;
IDispatch *dispatch;
CLSIDFromProgID(L"VBScript.RegExp", (LPCLSID) &guid);
if (FAILED(CoCreateInstance(guid, nullptr, CLSCTX_INPROC_SERVER, IID_IDispatch, (void **) &dispatch))) {
assert(false);
}
// call methods
putPattern(dispatch);
auto *enumdispatcher = callExecute(dispatch);
auto ev = requestEnumVariant(enumdispatcher);
// iterate
VARIANT result;
ULONG fetched;
if (SUCCEEDED(ev->Next(1, &result, &fetched))) {
IDispatch *match = result.pdispVal;
printMatch(match);
}
// cleanup
ev->Release();
enumdispatcher->Release();
dispatch->Release();
CoUninitialize();
return 0;
}
@WKleinschmit
Copy link

The 3rd parameter of GetIDsOfNames is the number of names. This should be 1 not LOCALE_USER_DEFAULT since it has nothing to do with a localse.

@mcow
Copy link

mcow commented May 22, 2019

@WKleinschmit you are correct about parameter #3, but the bug is, he's using DISPATCH_METHOD in that position. (LOCALE_USER_DEFAULT is in fact the symbol to use for parameter #4 unless there is some actual locale work being done.) His bug is how I ended up here in the first place, because I'm looking for a good example of Invoke(… DISPATCH_METHOD …), with little luck so far.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment