Convert _Assembly to VARIANT - c++

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?

Related

C++ and WMI: Pass a reference to a CIM class in the IWbemClassObject::Put method

I'm trying to invoke a certain WMI method using C++: Msvm_VirtualSystemManagementService::GetVirtualSystemThumbnailImage (https://learn.microsoft.com/en-us/previous-versions/windows/desktop/virtual/getvirtualsystemthumbnailimage-msvm-virtualsystemmanagementservice).
The method itself requires three parameters: a reference to an instance of CIM_VirtualSystemSettingData, and two uint16s.
In C++, invoking a WMI method first requires you to obtain the the parameters for a method via IWbemClassObject::GetMethod and SpawnInstance; at this point, you can then start using the IWbemClassObject::Put method to begin filling out the parameters, i.e.:
CComVariant varCommand2;
varCommand2.vt = VT_BSTR;
varCommand2.bstrVal = _bstr_t("32");
hres = pClassInstance->Put(L"WidthPixels", 0, &varCommand2, CIM_UINT16);
This works fine. However, I am unable to find any documentation whatsoever with regard to passing an instance of a CIM class. The documentation on on IWbemClassObject::Put states:
If pVal is to contain an embedded IWbemClassObject, the caller must call IWbemClassObject::QueryInterface for IID_IUnknown and place the resulting pointer in the VARIANT using a type of VT_UNKNOWN.
As such, this is what I am trying to do:
CComVariant varCommand;
varCommand.vt = VT_UNKNOWN;
vVirtualSystemSettingData[0].getClassInstance()->QueryInterface(IID_IUnknown, (void**)&varCommand); //getClassInstance returns a reference to the CComPtr that contains the VirtualSystemSettingData I want to use
hres = pClassInstance->Put(L"TargetSystem", 0, &varCommand, 0);
Unfortunately, I simply get a mismatch error, so I know I am not doing this correctly. Ergo, does anyone know how to pass references of CIM objects to the IWbemClassObject::Put method?
Kind regards!
If your instance is already stored in the wmi repository you can use his path for creating reference.
For example:
VARIANT v;
VariantInit(&v);
V_VT(&v) = VT_BSTR;
V_BSTR(&v) = SysAllocString(L"{SOME_CLASS}.Name=\"{YOUR_INSTNACE_NAME}\"");
hres = pClassInstance->Put(L"TargetSystem", 0, &v, CIM_REFERENCE);
VariantClear(&v);
Access to instance from another namespace will be look like:
SysAllocString(L"\\\\.\\root\\{SOME_NAMESPACE}:{SOME_CLASS}.Name=\"{YOUR_INSTACE_NAME}\"")
And some full code example:
https://github.com/spmana/WMIWrapper/tree/master

Directshow current position AVIMUX

I am using winsoft WCamera component with C++ Builder and would like to try and get the current time position from the AVIMUX part of the Directshow graph. Capture is working fine but when I look at the generated file it always seems longer in time than my elapsed time using GetTickCount.
As WCamera component doesn't provide the current media position I am using GetTickCount to give me an approximate position in the video recording to mark events which have occurred. However I am finding that the video is always longer than the time I measure. I would like to try and get the current position from the AVI MUX and see if this is more accurate but I am not sure how to do this.
I tried
HRESULT FindFilterInterface(
IGraphBuilder *pGraph, // Pointer to the Filter Graph Manager.
REFGUID iid, // IID of the interface to retrieve.
void **ppUnk) // Receives the interface pointer.
{
if (!pGraph || !ppUnk) return E_POINTER;
HRESULT hr = E_FAIL;
IEnumFilters *pEnum = NULL;
IBaseFilter *pF = NULL;
if (FAILED(pGraph->EnumFilters(&pEnum)))
{
return E_FAIL;
}
// Query every filter for the interface.
while (S_OK == pEnum->Next(1, &pF, 0))
{
hr = pF->QueryInterface(iid, ppUnk);
pF->Release();
if (SUCCEEDED(hr))
{
break;
}
}
pEnum->Release();
return hr;
}
But this gives the error
[bcc64 Error] main.cpp(29): non-const lvalue reference to type '_di_IEnumFilters' (aka 'DelphiInterface') cannot bind to a temporary of type 'Wdirectshow9::IEnumFilters **'
WDirectShow9.hpp(1392): passing argument to parameter 'ppEnum' here
[bcc64 Error] main.cpp(34): non-const lvalue reference to type '_di_IBaseFilter' (aka 'DelphiInterface') cannot bind to a temporary of type 'Wdirectshow9::IBaseFilter **'
WDirectShow9.hpp(1402): passing argument to parameter 'ppFilter' here
hpp file defines this as
__interface IEnumFilters;
typedef System::DelphiInterface<IEnumFilters> _di_IEnumFilters;
Any suggestions as to how I can access the IEnumFilters?

Get C# out string paramater value to C++ BSTR*?

