0

I'm calling a COM function that requires a wchar_t** argument. What I would like to do is:

wchar_t* arr[3] = {L"str1", L"str2", L"str3"};

What I get back is a const wchar_t**, which the compiler rejects.

I also tried:

wchar_t* arr[3];
wchar_t p1[] = L"str1";
wchar_t p2[] = L"str2";
wchar_t p3[] = L"str3";
arr[0] = p1;
arr[1] = p2;
arr[2] = p3;

What I get back is wchar_t* (*)[3], which the compiler also rejects.

I'm new to C++ and really struggling with how string literals are handled.

ETA: The function I'm trying to use is GetIDsOfNames and the second parameter is where I'm having a problem. I want to pass 3 names in that parameter (I can successfully pass one name with wchar_t ptName[] = L"namestring" but can't figure out how to combine multiple names in an array).

HRESULT GetIDsOfNames(  
REFIID   riid,  
LPOLESTR *rgszNames, 
UINT     cNames,  
LCID     lcid,  
DISPID   *rgDispId  
); 
walnut
  • 21,629
  • 4
  • 23
  • 59
c2po
  • 13
  • 3
  • 2
    What is rejecting it? You'll need to show both the code that causes the error, and the precise error. – tadman Feb 18 '20 at 02:23
  • You will probably find that the COM function takes a `BSTR*` argument (this has different sematics to `wchar_t **`), please check the function's IDL specification or other documentation – M.M Feb 18 '20 at 02:29
  • Also you should post all of the relevant code, and error messages (preferably post a https://stackoverflow.com/help/minimal-reproducible-example ), and the function's specification and any other documentation. Conventionally a parameter type of `BSTR*` would be an output parameter for a single string – M.M Feb 18 '20 at 02:30
  • simply use `const_cast(arr)` – RbMm Feb 18 '20 at 03:18

2 Answers2

2

The main problem you are encountering is that the array must be an array of pointers to non-constant characters, however you are trying to use string literals which are constant characters.

Most examples you find online of calling this function ignore this problem because the Microsoft compiler allowed this type error up until recently (and still does if you don't invoke it in strict standard mode, AFAIK).

To set up the array in Standard C++ the code could be:

wchar_t p1[] = L"str1";
wchar_t p2[] = L"str2";
wchar_t p3[] = L"str3";
wchar_t* arr[3] = { p1, p2, p3 };

and so the whole call might be:

DISPID dispid[3];
HRESULT result = iFoo->GetIDsOfNames( IID_NULL, arr, 3, LOCALE_SYSTEM_DEFAULT, dispid);

The code you described as "I also tried:" would be correct but I guess you mistakenly went on to put &arr as argument to GetIDsOfNames, instead of arr.

It's normal practice in COM programming for C++ to use wrapper classes that provide a more convenient C++ interface to these underlying C Win32 API functions .

M.M
  • 138,810
  • 21
  • 208
  • 365
  • really use `const wchar_t* arr[3] = {L"str1", L"str2", L"str3"};` is ok. and then need use const_cast(arr). or possible `wchar_t* arr[] = { const_cast(L"str1"), ... }` – RbMm Feb 18 '20 at 03:22
  • not agree, how is any strict aliasing violation is related here ? in what is ub ?? – RbMm Feb 18 '20 at 03:25
  • @RbMm it would be better to post an answer with your suggestions, rather than answering in comments of other answers – M.M Feb 18 '20 at 03:26
  • 1
    @M.M It is not a strict aliasing violation, because the types are *similar*, see https://en.cppreference.com/w/cpp/language/reinterpret_cast#Type_aliasing. Basically, you can modify `const`ness of the pointer on all levels without causing an aliasing violation. I do think though, that `const_cast` seems very dangerous here. What if the function actually tries to modify the strings? – walnut Feb 18 '20 at 03:29
  • 1
    @walnut yeah, I forget that C++ allows aliasing const at all depths (C only allows at top level). The code of course relies on the function doing what its documentation says (which is: not modifying the strings) – M.M Feb 18 '20 at 03:31
  • Thank you M.M...you guessed correctly, I used &arr. With that change it now compiles. – c2po Feb 18 '20 at 03:36
1

A string literal is const data in C++. You can't assign a pointer-to-const to a pointer-to-non-const without using a typecast, eg:

const wchar_t* arr[3] =
{
    L"str1",
    L"str2",
    L"str3"
};

...->GetIDsOfNames(..., const_cast<LPOLESTR*>(arr), 3, ...);

Alternatively:

wchar_t* arr[3] =
{
    const_cast<wchar_t*>(L"str1"),
    const_cast<wchar_t*>(L"str2"),
    const_cast<wchar_t*>(L"str3")
};

...->GetIDsOfNames(..., arr, 3, ...);

Otherwise, you will have to make a copy of the const data into non-const arrays, like M.M.'s answer shows.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • i be use `const_cast(arr)` instead `(LPOLESTR*)arr` but boyh is ok – RbMm Feb 18 '20 at 03:24
  • Thanks Remy...your answer was very useful for my understanding. I tried your suggestions and they both worked. – c2po Feb 18 '20 at 03:40