|
-
December 14th, 2011, 05:34 AM
#16
Re: Reading ASCII Strings into a Unicode Program
 Originally Posted by wdolson
When I move the code to load data into m_CfgData to the app class, or the document class, setting filename works properly with no problems.
I will emphasize what VictorN has stated.
If it is determined that the issue is not an MFC architecture related issue (for example, there is an MFC reason why the code doesn't work, and not because of bugs), then you don't move any code.
By moving code, all you did was move the potential bug to another location in your program, and now the bug is probably hidden. Then you deploy the code on a customer's machine, and the code crashes -- that's how these things happen.
I emphasize to never finagle with the code by moving it around if you see a bug. Take the buggy code and fix it. If you do move the code, then the problem gets more difficult, if not impossible to fix.
Regards,
Paul McKenzie
-
December 14th, 2011, 10:09 PM
#17
Re: Reading ASCII Strings into a Unicode Program
Unless someone can point me to some literature that says otherwise, I'm pretty well convinced this is an MFC architecture issue. I put the exact same code in the mainframe and the app class. They even used the exact same struct definition in the same header file.
The CStrings ended up as <Bad Ptr> after writing to them with code like the following:
TCHAR *pszRet;
pszRet = (TCHAR *)ini.GetValue(_T("MTLAUNCH"), _T("DataPath"), path);
m_CfgData.DataPath = pszRet;
ini.GetValue is from a class I found for getting data to and from INI files and also does the ASCII to Unicode translation.
The above code works without any problems at all in the app class, but in the mainframe, m_CfgData.DataPath says <Bad Ptr> after it is supposed to be set.
The way the structure was originally defined, it was POD. The strings were all char arrays statically defined as MAXPATH in length.
I was wrong in my nomenclature earlier, the CString was at least appearing to be an empty string when I tried to set the new CString to the one stored in the mainframe.
I don't have infinite time to drill down to the lowest levels of the MFC architecture to completely prove this. I am doing this project for someone else and my client is paying the bills. I have experimented doing this a couple of different ways and it worked every time from the app class and failed every time from the mainframe.
That's enough for me to move ahead at this point. I know it isn't perfect, but we don't always have time to do a DNA test to determine if a duck is really a duck.
I am interested to know if this is a known limitation of the MFC architecture, but at this point it is academic.
Bill
-
December 15th, 2011, 01:54 AM
#18
Re: Reading ASCII Strings into a Unicode Program
Did you remove all the m_CfgData "initializations" with memset?
Did you implement a ctor in your struct IniData?
Victor Nijegorodov
-
December 15th, 2011, 04:53 AM
#19
Re: Reading ASCII Strings into a Unicode Program
-
December 15th, 2011, 05:32 AM
#20
Re: Reading ASCII Strings into a Unicode Program
Could you show your updated code?
Are you still trying to call ANSI functions in your UNICODE applications?
What is the relationships between your updated structure and those ANSI functions calls?
Victor Nijegorodov
-
December 15th, 2011, 10:23 AM
#21
Re: Reading ASCII Strings into a Unicode Program
Code:
pszRet = (TCHAR *)ini.GetValue(_T("MTLAUNCH"), _T("DataPath"), path);
I am curious about this TCHAR* cast. What is the actual type returned by GetValue()?
-
December 15th, 2011, 01:15 PM
#22
Re: Reading ASCII Strings into a Unicode Program
It returns a wchar_t* which as far as I can tell is identical to a TCHAR * in Unicode, but the compiler couldn't deal with it without the cast.
Bill
-
December 15th, 2011, 01:24 PM
#23
Re: Reading ASCII Strings into a Unicode Program
 Originally Posted by wdolson
It returns a wchar_t* which as far as I can tell is identical to a TCHAR * in Unicode, but the compiler couldn't deal with it without the cast.
Bill
It's always a danger sign when you have to cast in order to force the compiler to accept something. Can you provide the exact error message you get without the cast?
-
December 15th, 2011, 03:50 PM
#24
Re: Reading ASCII Strings into a Unicode Program
 Originally Posted by wdolson
It returns a wchar_t* which as far as I can tell is identical to a TCHAR * in Unicode, but the compiler couldn't deal with it without the cast.
It isn't the compiler's fault. You have faulty code, and the compiler is correctly informing you that the two pointer types are not the same, saving you from shooting yourself in the foot.
For example, the compiler can't deal with this either without me casting:
Code:
class Elephant
{
// stuff that makes an elephant an elephant
};
class Doughnut
{
// stuff that makes a doughnut a doughnut
};
Doughnut* GetDoughnut()
{
return new Doughnut;
}
int main()
{
Elephant *e;
e = (Elephant*)GetDoughnut();
}
I casted a pointer to a Doughnut to a pointer to an Elephant. If I remove the cast, the compiler correctly states that the pointers are not the same type. So is a Doughnut an Elephant? Of course not.
Basically, you're letting 'C' creep into a C++ program. You can cast anything to anything using a C-style cast. By doing this, you're telling the compiler to shut-up, and you should not be doing this in a C++ program. If the compiler says "type A isn't the same as type B", believe it and fix the error by not casting, but looking carefully at your code and your design.
Regards,
Paul McKenzie
-
December 15th, 2011, 08:05 PM
#25
Re: Reading ASCII Strings into a Unicode Program
 Originally Posted by Lindley
It's always a danger sign when you have to cast in order to force the compiler to accept something. Can you provide the exact error message you get without the cast?
error C2440: '=' : cannot convert from 'const wchar_t *' to 'TCHAR *'
Bill
-
December 15th, 2011, 08:15 PM
#26
Re: Reading ASCII Strings into a Unicode Program
 Originally Posted by VictorN
Could you show your updated code?
Are you still trying to call ANSI functions in your UNICODE applications?
What is the relationships between your updated structure and those ANSI functions calls?
The class I'm using to read the ini is called CSimpleIni from here http://code.jellycan.com/simpleini/. Using this, I can eliminate the ANSI function calls in the program.
It's usage is pretty simple:
Code:
TCHAR iniFile[MAXPATH];
const TCHAR *pszRet;
// skipping code to set iniFile...
CSimpleIni ini(TRUE, FALSE, FALSE);
SI_Error rc = ini.LoadFile(iniFile);
pszRet = ini.GetValue(_T("MTLAUNCH"), _T("DataPath"), path);
m_CfgData.DataPath = pszRet;
I added the const to the declaration of pszRet after the cast was brought to my attention.
The struct is now declared as:
Code:
struct IniData
{
CString DataPath;
int DrvType;
int DrvPort;
CString ConfigPath;
CString MapPath;
CString PinNamePath;
CString SocketPath;
CString CalPath;
CString clrBackground;
CString clrGrid;
int MeasureSpec;
int SuperMeasure;
IniData() : DrvType(0), DrvPort(0), MeasureSpec(0), SuperMeasure(0) {}
};
Bill
-
December 15th, 2011, 08:28 PM
#27
Re: Reading ASCII Strings into a Unicode Program
 Originally Posted by wdolson
error C2440: '=' : cannot convert from 'const wchar_t *' to 'TCHAR *'
Bill
That error is legitimate. Never ignore it.
What it means is that you're attempting to take a pointer to a const field, and just assuming you can write to it if need be. The compiler can never assume this, and neither should you.
For example:
Code:
int main()
{
const char *p1 = "abc123";
char *p2 = (char *)p1; // I told the compiler to shut up.
p2[0] = 'x'; // oops
}
This is the "foot shooting scenario" that the compiler is trying to prevent.
A const T* is not the same as a T*. The former implies that you cannot write to what T points to, while the latter implies that T points to a writable field.
Regards,
Paul McKenzie
-
December 15th, 2011, 08:48 PM
#28
Re: Reading ASCII Strings into a Unicode Program
I fixed it after you pointed it out to me.
I'm copying the contents of the pointer right after it's set and then discarding the pointer, so while it was less than optimal coding practice, it wasn't causing the problems I initially wrote about.
Bill
-
December 15th, 2011, 08:54 PM
#29
Re: Reading ASCII Strings into a Unicode Program
 Originally Posted by wdolson
OK. Took a look at the code, and it's supposed to be a generic C++ class for INI reading. The problem is that it has a few issues.
1) Since it's generic, the calls to new[] and then checking for NULL afterwards won't work, unless your code on the outside has overridden operator new[] to return a NULL on failure. This code in particular:
Code:
char * pData = new char[lSize];
if (!pData) {
return SI_NOMEM;
This code isn't going to work if new[] fails, since a failure of new[] throws an exception by default. A return of NULL only happens if you use the nothrow() version of new[] or you (or another entity, i.e. MFC) has overloaded new[] to return a NULL on failure. Since this is a generic class, this code is not correct in this context.
2) The author really should use std::vector<>, and not use new[] /delete[] at all. As it stands now, the code is not exception safe and will produce memory leaks if any of those functions throws an exception. Usage of RAII such as vector<> would fix this issue. Having said this, the class is OK but for these few issues.
Now this code:
Code:
pszRet = ini.GetValue(_T("MTLAUNCH"), _T("DataPath"), path);
m_CfgData.DataPath = pszRet;
Can be shortened to this:
Code:
m_CfgData.DataPath = ini.GetValue(_T("MTLAUNCH"), _T("DataPath"), path);
So what happens in this case? The CString can take a const pointer to a TCHAR to construct itself, so that isn't an issue.
The real fix for your problem is to do this:
Code:
typedef CSimpleIniTempl<TCHAR, SI_NoCase<TCHAR>,SI_ConvertW<TCHAR> > MyCSimpleIni;
Then you use "MyCSimpleIni" or whatever you want to call it in your program. The CSimpleIni is really a typedef for the template instantiation, but it was based on wchar_t.
Therefore just declare a CSimpleIniTempl using the char type you're program is using, and for you , the char type is TCHAR.
This is also a usage of something called "policy-based design", where the type controls how things are done within the template class.
Regards,
Paul McKenzie
Last edited by Paul McKenzie; December 15th, 2011 at 08:59 PM.
-
December 15th, 2011, 08:57 PM
#30
Re: Reading ASCII Strings into a Unicode Program
 Originally Posted by wdolson
I fixed it after you pointed it out to me.
See my last post. The real fix is to declare the CSimpleIniTempl to use TCHAR instead of wchar_t. Then that fixes everything (except for the two issues I pointed out).
Regards,
Paul McKenzie
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|