There is a macro written in VBA, that I'd like to call from C++:
Public Function MacroName() As DOMDocument
I'm doing it like this:
_variant_t ret = d_pApp->Run(_bstr_t("MacroName")).bstrVal;
Now, I'd like to cast this ret to IXMLDOMDocumentPtr...
IXMLDOMDocumentPtr d_plDomDocument;
d_plDomDocument = static_cast<IXMLDOMDocumentPtr>(ret);
Well, that doesn't work. The error says, that the type is wrong.
What is the proper way to cast then?
Your error is here:
_variant_t ret = d_pApp->Run(_bstr_t("MacroName"))>>>>>.bstrVal;<<<<
It should be:
_variant_t ret = d_pApp->Run(_bstr_t("MacroName"));
Once you do that you may find that your static_cast works - I cannot remember offhand. Otherwise, you can use the following method.
First ret.ChangeType(VT_UNKNOWN) then if that succeeds then use d_plDomDocument = ret.punkVal;. This will do a QueryInterface under the hood.
Or in a single step:
d_plDomDocument = IXMLDOMDocumentPtr(ret);
This will return a NULL _com_ptr_t if the variant cannot be converted to an object.
Related
I am trying to get the return value from c++ function in dart.
My c++ code is something like this
static bool is_alive() {
return true;
}
From dart, I loaded the shared lib with this native code and I am trying to call that is_alive() function.
typedef BooleanFunction = Pointer<Int8> Function();
Pointer<NativeFunction<BooleanFunction>> isAlive = (functionAddress).cast<NativeFunction<BooleanFunction>>();
Pointer<Int8> Function() isAliveFunc = isAlive.asFunction();
I called then the isAliveFunc from dart and I want the result of that functions. I tried all these ways. None of these works.
Pointer<Int8> casted = isAliveFunc()!.cast();
Pointer<Int8>? fromPointer = isAliveFunc()!;
developer.log('value : $casted');
I get the result like this Pointer<Int8>: address=0x1
How can I fetch the value from this pointer in dart ? I expect to get a 1 or 0 as the result.
For some reason you never actually call your isAliveFunc function.
Just call the function as you would any other:
Pointer<Int8> casted = isAliveFunc();
or
Pointer<Int8> casted = isAliveFunc.call();
You should also be paying attention to your Dart static analysis warnings and errors.
Your function definitions are also incorrect. is_alive returns a bool/Int8, not a pointer.
Your BooleanFunction typedef should be:
typedef BooleanFunction = Int8 Function();
int Function() isAliveFunc = isAlive.asFunction();
And the function call return should be assigned to an int:
int casted = isAliveFunc();
I have a CLR hosting application that I'm trying to make it support WPF.
I attempted to set a value of a field to _Assembly but the problem is that I have to pass a variable of type VARIANT.
This is the C# code that I'm trying to convert to C++:
Assembly assembly = Assembly.Load(data);
...
field.SetValue(null, assembly); // I'm attempting to do that in C++
Here is what I did:
_AssemblyPtr pAssembly = NULL;
...
hr = AppDomain->Load_3(sa, &pAssembly);
...
CComVariant obj;
BindingFlags bFlags = (BindingFlags)(BindingFlags_SetField | BindingFlags_NonPublic | BindingFlags_Static);
hr = fieldInfo->SetValue(obj, CComVariant(pAssembly), bFlags, NULL, NULL);
It fails at fieldInfo->SetValue and more accurate at the 2nd argument which is supposed to be of type VARIANT. Error: hr = E_INVALIDARG One or more arguments are invalid.
If I set the second argument to CComVariant(NULL), it doesn't fail but I need to put the _Assembly there.
Any idea how I can deal with the problem?
I'm not going to get into too much of the details on the Excel side of things, I essentially took code from this example:
C++ app automates Excel (CppAutomateExcel)
solution1.cpp
So I've tried this code in MSVC and it compiles:
class foo { public: virtual void bar(){} };
int main()
{
void (foo::*p)() = &foo::bar;
}
But similar code to capture the address of the move function in Excel does not work:
int main()
{
Excel::_ApplicationPtr spXlApp;
HRESULT hr = spXlApp.CreateInstance(__uuidof(Excel::Application));
Excel::WorkbooksPtr spXlBooks = spXlApp->Workbooks;
Excel::_WorkbookPtr spXlBook = spXlBooks->Add();
Excel::_WorksheetPtr spXlSheet = spXlBook->ActiveSheet;
HRESULT(Excel::_Worksheet::*pMove)(...) = &spXlSheet->Excel::_Worksheet::Move;
<... irrelevant code ...>
return 0;
}
This has the following compiler error:
error C2276: '&': illegal operation on bound member function expression
If I remove the &, it says I should add it back:
error C3867: 'Excel::_Worksheet::Move': non-standard syntax; use '&' to create a pointer to member
Any help on what to do here would be greatly appreciated.
You say in your question "but similar code..." and then you show code in which you do not do the same thing. Try using the same syntax for setting pMove as you used for setting p in your smaller example. Try something like &Excel::_Worksheet::Move; (without the "spXlSheet->").
If you can specify the specific instance of the object for which to call the function pointer at the time that you set the function pointer as you have there, I'm not aware of such a capability. After dropping spXlSheet-> from where you set the variable, use it instead where you want to call the function pointer.
You need to declare the method pointer like this instead:
// or whatever parameter type Move() actually uses...
void (Excel::_Worksheet::*pMove)(tagVARIANT, tagVARIANT) = &Excel::_Worksheet::Move;
Then, to actually call pMove(), you would have to do something like this:
Excel::_WorksheetPtr spXlSheet = ...;
(spXlSheet.Get()->*pMove)(...);
I'm trying to do something like:
if (foo)
return SET_ERROR_AND_RETURN_NULL(ERROR_HERE);
using...
#define SET_ERROR_AND_RETURN_NULL(error)
lastError = error; \
return nullptr; \
so that later I can...
if (GetMyLastError() == ERROR_HERE) { foo }
However, I get "Return value type does not match the function type." Just defining SET_ERROR_AND_RETURN_NULL as a nullptr works of course, so I'm guessing it has to do with how types work with macros?
Perhaps I shouldn't do this using a macro, but I was inspired by windows system error codes. If it's a bad idea, I'd like to understand why a function call would be better.
I'm also trying to do it this way because I was hoping to keep the if statement return a one-liner without needing to set lastError there.
A textual substitution shows the error.
if (foo)
return SET_ERROR_AND_RETURN_NULL(ERROR_HERE);
becomes:
if (foo)
return lastError = ERROR_HERE;
return nullptr;
which is parsed as
if (foo)
return lastError = ERROR_HERE;
return nullptr;
Now return lastError = ERROR_HERE will return the error (because of the return value of = operator), which is probably not the return type of your method. It's a macro, not a function so it's textually replaced: if you return from a macro you are returning directly from the code in which the macro is expanded.
That's why you shouldn't use them when you can avoid to use them, here a static method would have been enough.
I am trying to use the IFileSystemImage2 interface to create an ISO with multiple boot records using Imapi2.
To do this, I should be able to use put_BootImageOptionsArray passing in SAFEARRAY* of VT_DISPATCH type, i.e. COM pointers of type IBootOptions for each boot options configuration. As a short demo, I have the following code (I only created one IBootOptions in this case):
SAFEARRAYBOUND bounds[1];
bounds[0].cElements = 1;
bounds[1].lLbound = 0;
IBootOptions* BootOptionsArrayData = NULL;
SAFEARRAY* Array = SafeArrayCreateEx(VT_DISPATCH,
1,
bounds,
(void*) &IID_IBootOptions);
hr = SafeArrayAccessData(Array,
reinterpret_cast<void**>(&BootOptionsArrayData));
BootOptionsArrayData = BootOptions; // BootOptions = IBootOptions*
hr = SafeArrayUnaccessData(Array);
hr = IsoImage->put_BootImageOptionsArray(Array);
However, every time I call put_BootImageOptionsArray I get E_NOINTERFACE returned.
IsoImage is being created as you'd expect:
hr = CoCreateInstance(CLSID_MsftFileSystemImage,
NULL,
CLSCTX_ALL,
__uuidof(IFileSystemImage2),
(void**) &IsoImage);
Using IFileSystemImage2 any inherited functionality from IFileSystemImage works fine. Likewise, I can CoCreateInstance a IFileSystemImage instead, and this interface can be used just fine.
I have attached to my process in WinDbg and set a breakpoint in CMsftFileSystemImage::put_BootOptionsArray, however, this function (the underlying implementation) simply isn't being called.
My question, therefore is simple: the implementation appears to be there, but I don't seem to be able to call it. Does anyone have any experience of using this particular bit of functionality and if so how did you get it to work?
The documentation stipulates the SAFEARRAY must be an array of VARIANT that contain IDispatch interface pointers, so you could do something like this (I'm using smart pointers which is easier...):
CComPtr<IFileSystemImage2> image;
CComPtr<IBootOptions> options;
image.CoCreateInstance(CLSID_MsftFileSystemImage);
options.CoCreateInstance(CLSID_BootOptions);
// set various options here...
options->put_Manufacturer(CComBSTR(L"joe"));
// create a SAFEARRAY of VARIANT
CComSafeArray<VARIANT> a(1);
// create a VARIANT of type VT_UNKNONW (or VT_DISPATCH)
CComVariant v(options);
// put it in the array
a.SetAt(0, v);
HRESULT hr = pImage->put_BootImageOptionsArray(a.m_psa);