Convert a Widestring to an Ascii String?

M

Marc

Hello dear,

I have a string and every second char is a \0. Can I somehow convert it to a
normal string. Or may-be in the underlying code I am doing something wrong,
choose the wrong C# type?

This is my function I am trying to get right:

public static bool GetPrivateProfileSectionAsCS(string appName, string
fileName, out string section)
{
section = null;
if (!System.IO.File.Exists(fileName))
return false;
uint MAX_BUFFER = 32767;
IntPtr pReturnedString = Marshal.AllocCoTaskMem((int)MAX_BUFFER);
uint bytesReturned = GetPrivateProfileSectionW(appName, pReturnedString,
MAX_BUFFER, fileName);
if ((bytesReturned == MAX_BUFFER - 2) || (bytesReturned == 0))
return false;
System.Text.StringBuilder returnedString = new
System.Text.StringBuilder((int)bytesReturned);
//bytesReturned -1 to remove trailing \0
for (int i = 0; i < bytesReturned - 1; i++)
returnedString.Append((char)Marshal.ReadByte(new
IntPtr((uint)pReturnedString + (uint)i)));
Marshal.FreeCoTaskMem(pReturnedString);
section = returnedString.ToString();
section.Replace("\0", ""); // this does not work
return true;
}

And this is how my string section looks like:

"N\0U\0M\0B\0E\0R\0=\0f\0t\0A\0u\0t\0o\0I\0n\0c\0\0\0S\0t\0a\0t\0u\0s\0N\0r\0=\0I\0D\0A\0\0\0P\0a\0t\0N\0a\0m\0e\0=\0N\0o\0t\0U\0s\0e\0d\0\0\0D\0a\0t\0e\0=\0T\0x\0_\0D\0t\0T\0m\0<\0r\0e\0g\0e\0x\0>\0(\00\0[\01\0-\09\0]\0|\0[\01\02\0]\0[\00\0-\09\0]\0|\03\0[\00\01\0]\0)\0-\0(\00\0[\01\0-\09\0]\0|\01\0[\00\01\02\0]\0)\0-\0(\01\09\0|\02\00\0)\0[\00\0-\09\0]\0[\00\0-\09\0]\0<\0/\0r\0e\0g\0e\0x\0>\0\0\0T\0i\0m\0e\0=\0T\0x\0_\0D\0t\0T\0m\0<\0r\0e\0g\0e\0x\0>\0[\00\0-\09\0]\0[\00\0-\09\0]\0:\0[\00\0-\09\0]\0[\00\0-\09\0]\0:\0[\00\0-\09\0]\0[\00\0-\09\0]\0<\0/\0r\0e\0g\0e\0x\0>\0\0\0V\0e\0l\0d\0n\0a\0a\0m\0=\0F\0i\0e\0l\0d\0_\0L\0a\0b\0e\0l\0+\0F\0i\0e\0l\0d\0_\0N\0a\0m\0e\0\0\0C\0l\0i\0n\0i\0c\0=\0T\0s\0t\0l\0\0\0B\0e\0a\0m\0N\0r\0=\0N\0o\0t\0U\0s\0e\0d\0\0\0S\0e\0g\0m\0N\0r\0=\0N\0o\0t\0U\0s\0e\0d\0\0\0T\0e\0r\0m\0i\0n\0a\0t\0e\0=\0N\0o\0t\0U\0s\0e\0d\0\0\0D\0i\0a\0p\0h\0P\0r\0e\0s\0c\0=\0N\0o"
 
J

