Dodgy string conversion (please help)

  • Thread starter Thread starter Duncan Winn
  • Start date Start date
D

Duncan Winn

I am new to VC++7. I am using a method GetPrivateProfileString that
requires an LPTSTR.
I have defined this as a:

char * data_name;

I am then trying to convert this to an LPOLESTR and I have done this as
follows:

LPOLESTR dunk_data = (LPOLESTR)T2CW(data_name);

However this is in a loop and data_name always contains the correct string
but dunk_data sometimes contains the correct data and sometimes loads of
Chinese or Arabic characters also/instead.

Something is dodgy, please can someone point me in the right direction???

thanks,

Duncan
 
I am new to VC++7. I am using a method GetPrivateProfileString that
requires an LPTSTR.
I have defined this as a:

char * data_name;

I am then trying to convert this to an LPOLESTR and I have done this as
follows:

LPOLESTR dunk_data = (LPOLESTR)T2CW(data_name);

However this is in a loop and data_name always contains the correct string
but dunk_data sometimes contains the correct data and sometimes loads of
Chinese or Arabic characters also/instead.

Something is dodgy, please can someone point me in the right direction???

You need to read up on TCHARs and generic text programming in general. First
of all, your conversion should be:

LPTSTR dunk_data = A2T(data_name);
or
LPCTSTR dunk_data = A2CT(data_name)

depending on what you're using this for (non-const or const string). Also,
you don't need LPOLESTR from what I see, assuming this is for
"GetPrivateProfileString()" (OLESTR buffers and pointers are for COM work).
More importantly, just define "data_name" as a TCHAR instead of "char" and
you won't need this conversion at all. In fact, this is how you should
normaly define all your (character/string) buffers unless you're always
targetting an ASCII or Unicode build exclusively (and never the other). This
will all become clear once you read up on the subject though follow-up
questions will be likely (it can be confusing at first). Note that ASCII
builds are becoming less and less relevant as everything moves to Unicode
anyway so it's less of an issue now. IOW, you can also choose to use
"wchar_t" directly instead of TCHAR if your app will *always* be targetted
for an NT-based OS (NT, 2000, XP and beyond). These OSs work in Unicode
under the hood but the whole topic is deeper than I can get into here (you
may be a little lost by now). BTW, for those times when you do need the ATL
conversion macros as above (sometimes you do), don't generally call them
directly inside of loops. They allocate space on the stack which grows on
each iteration until you can have a potential stack overflow problem. If you
need to do this then invoke a (possibly inlined) function inside your loop
instead (which calls the ATL conversion macro and therefore frees the space
automatically on each iteration).
 
Duncan said:
I am new to VC++7. I am using a method GetPrivateProfileString that
requires an LPTSTR.
I have defined this as a:

char * data_name;

I am then trying to convert this to an LPOLESTR and I have done this as
follows:

LPOLESTR dunk_data = (LPOLESTR)T2CW(data_name);

However this is in a loop and data_name always contains the correct string
but dunk_data sometimes contains the correct data and sometimes loads of
Chinese or Arabic characters also/instead.

Something is dodgy, please can someone point me in the right direction???

thanks,

Duncan

I hit a problem like that a while ago
If I remember correctly those conversion macros can be dangerous to use
in loops since they allocate memory on the stack in a special way (can't
remember the exact details) and this can lead to memory corruption

Try put the code containing the call to T2CW() in a separate function

so you should have something like
for()
{
fn();
}

and the function can not be inline

Vin
 
Duncan Winn said:
I am new to VC++7. I am using a method GetPrivateProfileString that
requires an LPTSTR.
I have defined this as a:

char * data_name;

I am then trying to convert this to an LPOLESTR and I have done this as
follows:

LPOLESTR dunk_data = (LPOLESTR)T2CW(data_name);

However this is in a loop and data_name always contains the correct string
but dunk_data sometimes contains the correct data and sometimes loads of
Chinese or Arabic characters also/instead.

Something is dodgy, please can someone point me in the right direction???

AFAIK, you are not supposed to use the string conversion macros in a loop.
That might be the problem. Another thing is that a char* is not necessarily
the same thing as a TCHAR*. That might be the problem too. How do you
initialize and/or use 'data_name'? Also, why not try the T2COLE macro
instead of casting T2CW?

Jeff...
 
Thanks John.....

To clarify..... I am using GetPrivateProfileString so I have now defined a
'TCHAR * data_name' and used it asfollows:

GetPrivateProfileString (section_name, field_name, "", data_name, 256,
"C:\ini22.ini");

This works and gives me the correct result! However I am then trying to use
the result in COM by calling a method in an OLE DB provider that requires an
LPOLESTR. I have tried to convert my TCHAR as follows:
_rgColumns[ulCols].pwszName = (LPOLESTR)(T2COLE(data_name)); // and also
T2OLE

But this give me the strange results as sometimes the output is correct and
other times not????

Any further suggestions? I have tried using wchar_t but it did not give
anything meaningful from the GetPrivateProfileString??
 
To clarify..... I am using GetPrivateProfileString so I have now defined
a
'TCHAR * data_name' and used it asfollows:

GetPrivateProfileString (section_name, field_name, "", data_name, 256,
"C:\ini22.ini");

