Re: Populating CString in Win32 dll interface that accepts LPCTSTR
- From: Joseph M. Newcomer <newcomer@xxxxxxxxxxxx>
- Date: Fri, 27 Jun 2008 17:05:44 -0400
See below...
On Fri, 27 Jun 2008 07:53:03 -0700, "Tom Serface" <tom.nospam@xxxxxxxxxxxxx> wrote:
Hi Joe,****
I'm confused from the code, but it seems to me the call to GetBuffer() and
to ReleaseBuffer() is unneeded altogether.
Not only are they needed but it cannot possibly work unless they are used. The DLL is
going to write some arbitrary amount of information, which the caller naively thinks is <
256 characters, into the buffer (what happened to those ideas about "safe computing" that
were so popular years ago?)
****
I've only had to call****
ReleaseBuffer() if I actually modify the buffer after GetBuffer is called
and I only call GetBuffer() if I want to modify the string directly or the
calling parameter demands a LPTSTR (which I admit is hardly ever).
But the OP wanted the string to be "populated" by the DLL. That's the OP's words, see the
message. So we can assume the buffer has been modified. Without the ReleaseBuffer call,
the CString contents are not consistent with the actual string data.
****
Since****
the parameter is a pointer to a const I think it's unlikely they can modify
the buffer supplied anyway.
The fact that it is a pointer to a const from one view does not change the fact that the
parameter might be non-const from the viewpoint of the DLL. Essentially, what happens
here is an implict cast here by telling the C/C++ build that it is a pointer to a const
Unicode or ANSI string, but the DLL might think it is a non-const pointer to an ANSI
string. The prototype shown for the function pointer MIGHT be pointing to a function that
says
bool Something(LPSTR result)
which means the prototype given is erroneous, OR, it might be
bool Something(LPTSTR result)
in which case the DLL and the app MUST BOTH be compiled either as Unicode or non-Unicode.
If the DLL is compiled as ANSI and the app is compiled as Unicode, the nominal text of the
prototypes will give the illusion of being the same, but in fact they are not. When I've
had to do this, I usually do the same thing Microsoft does, e.g.,
#ifdef _UNICODE
bool SomethingW(LPWSTR result)
#else
bool SomethingA(LPSTR result)
#endif
so at least it won't link if there is a failure. In some cases where I'm delivering a DLL
as a product, I do the same thing as Microsoft does, which is to implement BOTH forms, do
the real work in Unicode, and convert back, e.g.,
extern bool __cdecl DoSomethingA(LPSTR result, int len);
extern bool __cdecl DoSomethingW(LPWSTR result, int len);
#ifdef _UNICODE
#define DoSomething DoSomethingW
#else
#define DoSomething DoSomethingA
#endif
and DoSomethingA is
extern "C" bool __cdecl DoSomethingA(LPSTR result, int len)
{
CArray<WCHAR> data;
data.SetSize(len);
if(!DoSomethingW(data.GetData(), len))
return false;
WideCharToMultiByte(CP_ACP, result, len, data.GetData(), -1, NULL, 0);
// I may have not gotten the parameters in the right order, check the docs
// error detection and response left as EFTR
return true;
}
A major improvement over the piece of trash code shown was that I actually use an explicit
length, which is what every string-modifying piece of code should do. The code as
suggested by the OP represents obsolete, sloppy thinking and poor implementation.
****
****
I liked your repsonse though. I didn't even consider that OP would want to
perhaps fill the string. If that's the case then making the parametere a
LPCTSTR is definitely wrong, but if the DLL is using the string without
modifying it then that would be the better way to do it just to be sure. I
think we need to see some more of the code if possible.
Like too many people asking a question, the OP shows half the code required to figure out
what is going on (most of the rest seem to show no code and expect us to guess...). We
see the prototype used on the "client" side of the DLL, but we do NOT see the actual
prototype of the DLL function!
*****
Joseph M. Newcomer [MVP]
Tom
"Joseph M. Newcomer" <newcomer@xxxxxxxxxxxx> wrote in message
news:sar964l2uh4j4s05h072dfn19fujchsco6@xxxxxxxxxx
See below...
On Fri, 27 Jun 2008 05:18:33 -0700 (PDT), "divya_rathore_@xxxxxxxxx"
<divyarathore@xxxxxxxxx> wrote:
I have a Win32 dll interface:****
typedef bool (__cdecl *TITLEPTR)(LPCTSTR);
and I want a string to be populated by calling this inside a UNICODE
enabled MFC App (VS2008):
CString str;
if (!(*pfn3)( str.GetBuffer(256)) )
This is totally weird syntax. If pfn3 is a pointer to a function, you can
call it with
pfn3(str.GetBuffer(256);
The silly (*pfn3) notation has not been required since K&R C and is
considered obsolete,
used only for backward compatibility with old programs written before
ANSI/ISO C.
Therefore, there is no reason to use this obsolete and clumsy notation.
Note that in any sensible interface, you would pass in a pointer to the
string AND A
LENGTH; how is it that you know for certain that 256 is the correct amount
of space to
allocate (and if you "it's a file name" you're in trouble, because file
names by default
are longer than 256; take a look at MAX_PATH)
{****
MessageBox(_T("Some Problemo!"));
}
..All I am getting in str is jumbled characters (ANSI?).
I see no ReleaseBuffer here. It won't work if you don't call
ReleaseBuffer
****
How can I get the string str populated properly? I am clearly missing****
some Unicode concepts here.
If your app is Unicode, and your DLL returns 8-bit characters, you would
declare
CStringA str;
which gives you an 8-bit string, but then you wouldn't be using LPCTSTR as
the prototype
of the function, if it returned 8-bit strings; it would LPSTR. LPCTSTR
says that it will
take 8-bit strings in an 8-bit app, and Unicode strings in a Unicode app,
AND THAT THIS
PARAMETER REPRESENTS CONSTANT DATA AND WILL THEREFORE NOT BE MODIFIED. If
the purpose is
to fill a buffer, it would have to be LPTSTR (for ANSI/Unicode), LPSTR
(for ANSI) or
LPWSTR (for Unicode). Since it is a DLL, you have to declare data of the
correct type
that matches the prototype of the function. Because it is a DLL, you have
to use the
header file it was compiled with to determine the correct typedef for your
function. You
can't just invent one out of thin air and expect it to work.
joe
****
Joseph M. Newcomer [MVP]
warm regards,
Divya Rathore
email: newcomer@xxxxxxxxxxxx
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
email: newcomer@xxxxxxxxxxxx
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
.
- Follow-Ups:
- Re: Populating CString in Win32 dll interface that accepts LPCTSTR
- From: Tom Serface
- Re: Populating CString in Win32 dll interface that accepts LPCTSTR
- References:
- Populating CString in Win32 dll interface that accepts LPCTSTR
- From: divya_rathore_@xxxxxxxxx
- Re: Populating CString in Win32 dll interface that accepts LPCTSTR
- From: Joseph M . Newcomer
- Re: Populating CString in Win32 dll interface that accepts LPCTSTR
- From: Tom Serface
- Populating CString in Win32 dll interface that accepts LPCTSTR
- Prev by Date: Re: Folderselector dialog problems.
- Next by Date: Re: How to increase the video memory
- Previous by thread: Re: Populating CString in Win32 dll interface that accepts LPCTSTR
- Next by thread: Re: Populating CString in Win32 dll interface that accepts LPCTSTR
- Index(es):
Relevant Pages
|
Loading