🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Thread View: borland.public.cppbuilder.nativeapi
2 messages
2 total messages Started by Mark Guerrieri Mon, 11 Dec 2006 18:15
Problem converting WideString to AnsiString
#2857
Author: Mark Guerrieri
Date: Mon, 11 Dec 2006 18:15
88 lines
3583 bytes
I have the following functions that are called from within the context of a
thread:

//--------------------------------------------------------------------------
-

int  __fastcall TCCSMsgObjectEx::BuildMessageFromString(const AnsiString&
cMessage)
{
  int nSize = cMessage.Length();
  if(FMessageBuffer == NULL || nSize > (int)FMessageSize)
  {
    if(FMessageBuffer)
      free(FMessageBuffer);
    FMessageBuffer = (BYTE*)malloc(nSize);
    if(FMessageBuffer == NULL)
     OutOfMemoryError();
  }
  FMessageSize = nSize;
  memcpy(FMessageBuffer, cMessage.c_str(), nSize);
  return FMessageSize;
}
//--------------------------------------------------------------------------
-

int  __fastcall TCCSMsgObjectEx::BuildMessageFromString(const WideString&
cMessage)
{
  int nSize = ::WideCharToMultiByte(CP_ACP, 0, cMessage.c_bstr(),
cMessage.Length(), 0, 0, NULL, NULL);

  if(nSize <= 0)
    RaiseLastOSError();

  if(FMessageBuffer == NULL || nSize > (int)FMessageSize)
  {
    if(FMessageBuffer)
      free(FMessageBuffer);
    FMessageBuffer = (BYTE*)malloc(nSize);
    if(FMessageBuffer == NULL)
     OutOfMemoryError();
  }
  FMessageSize = nSize;
  nSize = ::WideCharToMultiByte(CP_ACP, 0, cMessage.c_bstr(),
cMessage.Length(), FMessageBuffer, nSize, NULL, NULL);
  if(nSize <= 0)
   RaiseLastOSError();

  return FMessageSize;
}
//--------------------------------------------------------------------------
-

FMessageBuffer (BYTE*) and FMessageSize (int) are internal to the class.

I retrieve a WideString value wValue, and call:

BuildMessageFromString(wValue);

The first call to ::WideCharToMultiByte to get the size of the buffer ALWAYS
returns 0 with GetLastError returning 87- "The Parameter is Incorrect"

If I do the following:

AnsiString cValue = AnsiString(wValue);
BuildMessageFromString(cValue);

then everything works as expected.

wValue is a 54 character string that begins with 12 NULL characters and has
other NULL characters in other positions as well.  The AnsiString cValue is
correct in that it has a length of 54 and scanning the strings yields the
correctly converted characters (which all happen to be ansi anyway.)

So why does ::WideCharToMultiByte fail every time?  If I pass -1 for the
input buffer length, then the fuction suceeds, but sees this as a NULL
string since the first character is a NULL.

The string stored in wValue may get quite large at times and I would like to
avoid the overhead of converting to AnsiString first then storing the
results in the buffer; ::WideCharToMultiByte should just store directly to
the buffer for me, it can't seem to handle my NULL-infested string...

Any ideas?

Mark

Mark
Re: Problem converting WideString to AnsiString
#2858
Author: Remy Lebeau (TeamB)
Date: Mon, 11 Dec 2006 19:18
77 lines
3501 bytes
"Mark Guerrieri" <mguerrieri@nospam_cmsgrp.com> wrote in message
news:457da01d@newsgroups.borland.com...

> The first call to ::WideCharToMultiByte to get the size of the buffer
> ALWAYS returns 0 with GetLastError returning 87- "The Parameter
> is Incorrect"

One thing I notice is that you are not taking into account that
WideString::c_bstr() will return a NULL pointer when the Length() is 0.
Unlike AnsiString::c_str(), which returns a non-NULL pointer instead.  The
lpWideCharStr parameter of WideCharToMultiByte() cannot be NULL.

Try this instead:

    int  __fastcall TCCSMsgObjectEx::BuildMessageFromString(const
WideString& cMessage)
    {
        int nSize;

        if( cMessage.Length() > 0 )
        {
            nSize = ::WideCharToMultiByte(CP_ACP, 0, cMessage.c_bstr(),
cMessage.Length(), NULL, 0, NULL, NULL);
            if( nSize <= 0 )
                RaiseLastOSError();
        }
        else
            nSize = 0;

        if( (!FMessageBuffer) || (nSize > (int)FMessageSize) )
        {
            if(FMessageBuffer)
                free(FMessageBuffer);
            if( nSize > 0 )
            {
                FMessageBuffer = (BYTE*) malloc(nSize);
                if( !FMessageBuffer )
                    OutOfMemoryError();
            }
        }
        FMessageSize = nSize;

        if( nSize > 0 )
        {
            nSize = ::WideCharToMultiByte(CP_ACP, 0, cMessage.c_bstr(),
cMessage.Length(), FMessageBuffer, nSize, NULL, NULL);
            if( nSize <= 0 )
                RaiseLastOSError();
        }

        return FMessageSize;
    }

> If I do the following:
>
> AnsiString cValue = AnsiString(wValue);
> BuildMessageFromString(cValue);
>
> then everything works as expected.

As it should be, because the WideString->AnsiString conversion handles the
condition where the WideString may be empty.

> The string stored in wValue may get quite large at times and I would like
> to avoid the overhead of converting to AnsiString first then storing the
> results in the buffer; ::WideCharToMultiByte should just store directly to
> the buffer for me, it can't seem to handle my NULL-infested string...

Yes, it can, as the VCL uses WideCharToMultiByte() internally for its own
conversion.  If the NULL characters were tripping up WideCharToMultiByte()
in general, then the VCL would be effected as well, which is obviously not
the case.  So the more likely cause is that your use of the function is
simply wrong.  Which is evident by the 87 error code.


Gambit
Thread Navigation

This is a paginated view of messages in the thread with full content displayed inline.

Messages are displayed in chronological order, with the original post highlighted in green.

Use pagination controls to navigate through all messages in large threads.

Back to All Threads