This works and gives me the correct result! However I am then trying to use
the result in COM by calling a method in an OLE DB provider that requires an
LPOLESTR. I have tried to convert my TCHAR as follows:
_rgColumns[ulCols].pwszName = (LPOLESTR)(T2COLE(data_name)); // and also
T2OLE

But this give me the strange results as sometimes the output is correct and
other times not????

Any further suggestions? I have tried using wchar_t but it did not give
anything meaningful from the GetPrivateProfileString??

First of all, you need to understand all these string types which I can't
fully explain here. Quick summary only: In Windows, all the args you pass to
"GetPrivateProfileString()" and most other WinAPI functions need to be TCHAR
based. Search MSDN for both "Generic Text Mappings" and also see technical
article "TN059" (for starters). In a nutshell, when you compile your app,
all occurrences of TCHAR are changed to "char" if the constants _UNICODE and
UNICODE are *not* #defined or "wchar_t" if they are #defined (the reason for
both #defined constants is another topic). This way, you can create a
Unicode build or an ASCII build simply by #defining these constants or not
at compile time (respectively). So, TCHAR is nothing more than "char" or
"wchar_t" depending on the presence of these #defined constants. Note that
if your app is targetted for WinNT or beyond then you should normally
#define both constants since WinNT works with Unicode under the hood. Your
app will therefore run more efficiently (you can read up on the subject but
the info is widely dispersed).

Now, understand that LPTSTR is simply a pointer to a non-const TCHAR based
string. LPCTSTR (note the added 'C') is a pointer to const TCHAR-based
string. IOW, if the #defined Unicode constants I described above are *not*
present, LPTSTR simply maps to "char *" and LPCTSTR maps to "const char *".
If those Unicode constants *are* #defined however, then LPTSTR maps to
"wchar_t *" and LPCTSTR maps to "const wchar_t *".

All WinAPI functions where you see either LPTSTR or LPCTSTR therefore need
to be passed TCHAR strings only (watch our for some rare functions that take
pure ASCII or Unicode arguments however - these will be LPSTR, LPCSTR,
LPWSTR or LPCWSTR). Most functions work with TCHAR however so you must pass
TCHAR args. String literals for instance should therefore be surrounded
with the _T macro (note that there are other variations on this macro's name
I won't get into here - they all do the same thing). A string like
"C:\\ini22.ini" should therefore be passed as _T("C:\\ini22.ini") instead
(also note the double backslash I added to the string - your original
example doesn't have this but it must - read up on "escape sequences"). The
_T macro simply ensures the string is either ASCII or Unicode accordingly
(by prepending an "L" in front of your string as required - you can read up
on this macro).

Finally, note that all ASCII-based (C-runtime) string functions you would
normally call such as "strcpy()" need to be replaced with their TCHAR
equivalent ("_tcscpy()" in this case). Search by title for "Routine
Mappings" in MSDN.

Now, an LPOLESTR is a different beast. It's actually a string of OLECHARs so
LPOLESTR is simply "OLECHAR *" and LPCOLESTR is a "const OLECHAR *". An
OLECHAR is the character used by COM on the host OS which is simply
"wchar_t" in Win32. So OLECHAR is really a "wchar_t" on all modern versions
of Windows but it should be treated as if it were a real type (OLECHAR, not
"wchar_t"). You can convert from a TCHAR string to an OLECHAR string by
using T2OLE or T2COLE (non-const and const versions). Therefore, your call
should appear as:

_rgColumns[ulCols].pwszName = T2OLE(data_name);

This assumes that "_rgColumns[ulCols].pwszName" is defined as an LPOLESTR,
which presumably it is since you're apparently using it to call an OLE DB
function that takes this (BTW, ADO is typically much easier than using OLE
DB directly). Anyway, the conversion should work correctly assuming you're
following all the rules I've described. If you are and something is still
amiss then something else is causing your problem.

Lastly, note that the "" you're passing as the 3rd arg to
"GetPrivateProfileString()" , which should actually be _T("") as per the
above discussion, may cause an unrelated problem. If an empty string is
returned in "data_name", you can't tell whether your "field_name" is either
missing or simply isn't assigned a value (I'd have to double check and it
may not be an issue for you anway).
 
Hi, thanks alot, that makes everything a bit clearer. My main problem still
is that in my loop I am defining a
LPWSTR tester;

and for some reason it uses the same bit of memory every time it loops, thus
overwriting the previous contents? I am not sure the best way to copy this
information? Any ideas?? All my other conversions seem to work fine!
 
Hi, thanks alot, that makes everything a bit clearer. My main problem
still
is that in my loop I am defining a
LPWSTR tester;

and for some reason it uses the same bit of memory every time it loops, thus
overwriting the previous contents? I am not sure the best way to copy this
information? Any ideas?? All my other conversions seem to work fine!

I'm not quite sure what you mean now. If this is defined inside the loop
itself then you can't rely on its value between iterations because "tester"
goes of scope on each iteration. IOW, it's re-created each time the loop
starts so its inital value will be random until you initialize it to
something again. Define it outside the loop and you'll be ok (assuming this
what you're alluding to - post the relevant code otherwise).
 
Back
Top