P/Invoking FormatMessage

J

jonfroehlich

I have seen many posts about p/invoking FormatMessage to convert an
error code to a string--unfortunately I can't seem to get it to work.
I read in the SmartPhone SDK that not all Windows CE-based devices
will contain the system message-table resources (when
FORMAT_MESSAGE_FROM_SYSTEM is specified), I'm wondering if that's my
problem? (I'm on a Cingular 2125 WM 5 device running .NET 2.0 SP1).
Also, is there a canonical error code that I can pass to these
functions to test them out?

I've implemented it in two ways (the first way is preferable--less
code).

[DllImport("coredll.dll", SetLastError = true)]
public static extern int FormatMessage(int dwFlags, IntPtr lpSource,
int dwMessageId, int dwLanguageId, StringBuilder lpBuffer, int nSize,
IntPtr Arguments);

public static string GetErrorMessage(int errorCode)
{
StringBuilder sb = new StringBuilder(1024);
int error = FormatMessage(FormatMessageFlags.FromSystem,
IntPtr.Zero, errorCode, 0, sb, sb.Capacity, IntPtr.Zero);
Debug.WriteLine("GetErrorMessage : FormatMessage returned:" +
error);
return sb.ToString();
}

FormatMessage always returns 0. I've also tried it this way (from
pinvoke.net):

[DllImport("coredll.dll", SetLastError = true)]
static extern uint FormatMessage(uint dwFlags, IntPtr lpSource,
uint dwMessageId, uint dwLanguageId, ref IntPtr lpBuffer,
uint nSize, IntPtr pArguments);

[DllImport("coredll.dll", SetLastError = true)]
static extern IntPtr LocalFree(IntPtr hMem);

public static string GetErrorMessage2(int errorCode)
{
// from header files
const uint FORMAT_MESSAGE_ALLOCATE_BUFFER = 0x00000100;
const uint FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200;
const uint FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000;

IntPtr lpMsgBuf = IntPtr.Zero;

uint dwChars = FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
IntPtr.Zero,
(uint)errorCode,
0, // Default language
ref lpMsgBuf,
0,
IntPtr.Zero);

if (dwChars == 0)
{
// Handle the error.
int le = Marshal.GetLastWin32Error();
return null;
}

string sRet = Marshal.PtrToStringUni(lpMsgBuf);

// Free the buffer.
lpMsgBuf = LocalFree(lpMsgBuf);
return sRet;
}

In this case, dwChars is always 0 and calling GetLastWin32Error=317.
 
P

Peter Foot [MVP]

Suggest you use Tools > Error Lookup in Visual Studio to check the return
code - 317 is "The system cannot find message text for message number 0x%1
in the message file for %2.". Since it appears that Smartphone doesn't have
error text resources, have you tried testing your code on another platform
e.g. the Pocket PC Emulator or a generic CE device?

Since you can't rely on the target device having the message strings, you
may be better having your own friendly error messages defined for common
error scenarios, and not rely on FormatMessage.

Peter

--
Peter Foot
Device Application Development MVP
www.peterfoot.net | www.inthehand.com

jonfroehlich said:
I have seen many posts about p/invoking FormatMessage to convert an
error code to a string--unfortunately I can't seem to get it to work.
I read in the SmartPhone SDK that not all Windows CE-based devices
will contain the system message-table resources (when
FORMAT_MESSAGE_FROM_SYSTEM is specified), I'm wondering if that's my
problem? (I'm on a Cingular 2125 WM 5 device running .NET 2.0 SP1).
Also, is there a canonical error code that I can pass to these
functions to test them out?

I've implemented it in two ways (the first way is preferable--less
code).

[DllImport("coredll.dll", SetLastError = true)]
public static extern int FormatMessage(int dwFlags, IntPtr lpSource,
int dwMessageId, int dwLanguageId, StringBuilder lpBuffer, int nSize,
IntPtr Arguments);

public static string GetErrorMessage(int errorCode)
{
StringBuilder sb = new StringBuilder(1024);
int error = FormatMessage(FormatMessageFlags.FromSystem,
IntPtr.Zero, errorCode, 0, sb, sb.Capacity, IntPtr.Zero);
Debug.WriteLine("GetErrorMessage : FormatMessage returned:" +
error);
return sb.ToString();
}

FormatMessage always returns 0. I've also tried it this way (from
pinvoke.net):

[DllImport("coredll.dll", SetLastError = true)]
static extern uint FormatMessage(uint dwFlags, IntPtr lpSource,
uint dwMessageId, uint dwLanguageId, ref IntPtr lpBuffer,
uint nSize, IntPtr pArguments);

