cannot marshall parameter error on call to win32 api - FormatMessage

S

Steve Richter

I have a C++ forms project that I am adding some unmanaged code to. I
have a member function of the Form1 class that returns a String^
holding the text of the last win32 error. The code is failing on the
call to FormatMessage.

Cannot marshal 'parameter #7': Pointers cannot reference marshaled
structures. Use ByRef instead.

how do I pass the argument ByRef and why is managed code involved in
this api call? FormatMessage is an unmanaged api and all of the
variables are unmanaged.

thanks,


String^ FormatMessage( DWORD rc )
{
String^ sMsg ;
LPVOID pMsgBuf = NULL ;
DWORD nRc ;

nRc = ::FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL, rc, MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)&pMsgBuf, 0, NULL ) ;

if ( pMsgBuf == NULL )
sMsg = L"Unknown return code " ;
else
{
sMsg = gcnew String( (wchar_t*) pMsgBuf ) ;
}

if ( pMsgBuf != NULL )
LocalFree( pMsgBuf ) ;

return sMsg ;
}
 
T

Tamas Demjen

Steve said:
Cannot marshal 'parameter #7': Pointers cannot reference marshaled
structures. Use ByRef instead.

You must have a name collision. You're probably not calling the
unmanaged Win32 FormatMessage, but another function that happens to have
the same name.

Your code compiles for me without any errors (VC++2005 SP1). Just try to
put it into an empty unit, like this:

// FormatMessage.cpp
#include "stdafx.h"
#include <windows.h>

using namespace System;

String^ FormatMessage( DWORD rc )
<snip> // your code unchanged

If that still doesn't work, remove #include "stdafx.h" and disable
precompiled headers for that unit.

Tom
 
S

Steve Richter

You must have a name collision. You're probably not calling the
unmanaged Win32 FormatMessage, but another function that happens to have
the same name.

Your code compiles for me without any errors (VC++2005 SP1). Just try to
put it into an empty unit, like this:

// FormatMessage.cpp
#include "stdafx.h"
#include <windows.h>

using namespace System;

String^ FormatMessage( DWORD rc )
<snip> // your code unchanged

If that still doesn't work, remove #include "stdafx.h" and disable
precompiled headers for that unit.

Tom

thanks for the help. The solution ended up being a change in the
project from "pure MSIL CLR support" to what I guess is a more
flexible "clr support".

now I am reading in the archives that I cant call my C++ code from C#
unless the c++ is pure MSIL? The FormatMessage API bombed on the last
argument, a VARARG or whatever it is called. How do I know what
unmanaged code can be included in a "pure MSIL" project and what cant?

-Steve
 
B

Ben Voigt

Steve Richter said:
thanks for the help. The solution ended up being a change in the
project from "pure MSIL CLR support" to what I guess is a more
flexible "clr support".

now I am reading in the archives that I cant call my C++ code from C#
unless the c++ is pure MSIL? The FormatMessage API bombed on the last

That is most assuredly false. MSIL vs native code does have implications
for security (native code cannot run without full trust), but C# can call
into mixed assemblies just fine.
argument, a VARARG or whatever it is called. How do I know what
unmanaged code can be included in a "pure MSIL" project and what cant?

In pure MSIL, every API call has to be converted to a DllImport statement.
If there's no conversion, it won't work.

In the case of FormatMessage, it's not that MSIL can't make the call, it's
that the compiler hasn't enough information to construct the P/Invoke
signature. However, you could do that yourself, just as doing P/Invoke from
C# (http://www.pinvoke.net/default.aspx/kernel32/FormatMessage.html)
 
M

Mattias Sjögren

In the case of FormatMessage, it's not that MSIL can't make the call, it's
that the compiler hasn't enough information to construct the P/Invoke
signature. However, you could do that yourself, just as doing P/Invoke from
C# (http://www.pinvoke.net/default.aspx/kernel32/FormatMessage.html)

Or take advantage of the fact that the Win32Exception class calls
FormatMessage internally. Something like this should do it I think

String^ FormatMessage( DWORD rc )
{
Win32Exception^ ex = gcnew Win32Exception((int)rc);
return ex->Message;
}


Mattias
 

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