2

I am replacing an old DLL which has a function, passing an LPWSTR by reference. The functions should create a new wchar buffer and return the newly created LPWSTR pointer. I found a solution, but I think it could be solved better!?

By the main proramm the DLL function is called like this:

LPWSTR data = null;
funcA(&data);

The function shoud creat a new wchar buffer and return the address.

So here is what I do (it works):

void funcA(LPWSTR szData)
{
  LPWSTR newData = L"DEMODATA";
  LPWSTR newBuffer = new TCHAR[9];
  wmemcpy(newBuffer, newData, 9);

  memcpy(szData, (LPWSTR)&newBuffer , sizeof(LPWSTR));  
}

Is it possibe to write the last line better readable? I tried to assign the new pointer but this does not work:

szData = (LPWSTR)&newBuffer; // not working!
Elduckle
  • 23
  • 4
  • Your funcA takes the argument by value but you pass it by reference? – AlexG Jan 29 '19 at 13:56
  • 1
    Probably your signature for funcA should be void funcA(LPWSTR* szData), so later you ca do *szData = newBuffer. This is essentially what your memcpy is doing. – Tiberiu Maran Jan 29 '19 at 13:57
  • `TCHAR` *can* be defined as ordinary `char`, depending on compiler settings. Rather prefer `wchar_t` instead (or `WCHAR` *if* MS defines it). – Aconcagua Jan 29 '19 at 14:11
  • The latter shouldn't work (and doesn't). With that you're retaining the address of an automatic variable (`newBuffer`), which expires the moment the function returns. Access anything through that address would invoke undefined behavior. The short of it is everything here suggest the original author incorrectly prototyped the function and has hacked up this way to circumvent that rather than just creating a new function. Lovely. `funcA` should be as Aconcagua describes below. Either option is better than what you have. – WhozCraig Jan 29 '19 at 14:36
  • You probably added the `(LPWSTR)` cast because the compiler was telling you about a type mismatch. It was right. You should have fixed the real problem. The cast just told the compiler to stop warning you about your mistake. – MSalters Jan 29 '19 at 15:10

3 Answers3

2

passing an LPWSTR by reference

But you don't do so...

void funcA(wchar_t* data); // LPWSTR resolved to what it actually is
                           // using correct pointers illustrates better
                           // than Microsoft's (valueless?) pointer typedefs...

The original pointer you pass is copied into the function argument, assignment then occurs to this copy.

You actually need to be able to assign to outside address, so you need to do what you already described:

void funcA(wchar_t*& data); // reference to pointer
//                 ^ (!)
{
    wchar_t const* newData = L"DEMODATA"; // literals are const!
    data = new wchar_t[9]; // you can assign directly (especially: no need for memcpy)
    wmemcpy(data, newData, 9);
}

Just for further illustration, might help to better understand: C style pointer to pointer:

void funcA(wchar_t** data); // pointer to pointer
//                 ^
{
    wchar_t* newData = new wchar_t[9];
    wmemcpy(newData, L"DEMODATA", 9);
    *data = newData;
//  ^ (!)
};

Usage of this variant:

wchar_t* text;
funcA(&text);
//    ^ (!)
Aconcagua
  • 24,880
  • 4
  • 34
  • 59
1

The function shoud creat a new wchar buffer and return the address.

Then do just that:

LPWSTR funcA() {
  LPWSTR newData = L"DEMODATA";
  LPWSTR newBuffer = new TCHAR[9];
  wmemcpy(newBuffer, newData, 9);

  return newBuffer;
}

LPWSTR data = funcA();

That being said, consider using unique_ptr to store owned pointers. This will work, but it's bad practice. Even better, use std::string to process data and only convert to WinAPI pointers when necessary.

Bartek Banachewicz
  • 38,596
  • 7
  • 91
  • 135
0
memcpy(szData, (LPWSTR)&newBuffer , sizeof(LPWSTR));  

is equivalent to

*(LPWSTR*)szData = newBuffer; //this copies into the address pointed to by szData

not to

szData = (LPWSTR)&newBuffer; // this copies into szData
Tiberiu Maran
  • 1,983
  • 16
  • 23