[DllImport("coredll.dll", SetLastError = true)]
static extern IntPtr LocalFree(IntPtr hMem);

public static string GetErrorMessage2(int errorCode)
{
// from header files
const uint FORMAT_MESSAGE_ALLOCATE_BUFFER = 0x00000100;
const uint FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200;
const uint FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000;

IntPtr lpMsgBuf = IntPtr.Zero;

uint dwChars = FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
IntPtr.Zero,
(uint)errorCode,
0, // Default language
ref lpMsgBuf,
0,
IntPtr.Zero);

if (dwChars == 0)
{
// Handle the error.
int le = Marshal.GetLastWin32Error();
return null;
}

string sRet = Marshal.PtrToStringUni(lpMsgBuf);

// Free the buffer.
lpMsgBuf = LocalFree(lpMsgBuf);
return sRet;
}

In this case, dwChars is always 0 and calling GetLastWin32Error=317.
 
J

jonfroehlich

Peter,

Thanks, I was not aware of such a tool. To clarify for readers, I
found the error lookup tool in C:\Program Files\Microsoft Visual
Studio 8\Common7\Tools (called errlook.exe). It was not listed in
Start Menu->Visual Studio Tools nor was it found in the Tools menu in
Visual Studio.

The error code I was passing FormatMessage was actually from the
Win32Exception.NativeErrorCode property, which was thrown from
SmsMessage.Send(). I was receiving two error codes:

-2113928702 : 0x82000202 : SMS_E_SIM - Problem with the subscriber
identity module (SIM).
-2113928691 : 0x8200020D : SMS_E_RADIOUNAVAILABLE - The radio hardware
is unavailable.

I looked up the error codes manually here: http://msdn2.microsoft.com/en-us/library/aa455072.aspx.
Is there no way to automate retrieving these error strings? If not,
what's the best practice? Should I basically copy the textual strings
from the docs and create my own error code mapping?

Thanks,

Jon

--
http://csharponphone.blogspot.com
Suggest you use Tools > Error Lookup in Visual Studio to check the return
code - 317 is "The system cannot find message text for message number 0x%1
in the message file for %2.". Since it appears that Smartphone doesn't have
error text resources, have you tried testing your code on another platform
e.g. the Pocket PC Emulator or a generic CE device?

Since you can't rely on the target device having the message strings, you
may be better having your own friendly error messages defined for common
error scenarios, and not rely on FormatMessage.

Peter

--
Peter Foot
Device Application Development MVPwww.peterfoot.net|www.inthehand.com


I have seen many posts about p/invoking FormatMessage to convert an
error code to a string--unfortunately I can't seem to get it to work.
I read in the SmartPhone SDK that not all Windows CE-based devices
will contain the system message-table resources (when
FORMAT_MESSAGE_FROM_SYSTEM is specified), I'm wondering if that's my
problem? (I'm on a Cingular 2125 WM 5 device running .NET 2.0 SP1).
Also, is there a canonical error code that I can pass to these
functions to test them out?
I've implemented it in two ways (the first way is preferable--less
code).
[DllImport("coredll.dll", SetLastError = true)]
public static extern int FormatMessage(int dwFlags, IntPtr lpSource,
int dwMessageId, int dwLanguageId, StringBuilder lpBuffer, int nSize,
IntPtr Arguments);
public static string GetErrorMessage(int errorCode)
{
StringBuilder sb = new StringBuilder(1024);
int error = FormatMessage(FormatMessageFlags.FromSystem,
IntPtr.Zero, errorCode, 0, sb, sb.Capacity, IntPtr.Zero);
Debug.WriteLine("GetErrorMessage : FormatMessage returned:" +
error);
return sb.ToString();
}
FormatMessage always returns 0. I've also tried it this way (from
pinvoke.net):
[DllImport("coredll.dll", SetLastError = true)]
static extern uint FormatMessage(uint dwFlags, IntPtr lpSource,
uint dwMessageId, uint dwLanguageId, ref IntPtr lpBuffer,
uint nSize, IntPtr pArguments);
[DllImport("coredll.dll", SetLastError = true)]
static extern IntPtr LocalFree(IntPtr hMem);
public static string GetErrorMessage2(int errorCode)
{
// from header files
const uint FORMAT_MESSAGE_ALLOCATE_BUFFER = 0x00000100;
const uint FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200;
const uint FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000;
IntPtr lpMsgBuf = IntPtr.Zero;
uint dwChars = FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
IntPtr.Zero,
(uint)errorCode,
0, // Default language
ref lpMsgBuf,
0,
IntPtr.Zero);
if (dwChars == 0)
{
// Handle the error.
int le = Marshal.GetLastWin32Error();
return null;
}
string sRet = Marshal.PtrToStringUni(lpMsgBuf);
// Free the buffer.
lpMsgBuf = LocalFree(lpMsgBuf);
return sRet;
}
In this case, dwChars is always 0 and calling GetLastWin32Error=317.
 
