Problem with P/Invoke

  • Thread starter Thread starter chandra.somesh
  • Start date Start date
C

chandra.somesh

Hi
I am trying to import a c++ code in c# using p/invoke but am having
some trouble in implementing it.

C++ code inside the dll

namespace abc{

class __declspec(dllexport) CommandLineParams{

void getCmdLineParams(wstring cc.wstring name );

};
}

C# code for p/invoke is this

[DllImport("Strider.dll")]
public extern void CommandLineParams.getCmdLineParams(string
cc, string Name);

when it use dumpbin to see what data is inside the dll , i see
following signature of this function

?getCmdLineParams@CommandLineParams@abc@@AAAXV?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@0000@Z
(private: void __cdecl abc::CommandLineParams::getCmdLineParams(class
std::basic_string<wchar_t,struct std::char_traits<wchar_t>,class
std::allocator<wchar_t> >,class std::basic_string<wchar_t,struct
std::char_traits<wchar_t>,class std::allocator<wchar_t> >))


Now i can't understand a thing in this signature ....

What am i doing wrong ? What should be the correct format of p/invoke ?

thanks in advance
Somesh
 
Thanks for replying..

I am now using a wrapper class to access the functions of the dll ....
however i get an exception with code 0xC0000005 .
I have pinvoked a function which expects a wstring while i send it a
string from the managed side...could that be a reason for the exception
or is it something else

Somesh
 
ok...so wstring is not supported by the marshaler ... so i am sticking
with plain system.string on both c# and c++ side and have used a
string2wstring converting logic on c++ side.....however i still get the
same exception .

Note that i am sending the parameters as system.string to the imported
function and not inside a complex object(struct etc..)

So where could the error be ? The entry point to the function is also
good and have verified it to be correct.. i have put breakpoints on the
imported function on the c++ side , but i get this exception even
before reaching the c++ code ... so i am guessing the marshall is
throwing this exception..then how come its a 'native exception' ??

Somesh
 
i am posting the code again.....

C++ wrapper code inside the dll


namespace abc{
class __declspec(dllexport) CommandLineParams{

static void getCmdLineParams(string cc.string name );

};
}


C# code for p/invoke is this

[DllImport("Strider.dll",EntryPoint=""?getStriderWrapper@StriderWrapper@abc@@SAXV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@0000@Z"]

public extern static void
CommandLineParams.getCmdLineParams(string cc, string Name);


The entry point is copied from the dumpbin result and i have checked
that its the correct one. However the program never goes over to the
c++ part and throws exception before that.

Somesh
 
One other thing to be aware of is that the CompactFramework doesn't have any
support for changing the calling conventions in the DllImport attribute. CF
expects all exported DLL functions to be __stdcall and not cdecl. I think
the CF will detect the stack mixup and fix itself, but I don't know what
kind of impact that'll have.

Also, your C++ code is off a bit and will definitely NOT work with C#. You
have an exported class, not a function, and the class has a member you're
trying to call. The C# code can't instantiate the class, nor can it call a
member of a C++ class. All exported functions need to be static and extern
"C". If you need to instantiate the class, you'll have to export a function
that does it and returns a pointer to it, and you'd call it in C# and expect
an IntPtr in return ... then you'd follow by calling another exported
function that takes a pointer to the class. Like so:

extern "C" CommandLineParams * __stdcall __declspec(dllexport)
CreateCommandLineParams()
{
return new CommandLineParams();
}

extern "C" void __stdcall __declspec(dllexport)
getCommandLineParams(CommandLineParams *p, LPCWSTR cc, LPCWSTR name)
{
p->getCommandLineParams(wstring(cc), wstring(name));
}

C#:

[DllImport(whatever)]
extern static IntPtr CreateCommandLineParams();

[DllImport(whatever)]
extern void getCommandLineParams(IntPtr p, string cc, string name);


Robert
 
So now i have the following code.....

c++ .....

extern "C" void __stdcall __declspec(dllexport)
wrapperCommandLineParams(string cc, string name)
{
CommandLineParams *inst = new CommandLineParams();
inst->getCmdLineParams(string2wstring(cc),
string2wstring(name));
delete inst ;
}

c#
public class Native
{
[DllImport("Strider.dll", EntryPoint =
"wrapperCommandLineParams", SetLastError = true)]
public static extern void getCommandLineParams(string cc, string
Name);
}


and i call this function simply as
getCommandLineParams(combobox.items[0].toString(),txtbox.text);

However i still get the same exception.
This time i am not trying to call a class member's function but i call
it as an extern "C" function and i have used the __stdcall convention
..Am i still doing something wrong ?? Also , is there some function
through which i can get more info about this exception..
since earlier when i tried to call class's member function through
p/invoke ... i got the same exception( native exception 0xC0000005 )
and even now when i have made the corrections, i get the exact same
exception.....so what exactly does this exception mean ??

Thanks for all the useful info and suggestions

Somesh
 
The problem lies in your C++ implementation. What is a "string" in C++ in
your context? It appears that it's a char*, since you're trying to
"convert" it to a wide character string. If that's the case you'd want to
declare it as such. THat's still going to fail though becasue CE is
Uinicode already, so the managed string is already a wchar_t array. You
probably want something like this:

extern "C" void __stdcall __declspec(dllexport)
wrapperCommandLineParams(TCHAR *cc, TCHAR *name)
{
....
}

-Chris
 
Back
Top