I have a method in C# DLL having one input and two output parameters. All the three are String.
I want to call that function from firebreath C++. How do I have to pass the BSTR* value from C++?. And how do I get that out values from C#?
I have already tried to get using
BSTR* userKey =NULL;
*userKey = ::SysAllocString(L"Hello Managed World");
But its not working.
C# function:
public void GetPublicKeyforEncryption(String ToUserEmailAddress, out String userKey , out String mySharedKey)
C++ Calling function:
std::wstring& ToUserEmailaddress;
BYTE **bEncryptData = NULL;
BSTR bsData = SysAllocStringLen(ToUserEmailaddress.data(), ToUserEmailaddress.size());
BSTR* userKey =NULL;
BSTR* mySharedKey =NULL;
CSharpInterface->GetPublicKeyforEncryption(bsData,userKey ,mySharedKey );
In the above c++ GetPublicKeyforEncryption bsData value is passed correctly,How will i allocate memory and Pass
userKey ,mySharedKey in the BSTR* type
Anyone can solve this issue?
Help me.
Thanks
Sanju
That's not correct code, BSTR is already a pointer type. You need to pass a pointer to your BSTR variable so the called method can assign it. Generic code that assumes just one out string argument:
BSTR retval = NULL;
HRESULT hr = CSharpInterface->SomeMethod(&retval);
if (SUCCEEDED(hr)) {
// Use retval
//...
SysFreeString(retval);
}

Passing native string type from CLI to native and back again

I am trying to write a CLI wrapper around some low-level COM-related calls. One of the operations that I need to do specifically is to get a specific value from a PROPVARIANT, i.e.:
pwszPropName = varPropNames.calpwstr.pElems[dwPropIndex];
where pwszPropName is documented to be an LPWSTR type and dwPropIndex is a DWORD value passed into the function by the user.
I have a native function defined as follows:
HRESULT CMetadataEditor::GetPropertyNameByID(DWORD ID, wchar_t *PropertyName)
I would like to return the value of pwszPropName via *PropertyName.
Is the wchar_t* type the best way to do this, and would I need to pin *PropertyName in my CLI to ensure it does not move in memory? Do I need to define the length of *PropertyName before passing it to native code (buffer)?
If wchar_t* is the right variable type to pass into the native function, what is the proper conversion of LPWSTR to whar_t*, and how then would you convert that value to System::String?
I have tried a number of different techniques over the past few days and can't seem to get anything right.
------------UPDATE------------
Here is my full code. First, the CLI:
String^ MetadataEditor::GetPropertyNameByID(unsigned int ID)
{
LPWSTR mPropertyName = L"String from CLI";
m_pCEditor->GetPropertyNameByID(ID, mPropertyName);
//Convert return back to System::String
String^ CLIString = gcnew String(mPropertyName);
return CLIString;
}
And the native code:
HRESULT CMetadataEditor::GetPropertyNameByID(DWORD ID, LPWSTR PropertyName)
{
HRESULT hr = S_OK;
LPWSTR myPropName;
PROPVARIANT varNames;
PropVariantInit(&varNames);
hr = m_pMetadata->GetAllPropertyNames(&varNames);
if(hr != S_OK)
{
PropVariantClear(&varNames);
return hr;
}
myPropName = varNames.calpwstr.pElems[ID];
PropertyName = myPropName;
PropVariantClear(&varNames);
return hr;
}
It doesn't seem like the value (myPropName) is set properly and/or sustained back into the CLI function because the CLI returns the value I set on mPropertyName before calling the native function.. I'm not sure why or how to fix this.
UPDATE!!!!
I suspected my problem had something to do with variables going out of scope. So I changed the C++ function definition as follows:
LPWSTR GetPropertyNameByID(DWORD ID, HRESULT ErrorCode);
After adjusting the CLI as well, I now get a value returned, but the first character is incorrect, and in fact can be different with every call. I tried using ZeroMemory() in the native class before assigning the output of the PROPVARIANT to the variable (ZeroMemory(&myPropName, sizeof(myPropName +1)); but still no luck.
You can design unmanaged function by the following way:
HRESULT CMetadataEditor::GetPropertyNameByID(DWORD ID, LPWSTR PropertyName, size_t size)
{
....
wcscpy(PropertyName, varNames.calpwstr.pElems[ID]); // or wcsncpy
...
}
PropertyName is the buffer allocated by caller, size is its size. Inside the function wcscpy or wcsncpy the string varNames.calpwstr.pElems[ID] to PropertyName. Client code:
WCHAR mPropertyName[100];
m_pCEditor->GetPropertyNameByID(ID, mPropertyName, sizeof(mPropertyName)/sizeof(mPropertyName[0]));
Think, for example, how GetComputerName API is implemented, and do the same

How do I use IFileSystemImage2's put_BootImageOptionsArray from IMAPI2 (getting E_NOINTERFACE)?

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);