Re: Populating CString in Win32 dll interface that accepts LPCTSTR



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!
*****

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
****


warm regards,
Divya Rathore
Joseph M. Newcomer [MVP]
email: newcomer@xxxxxxxxxxxx
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
Joseph M. Newcomer [MVP]
email: newcomer@xxxxxxxxxxxx
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
.



Relevant Pages

  • Re: VB6 ANSI to Unicode conversion wrong with fixed-length strings in structures
    ... when a string is passed ByRef. ... One way to show Unicode ... > I have a Fortran DLL that returns a structure containing fixed-length ... > returning Chinese characters. ...
    (microsoft.public.vb.bugs)
  • Re: Populating CString in Win32 dll interface that accepts LPCTSTR
    ... I've only had to call ReleaseBuffer() if I actually modify the buffer after GetBuffer is called and I only call GetBufferif I want to modify the string directly or the calling parameter demands a LPTSTR. ... and I want a string to be populated by calling this inside a UNICODE ...
    (microsoft.public.vc.mfc)
  • Re: Change the font
    ... I don't have code of DLL. ... I think we should have facility to change the font of any string. ... I have also tried by taking a unicode string and converting it to ... display strings that contain ASCII characters only. ...
    (microsoft.public.vc.mfc.docview)
  • Re: Populating CString in Win32 dll interface that accepts LPCTSTR
    ... As others have noted, you should not be passing a constant string here. ... Also, using the TCHAR apparatus across DLL boundaries is somewhat dangerous, because the Unicode conventions may not match. ... I tend to use either char or wchar_t in my DLL interfaces; then the compiler will tell you if your application is using the DLL in the wrong way. ...
    (microsoft.public.vc.mfc)
  • Re: Unicode String Parameters in DLLs
    ... Unicode, so you might have heard some stuff about that. ... It doesn't so any kind of conversion before or after the DLL ... string ); it does not terminate the string. ... but I've only tested it with standard characters (i.e. ...
    (microsoft.public.word.vba.general)

Loading