P

Peter Foot [MVP]

That's the best approach, especially with API specific error codes like the
SMS ones.

Peter

--
Peter Foot
Device Application Development MVP
www.peterfoot.net | www.inthehand.com

jonfroehlich said:
Peter,

Thanks, I was not aware of such a tool. To clarify for readers, I
found the error lookup tool in C:\Program Files\Microsoft Visual
Studio 8\Common7\Tools (called errlook.exe). It was not listed in
Start Menu->Visual Studio Tools nor was it found in the Tools menu in
Visual Studio.

The error code I was passing FormatMessage was actually from the
Win32Exception.NativeErrorCode property, which was thrown from
SmsMessage.Send(). I was receiving two error codes:

-2113928702 : 0x82000202 : SMS_E_SIM - Problem with the subscriber
identity module (SIM).
-2113928691 : 0x8200020D : SMS_E_RADIOUNAVAILABLE - The radio hardware
is unavailable.

I looked up the error codes manually here:
http://msdn2.microsoft.com/en-us/library/aa455072.aspx.
Is there no way to automate retrieving these error strings? If not,
what's the best practice? Should I basically copy the textual strings
from the docs and create my own error code mapping?

Thanks,

Jon

--
http://csharponphone.blogspot.com
Suggest you use Tools > Error Lookup in Visual Studio to check the return
code - 317 is "The system cannot find message text for message number
0x%1
in the message file for %2.". Since it appears that Smartphone doesn't
have
error text resources, have you tried testing your code on another
platform
e.g. the Pocket PC Emulator or a generic CE device?

Since you can't rely on the target device having the message strings, you
may be better having your own friendly error messages defined for common
error scenarios, and not rely on FormatMessage.

Peter

--
Peter Foot
Device Application Development MVPwww.peterfoot.net|www.inthehand.com


I have seen many posts about p/invoking FormatMessage to convert an
error code to a string--unfortunately I can't seem to get it to work.
I read in the SmartPhone SDK that not all Windows CE-based devices
will contain the system message-table resources (when
FORMAT_MESSAGE_FROM_SYSTEM is specified), I'm wondering if that's my
problem? (I'm on a Cingular 2125 WM 5 device running .NET 2.0 SP1).
Also, is there a canonical error code that I can pass to these
functions to test them out?
I've implemented it in two ways (the first way is preferable--less
code).
[DllImport("coredll.dll", SetLastError = true)]
public static extern int FormatMessage(int dwFlags, IntPtr lpSource,
int dwMessageId, int dwLanguageId, StringBuilder lpBuffer, int nSize,
IntPtr Arguments);
public static string GetErrorMessage(int errorCode)
{
StringBuilder sb = new StringBuilder(1024);
int error = FormatMessage(FormatMessageFlags.FromSystem,
IntPtr.Zero, errorCode, 0, sb, sb.Capacity, IntPtr.Zero);
Debug.WriteLine("GetErrorMessage : FormatMessage returned:" +
error);
return sb.ToString();
}
FormatMessage always returns 0. I've also tried it this way (from
pinvoke.net):
[DllImport("coredll.dll", SetLastError = true)]
static extern uint FormatMessage(uint dwFlags, IntPtr lpSource,
uint dwMessageId, uint dwLanguageId, ref IntPtr lpBuffer,
uint nSize, IntPtr pArguments);
[DllImport("coredll.dll", SetLastError = true)]
static extern IntPtr LocalFree(IntPtr hMem);
public static string GetErrorMessage2(int errorCode)
{
// from header files
const uint FORMAT_MESSAGE_ALLOCATE_BUFFER = 0x00000100;
const uint FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200;
const uint FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000;
IntPtr lpMsgBuf = IntPtr.Zero;
uint dwChars = FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
IntPtr.Zero,
(uint)errorCode,
0, // Default language
ref lpMsgBuf,
0,
IntPtr.Zero);
if (dwChars == 0)
{
// Handle the error.
int le = Marshal.GetLastWin32Error();
return null;
}
string sRet = Marshal.PtrToStringUni(lpMsgBuf);
// Free the buffer.
lpMsgBuf = LocalFree(lpMsgBuf);
return sRet;
}
In this case, dwChars is always 0 and calling GetLastWin32Error=317.
 
