Question

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.

Was it helpful?

Solution

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

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top