using LPCWSTR (WIN32 API)

rsajoo
rsajoo used Ask the Experts™
on
I am currently using the WIN32 API  in C++ and dealing with strings in the form of LPCWSTR... First off, I read a value from registry via the API and apprently its a byte array. So I converted it to LPCWSTR by casting it...Now, I'd like to concatenate it to another LPCWSTR...for example, I have a path and filename (both of type LPCWSTR) and I'd like to concatentate them so that I can execute teh file via the CreateProcess() method... I cannot seem to use the standard strcat or "+" operator ways of concatenation and am having difficulty finding documentation on these non-standard string types... PLEASE HELP
Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®

Author

Commented:
I tried the following but it doesnt seem to work...any suggestions?

pathname is of type LPCWSTR
exepath = ((LPCWSTR)(pathname + "\\FILENAME.EXE")); //as i want to concanate teh exe FILENAME to the path...so that i can run this filenmae.exe as follows...

CreateProcess((LPCWSTR) exepath,......
Top Expert 2012
Commented:
You should use

wchar_t acPath[MAX_PATH] = L"c:\\some\\directory";

wcscat(acPath, L"FILENAME.EXE");

'wcscat()' will concatenate the two strings, using "+" is not possible for these plain C-style strings. Also be sure to prepend the string literals with a 'L' to indicate UNICODE strings.

Alternatively you could use STL, e.g.

#include <string>
using namespace std;

wstring strPath = L"c:\\some\\directory";
wstring strFile = L"FILENAME.EXE";

wstring strExepath = strPath + strFile;

CreateProcess(strExepath.c_str(),......
jkr
Top Expert 2012
Commented:
Oh, and another alternative is the UNICODE version of 'sprintf()', i.e.

wchar_t acPath[MAX_PATH] = L"c:\\some\\directory";
wchar_w acExepath[MAX_PATH];

swprintf(acExepath,L"%s\\%s, acPath,L"FILENAME.EXE");

And a little correction, in the above, that should have been

wchar_t acPath[MAX_PATH] = L"c:\\some\\directory";

wcscat(acPath, L"\\FILENAME.EXE");
Why Diversity in Tech Matters

Kesha Williams, certified professional and software developer, explores the imbalance of diversity in the world of technology -- especially when it comes to hiring women. She showcases ways she's making a difference through the Colors of STEM program.

>>>> and apprently its a byte array. So I converted it to LPCWSTR
Hmmm. 'byte array' normally means 'single-byte' array but LPCWSTR is 'const wchar_t*' what is a pointer to a UNICODE or wide or double-byte array. I assume you've a UNICODE project and therefore the 'byte array' from registry correctly was a wide-char string.

LPCWSTR can be read as 'long pointer to constant wide string' what is a 'const wchar_t*' as already mentioned by jkr. The non-UNICODE type is LPCSTR == 'const char*'.  MS made a third variant of that type called LPCTSTR == 'const TCHAR*' . If the macro _UNICODE is defined TCHAR is a wchar_t and LPCTSTR is the same as LPCWSTR. If not _UNICODE is defined the TCHAR is a 'char' type and LPCTSTR is LPCSTR. So, if using LPCTSTR and TCHAR and _T("any literal") you can switch between UNICODE strings and non-UNICODE strings by simply changing one project macro. Moreover, the CString class has that switch either. CString is CStringT  and that either manages a wide string buffer or a single-byte char buffer.  And it has a built-in operator LPCTSTR which makes it possible to use a CString where a LPCTSTR is required. Contrary to char arrays/pointers and wchar_t arrays/pointers a CString can easily concatenate or assign other strings but because of the T switch either a UNICODE string or a single char string but not both.

I recommend using LPCTSTR and CString instead of LPCWSTR.

     BYTE buffer[1024] = { 0 };
     if (RegQueryValueEx(hkey, _T("ValName"), NULL, REG_SZ, &buffer, sizeof(buffer)))
     {
            LPCTSTR psz = (LPCTSTR)&buffer[0];
            CString strVal = psz;    
            strVal += _T("any other string");
           
     }

Regards, Alex

Author

Commented:
Thanks!! I am currently looking into both of your suggested solutions...
JKR: your solution using STL works just fine. However, how do i convert a LPCWSTR to wstring format ... as I got a value from a registry (which is of type byte pointer to byte array, call this b). Do I just do this: bstr = ((wstring) b) and then if want to concatenate bstr and another wstring say "blah"...than it it would be c = bstr+b...and than i can send these to CreateProcess(c.c_str()...)

itsmeandnobodyelse: Alternatively, I am looking into your solution as well and i cant seem to use it ...whats the library for using CStrings...i get a compilor error... and how do i pass the strVal into a CreateProcess() as a LPCWSTR...do i simply need to cast? so CreateProcess((LPCWSTR) strVal)...from your explaination it would make sense so but i'd liek to confrim...
jkr
Top Expert 2012
Commented:
>>owever, how do i convert a LPCWSTR to wstring format ...

Just assign it to the wstring object, just like in the above sample, e.g.

wchar_t buf[SOME_SIZE];

// fill that using 'RegQueryValueEx()'

wstr str = buf;

that's it.
jkr
Top Expert 2012
Commented:
Sorry, that is

wchar_t buf[SOME_SIZE];

// fill that using 'RegQueryValueEx()'

wstring str = buf;
>>>> whats the library for using CStrings
It is MFC library. MFC is available for any VC compiler beside of the VS 2005 Express Edition.

If you don't have/use MFC CString is no option. The "T" option nevertheless makes sense as far as you won't go the UNICODE way only.

For string manipulations you should use a string class and I recommend the same as jkr, std::wstring respectively std::string for single byte strings. You easily could enhance the T concept to STL string class cause std::string or std::wstring are typedefs of the template class basic_string. By defining

  typedef basic_string<TCHAR> tstring;

you've got a fully equivalent class to MFC CString.

Regards, Alex
>>>> // fill that using 'RegQueryValueEx()'
You need to cast the wchar_t array cause RegQueryValueEx wants a BYTE pointer:

     wchar_t buffer[1024] = { 0 };
     if (RegQueryValueEx(hkey, _T("ValName"), NULL, REG_SZ, (BYTE*)&buffer, sizeof(buffer)))
     {
            wstring strVal = buffer;    
            strVal += L("any other wide string");
           
     }


Or when going the T way:

     TCHAR buffer[1024] = { 0 };
     if (RegQueryValueEx(hkey, _T("ValName"), NULL, REG_SZ, (BYTE*)&buffer, sizeof(buffer)))
     {
            tstring strVal = buffer;    
            strVal += _T("any other string wide or not");
           
     }

Regards, Alex

Author

Commented:
JKR, Ithanks again...I tried the code in yoru last post... and heres hte problem...I want to dynamically allocate memory for the buffer...ie. I dont want to initialize it...as when I was reading the data from the registry it kept giving me a "more memory required" error... So I read the datasize first and than do allocate memory for the buffer as follows: (whcih works just fine)

 wchar_t * buf = new wchar_t[datasize];

Now, instead of &buf, I pass it in as buf into the RegQueryValueEx() function (which also works just fine, since i get a success error code)...however, when I do extract the data from teh buffer:

wstring str = *buf, str ends up as blank...how do i get around this issue?

Author

Commented:
I tried casting so like so:
wstring str = (wstring) *buf but its gives me an error saying that wchar_t cannot be casted to wstring...
jkr
Top Expert 2012
Commented:
That should just be

wchar_t * buf = new wchar_t[datasize];

//...

wstring str = buf;

If you prepend a '*', that indeed will only copy the first character, since you are asking for the content of the pointer - which is just a single char.
Note, the RegQueryValueEx has a LPBYTE (what actually is 'unsigned char*') as buffer argument. That is cause ReqQueryValueEx may return string data as well as binary data as well as integer values. When passing  a wchar_t* you need to cast that pointer to BYTE* or LPBYTE or unsigned char* what all is equivalent.

       DWORD  bufsize = 0;
       // get size of buf
       ret = RegQueryValueEx(hkey, _T("ValName"),
           NULL, REG_SZ,
           NULL,
           &bufsize);
       
       // calculate the number of wide chars needed
       DWORD neededLength = bufsize/sizeof (wchar_t);
       wchar_t * buf = new wchar_t[neededLength];
       if (RegQueryValueEx(hkey, _T("ValName"),
           NULL, REG_SZ,
           (BYTE*)buf,
            &datasize)
      {
              ...

Some more remarks on that:
RegQueryValueEx is also a subject of the 'T' issue I pointed out above. In case of UNICODE it turns to RegQueryValueExW what takes a wide string (LPCWSTR) for the valuename argument. For non-UNICODE it is RegQueryValueExA what takes a LPCSTR (const char*). In both cases the return buffer is a LPBYTE type, *but* in UNICODE case RegQueryValueEx  returns wide strings in that buffer and in non-UNICODE single-byte strings.

The buffer size is different to the number of wide chars as wchar_t has a size of 2 bytes on Windows. Though it doesn't matter if you would allocate and pass a larger buffer you should be aware of that.

Note, the buffersize is input and output, so you need to pass the address of a writeable DWORD variable.

Regards, Alex


 

Author

Commented:
Also, how do i determine the number of elements in a wchar_t array and the number of characters in a wstring ? I am writing these tuype of values to the registry (via the RegSetValueEx method)

And just out of curiosity, my main method is:
int _tmain(int argc, _TCHAR* argv[]) (generated by default by the IDE) so whats the _TCHAR* argv[], is it an array where each each elment is a pointer to a tchar[] array?

Please let m eknow

thanks again

Do more with

Expert Office
Submit tech questions to Ask the Experts™ at any time to receive solutions, advice, and new ideas from leading industry professionals.

Start 7-Day Free Trial