J

jonfroehlich

Thanks a lot Peter, your guidance is always appreciated.

--
http://csharponphone.blogspot.com

That's the best approach, especially with API specific error codes like the
SMS ones.

Peter

--
Peter Foot
Device Application Development MVPwww.peterfoot.net|www.inthehand.com


Thanks, I was not aware of such a tool. To clarify for readers, I
found the error lookup tool in C:\Program Files\Microsoft Visual
Studio 8\Common7\Tools (called errlook.exe). It was not listed in
Start Menu->Visual Studio Tools nor was it found in the Tools menu in
Visual Studio.
The error code I was passing FormatMessage was actually from the
Win32Exception.NativeErrorCode property, which was thrown from
SmsMessage.Send(). I was receiving two error codes:
-2113928702 : 0x82000202 : SMS_E_SIM - Problem with the subscriber
identity module (SIM).
-2113928691 : 0x8200020D : SMS_E_RADIOUNAVAILABLE - The radio hardware
is unavailable.
I looked up the error codes manually here:
http://msdn2.microsoft.com/en-us/library/aa455072.aspx.
Is there no way to automate retrieving these error strings? If not,
what's the best practice? Should I basically copy the textual strings
from the docs and create my own error code mapping?

--
http://csharponphone.blogspot.com
Suggest you use Tools > Error Lookup in Visual Studio to check the return
code - 317 is "The system cannot find message text for message number
0x%1
in the message file for %2.". Since it appears that Smartphone doesn't
have
error text resources, have you tried testing your code on another
platform
e.g. the Pocket PC Emulator or a generic CE device?
Since you can't rely on the target device having the message strings, you
may be better having your own friendly error messages defined for common
error scenarios, and not rely on FormatMessage.
Peter
--
Peter Foot
Device Application Development MVPwww.peterfoot.net|www.inthehand.com

I have seen many posts about p/invoking FormatMessage to convert an
error code to a string--unfortunately I can't seem to get it to work.
I read in the SmartPhone SDK that not all Windows CE-based devices
will contain the system message-table resources (when
FORMAT_MESSAGE_FROM_SYSTEM is specified), I'm wondering if that's my
problem? (I'm on a Cingular 2125 WM 5 device running .NET 2.0 SP1).
Also, is there a canonical error code that I can pass to these
functions to test them out?
I've implemented it in two ways (the first way is preferable--less
code).
[DllImport("coredll.dll", SetLastError = true)]
public static extern int FormatMessage(int dwFlags, IntPtr lpSource,
int dwMessageId, int dwLanguageId, StringBuilder lpBuffer, int nSize,
IntPtr Arguments);
public static string GetErrorMessage(int errorCode)
{
StringBuilder sb = new StringBuilder(1024);
int error = FormatMessage(FormatMessageFlags.FromSystem,
IntPtr.Zero, errorCode, 0, sb, sb.Capacity, IntPtr.Zero);
Debug.WriteLine("GetErrorMessage : FormatMessage returned:" +
error);
return sb.ToString();
}
FormatMessage always returns 0. I've also tried it this way (from
pinvoke.net):
[DllImport("coredll.dll", SetLastError = true)]
static extern uint FormatMessage(uint dwFlags, IntPtr lpSource,
uint dwMessageId, uint dwLanguageId, ref IntPtr lpBuffer,
uint nSize, IntPtr pArguments);
[DllImport("coredll.dll", SetLastError = true)]
static extern IntPtr LocalFree(IntPtr hMem);
public static string GetErrorMessage2(int errorCode)
{
// from header files
const uint FORMAT_MESSAGE_ALLOCATE_BUFFER = 0x00000100;
const uint FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200;
const uint FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000;
IntPtr lpMsgBuf = IntPtr.Zero;
uint dwChars = FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
IntPtr.Zero,
(uint)errorCode,
0, // Default language
ref lpMsgBuf,
0,
IntPtr.Zero);
if (dwChars == 0)
{
// Handle the error.
int le = Marshal.GetLastWin32Error();
return null;
}
string sRet = Marshal.PtrToStringUni(lpMsgBuf);
// Free the buffer.
lpMsgBuf = LocalFree(lpMsgBuf);
return sRet;
}
In this case, dwChars is always 0 and calling GetLastWin32Error=317.
 

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