Jon Skeet [C# MVP]

I have a string and every second char is a \0. Can I somehow convert it to a
normal string. Or may-be in the underlying code I am doing something wrong,
choose the wrong C# type?

I don't know the details of GetPrivateProfileSectionW, but you may
well be able to get away with creating a byte[] instead of using
AllocCoTaskMem to return an IntPtr. You can then pass that byte[] into
GetPrivateProfileSectionW and use Encoding.Unicode afterwards.

Otherwise, use Marshal.Copy to copy the data into a byte[], and then
again you can use Encoding.Unicode to turn the data into a string.

If these don't work, it's worth asking on the .interop newsgroup.

Jon
 
N

Nicholas Paldino [.NET/C# MVP]

Or, he could just use a definition of GetPrivateProvideSection which
would marshal the string correctly. A declaration that uses bytes in the
parameter doesn't do any good.

The declaration should be:

[DllImport("kernel32.dll", CharSet=CharSet.Auto)]
static extern uint GetPrivateProfileString(
string lpAppName,
string lpKeyName,
string lpDefault,
[In, Out] char[] lpReturnedString,
uint nSize,
string lpFileName);

The use of the char array is to prevent the marshaling layer from not
sending back all of the characters in the string after finding the first
null character.

It makes it a lot easier than allocating the memory and whatnot (which
should have been placed in a try/finally block, in the case of an
exception).


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)


Jon Skeet said:
I have a string and every second char is a \0. Can I somehow convert it
to a
normal string. Or may-be in the underlying code I am doing something
wrong,
choose the wrong C# type?

I don't know the details of GetPrivateProfileSectionW, but you may
well be able to get away with creating a byte[] instead of using
AllocCoTaskMem to return an IntPtr. You can then pass that byte[] into
GetPrivateProfileSectionW and use Encoding.Unicode afterwards.

Otherwise, use Marshal.Copy to copy the data into a byte[], and then
again you can use Encoding.Unicode to turn the data into a string.

If these don't work, it's worth asking on the .interop newsgroup.

Jon
 
M

Marc

Nicholas Paldino said:
Or, he could just use a definition of GetPrivateProvideSection which
would marshal the string correctly. A declaration that uses bytes in the
parameter doesn't do any good.

The declaration should be:

[DllImport("kernel32.dll", CharSet=CharSet.Auto)]
static extern uint GetPrivateProfileString(

I am using GetPrivateProfileSECTION not GetPrivateProfileSTRING

But I guess the defintion should be:

[DllImport("kernel32.dll", CharSet=CharSet.Auto)]
static extern uint GetPrivateProfileSection(
string lpAppName,
[In, Out] char[] lpReturnedString,
uint nSize,
string lpFileName);

And this I am using in my program:

[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
static extern uint GetPrivateProfileSectionW(string lpAppName, IntPtr
lpReturnedString, uint nSize, string lpFileName);

public static bool GetPrivateProfileSectionAsCS(string appName, string
fileName, out string section)
{

So there is a difference, but do not ask me now what is correct.

And there is also this little problem. The section is not one null
terminated string but several. This is in MSDN

"The format of the returned keys and values is one or more null-terminated
strings, followed by a final null character. Each string has the following
form: key=string"

I've already used GetPrivateProfileSTRING, that one was easy. Ok, I will
look into it and thanks for suggestions.
 
N

Nicholas Paldino [.NET/C# MVP]

Marc,

Regardless, if you use the character array, then you can parse the
character array, looking for the null characters, and splitting the strings
apart that way.


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

Marc said:
Nicholas Paldino said:
Or, he could just use a definition of GetPrivateProvideSection which
would marshal the string correctly. A declaration that uses bytes in the
parameter doesn't do any good.

The declaration should be:

[DllImport("kernel32.dll", CharSet=CharSet.Auto)]
static extern uint GetPrivateProfileString(

I am using GetPrivateProfileSECTION not GetPrivateProfileSTRING

But I guess the defintion should be:

[DllImport("kernel32.dll", CharSet=CharSet.Auto)]
static extern uint GetPrivateProfileSection(
string lpAppName,
[In, Out] char[] lpReturnedString,
uint nSize,
string lpFileName);

And this I am using in my program:

[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
static extern uint GetPrivateProfileSectionW(string lpAppName, IntPtr
lpReturnedString, uint nSize, string lpFileName);

public static bool GetPrivateProfileSectionAsCS(string appName, string
fileName, out string section)
{

So there is a difference, but do not ask me now what is correct.

And there is also this little problem. The section is not one null
terminated string but several. This is in MSDN

"The format of the returned keys and values is one or more null-terminated
strings, followed by a final null character. Each string has the following
form: key=string"

I've already used GetPrivateProfileSTRING, that one was easy. Ok, I will
look into it and thanks for suggestions.
 
M

Marc

Nicholas Paldino said:
Marc,

Regardless, if you use the character array, then you can parse the
character array, looking for the null characters, and splitting the
strings apart that way.

Hey thanks, this works:

[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
static extern uint GetPrivateProfileSection(string lpAppName, [In, Out]
char[] lpReturnedString, uint nSize, string lpFileName);
//
public static bool GetPrivateProfileSectionAsCommaText(string appName,
string fileName, out string section)
{
section = "";
uint MAX_BUFFER = 327670;
char[] sectionchar = new char[MAX_BUFFER];
if (!System.IO.File.Exists(fileName))
return false;
uint bytesReturned = GetPrivateProfileSection(appName, sectionchar,
MAX_BUFFER, fileName);
if ((bytesReturned == MAX_BUFFER - 2) || (bytesReturned == 0))
return false;
for (int i = 0; i < bytesReturned; i++)
{
if (sectionchar != (char)0)
section += sectionchar;
else
{
if (i != bytesReturned - 1) section += ',';
}
}
return true;
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top