0

I'm working on a function that calls a Win32 function called RmRegisterResources.
This function accepts a parameter of type LPCWSTR[] for a list of file paths, our resources.
I'm trying to assemble the LPCWSTR array, but it always initialize with only one member.

Here's what I'm doing:

void Test(std::vector<LPCWSTR> input)
    {
        size_t vecsize = input.size();
        LPCWSTR* resourcelist = new LPCWSTR[vecsize];

        for (size_t i = 0; i < input.size(); i++)
        {
            LPCWSTR single = input.at(i);
            size_t strsize = wcslen(single);
            resourcelist[i] = new WCHAR[strsize];
            wcscpy_s((WCHAR*)resourcelist[i], strsize, single);
        }

        /*
            The rest of the code...
        */
    }  

On the for loop's first iteration, it copies the first string with no problem.
On the second one, wcscpy_s doesn't fail, but I have no idea where it copied the string.
At the end, the call to RmRegisterResources works with just the first copied string, no problem.

What am I missing?

Disc.: I am not a developer, I'm a curious sys admin wanting to learn C++. I know the issue must be simple, and believe me, I have searched two days in a row for a solution.
On the documentation, Microsoft encourages passing multiple file names at once, because the operation is costly.

Thank you very much!

Edit:
The vector input.data() thing:
enter image description here

Edit2:

If I create the array with a constant value, it works. like this:

LPCWSTR string[2] = { L"Thisisastring", L"Thisisalso" }

However, trying to allocate memory either with functions like LocalAlloc, or with the new keyword I got this error.

FranciscoNabas
  • 505
  • 3
  • 9
  • 3
    Why all this work to copy the array and the contents of each string? Just pass `input.data()` directly into [RmRegisterResources](https://learn.microsoft.com/en-us/windows/win32/api/restartmanager/nf-restartmanager-rmregisterresources). – selbie Sep 29 '22 at 21:46
  • 1
    Also this line is incorrect: `new WCHAR[strsize];`. It needs to be `new WCHAR[strsize+1];` to account for the null char. But in a C++ world, you should never have to "new" or "strcpy" a string. just use std::wstring and the .c_str() method when you need the pointer. – selbie Sep 29 '22 at 21:48
  • 1
    And know about [this resource](https://en.cppreference.com/w/) and [this one](https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list). – Paul Sanders Sep 29 '22 at 21:48
  • Didn't used the input.data() cause I had no idea I could lol. However, the input.data() call is returning only the first string. I'll add the screen shot at the question. About '\0', I'm aware, I just keep forgetting it. – FranciscoNabas Sep 29 '22 at 22:01
  • 1
    Seems like all your implementation can be changed to single line - `LPCWSTR* resourcelist = &input[0]`; – Victor Gubin Sep 29 '22 at 22:12
  • P.S. For moderator - question can be marked as a duplicate of https://stackoverflow.com/questions/6485496/how-to-get-stdvector-pointer-to-the-raw-data – Victor Gubin Sep 29 '22 at 22:19
  • 1
    I feel like the issue is you're looking at a pointer in the debugger but expect it to be an array. It doesn't work like that. You can add something like `pointerVariable,5` to the watch window to treat it as an array of 5 (or any size) items though. In this case `input.data()` returns a pointer to the first element so that's what the debugger, without any other hints, shows. – Retired Ninja Sep 29 '22 at 22:52
  • @VictorGubin `input.data()` and `&input[0]` have the same type (`LPCWSTR*` in this case), and point to the same memory address. – Remy Lebeau Sep 29 '22 at 23:15
  • @VictorGubin also, this is not a dupe of that question you linked to – Remy Lebeau Sep 29 '22 at 23:18
  • Thank you for your comments, @RetiredNinja, I thought the same, but the function returns the result only for the first string. When I do all the copy, I can se the first string being copied to the memory address I allocated for it, the second copy operation doesn't error, but idk where the string is being copied to. The RmRegisterResource returns like if I had input only the first string. – FranciscoNabas Sep 30 '22 at 02:19
  • Agreed this is not a dupe. I'm aware of pointers and how "strings" are formed. I'm also aware on how to reference or de-reference a pointer to an array of characters. Just doesn't make sense the second string not appearing at all. – FranciscoNabas Sep 30 '22 at 02:22
  • If I slightly change the code to add 1 to `strsize` to allow for the terminator it works fine for me. https://godbolt.org/z/oK7G35MW4 The issue with `input.data()` only showing one string in the debugger is because it has no way of knowing that the pointer points to an array unless you tell it by adding `,X` in the watch window where X is the number of entries you want to display. – Retired Ninja Sep 30 '22 at 02:59

1 Answers1

0

I'll post this as an answer because it ultimately answers my question about string arrays.
Thank you for the awesome help. Used the suggestions in all comments to find where my problem is.

I tested with a vector and a plain LPCWSTR* and I can see both strings.
The issue must be on RmRegisterResources requirements.
Here's how I found out.

The code:

std::vector<LPCWSTR>* hardcoded = new std::vector<LPCWSTR>();
hardcoded->push_back(L"C:\\dump.csv");
hardcoded->push_back(L"C:\\Users\\francisco.nabas\\Documents\\fail.xlsx");
        
std::vector<LPCWSTR>* testvec = new std::vector<LPCWSTR>();
LPCWSTR* reslist = new LPCWSTR[fileName->Length];
        
for (int i = 0; i < fileName->Length; i++)
{
    pin_ptr<const WCHAR> single = PtrToStringChars(fileName[i]);
    
    // LPCWSTR*
    size_t strsize = wcslen(single) + 1;
    reslist[i] = new WCHAR[strsize];
    wcscpy_s((WCHAR*)reslist[i], strsize, single);

    // std::vector<LPCWSTR>
    testvec->push_back((LPCWSTR)single);
}

LPCWSTR firstpath = reslist[0];
LPCWSTR secondpath = reslist[1];

I've opened the memory window during debugging to chase the addresses, and all of them took me to the strings I was looking for.

On hardcoded:
enter image description here

On testvec:
enter image description here

On reslist[0]:
enter image description here

On reslist1:
enter image description here

Regardless of the object, RmRegisterResource acts the same, only processes the first string on the "list".
I'll research a little more about this function and implementations.
Thank you all for the help, it's beautiful viewing things being allocated in memory :D.

Edit:

Found the issue with RmRegisterResources. The issue was me.
This is MS definition:
enter image description here

Note the parameter nFiles. Now look what I did:
enter image description here

Replaced with reslist.size() and it's working as expected.
Thank you once again.

FranciscoNabas
  • 505
  • 3
  • 9