Consuming a string from an unmanaged C++ DLL

L

Lcubed

Does anyone know of any good ways at all to pass strings from a C++
DLL to a C# app using .NET CF??

I've tried several things, One of my attempts was this:

// EXTREMELY simplified C++ function in DLL
LPWSTR CInterfaceLayerApp::SendAStringToCSharp()
{
return (LPWSTR) "String for C#";
}

// C# app - again simplified
[DllImport("InterfaceLayer.dll")]
[return: MarshalAs(UnmanagedType.LPWStr)]
static extern String SendAStringToCSharp();

// as called from C# function
String GetTheString = SendAStringToCSharp(); // function returns null
// if the DLL sends a char * then I receive the first char only

I need to have several functions that return strings so was hoping for
a safe, efficient way to do this.

Is there a best way (fastest, most efficient, least likely to cause
memory leakage) to pass strings from the unmanaged C++ DLL to the C#
application?
The strings can be in any format on the C++ side (char *, LPWSTR, even
ATL CString, etc), but I will need them to be Strings in the C# app.
I'm working with .NETCF 2.0.

I see a lot of PInvoke information but very little seems to be
available on how to handle return strings from unmanaged DLLs.

Any input or ideas sincerely and very much appreciated.
 
C

Chris Tacke, eMVP

You cannot simply do this cast in Windows CE:

return (LPWSTR) "String for C#";

That will *not* make a ANSI string into Unicode, it only gets rid of the
compiler error you were getting when you tried to just return it as ANSI. It
explains exactly why you get the result you do.

This is worth a read:
http://blog.opennetcf.com/ctacke/2006/12/19/ReturningStringsFromCFunctions.aspx


--

Chris Tacke, Embedded MVP
OpenNETCF Consulting
Giving back to the embedded community
http://community.OpenNETCF.com
 
L

Lcubed

Thanks for the pointing me in the right direction.

Please note : The cast isn't actually in the C++ code - I just wanted
a quick bit of code to show a function returning a LPWSTR.

So now I have a different problem - I've read unmanaged code should
never change data passed to it by managed code - especially strings.
But if I use references and pointers and the unmanaged code allocates
the string (or array), how would I then de-allocate it on the managed
side?

I have a large mass of data that the C++ DLL processes with only a
small bit of that needs to appear in the C# GUI.
Should I use byte arrays instead of strings? If so, how would I define
them in the C# calling code?
 
C

Chris Tacke, eMVP

Please note : The cast isn't actually in the C++ code - I just wanted
a quick bit of code to show a function returning a LPWSTR.

The point is that your sample was not returning a Unicode string though - so
your test would have been invalid.
So now I have a different problem - I've read unmanaged code should
never change data passed to it by managed code - especially strings.

Read where? It depends on what you're doing, but that's certainly not a
blanket truth.
But if I use references and pointers and the unmanaged code allocates
the string (or array), how would I then de-allocate it on the managed
side?

The unmanaged code should not be allocating (hence the point of the blog
entry I sent you).
I have a large mass of data that the C++ DLL processes with only a
small bit of that needs to appear in the C# GUI.

Processes how? Tell us what your actual scenario is instead of generalities
and we can give you targeted advice.
Should I use byte arrays instead of strings? If so, how would I define
them in the C# calling code?

Bytes and strings are all the same. Fundamentally they're all stored as
bytes and the machince doesn't care. The data type is strictly for
programmer convenience. You can use either one effectively.


--

Chris Tacke, Embedded MVP
OpenNETCF Consulting
Giving back to the embedded community
http://community.OpenNETCF.com
 
L

Lcubed

Processes how? Tell us what your actual scenario is instead of generalities
and we can give you targeted advice.

I have a C++ program that I use to communicate via WiFi with another
device. The devices exchange a lot of data which the C++ program (now
a DLL) uses to create various reports for the user. The C++ DLL works
as needed. From within a C++ project, the DLL works well. However,
calling the DLL from the C# program (also the GUI) is also fine and
returning int/float/whatever data is great, until I need to pass
strings back from the C++ DLL. Fortunately, I have control over both
sides so I can change the C++ DLL any way I need to make life easy for
the C# program.

Actually I just found your article :
http://blog.opennetcf.com/ctacke/2005/02/22/MarshalingStructsWithStringPointers.aspx
Thanks for all your articles BTW, they are very helpful.

As much as I was hoping that there would be a short, simple, elegant
way for the apps to share the string data, I think it's going to end
up with something similar to the 80-liner you discuss in your
article. Unless, I'm overlooking something?
 
C

Chris Tacke, eMVP

Depends. If you're targeting CF 2.0 or later, it probably not necessary to
hand-marshal the data, but again, without a concrete example of an actual
call signature you're trying to implement, it's really tough to say.


--

Chris Tacke, Embedded MVP
OpenNETCF Consulting
Giving back to the embedded community
http://community.OpenNETCF.com
 
P

Paul G. Tobey [eMVP]

"Sharing string data" as a general thing is no big deal. You can pass a
static string from managed code to native code and the native code can use
it. It shouldn't change it, though. If the native code DLL needs to
allocate memory, the contract for the call that does that needs to be clear
about how managed code should free the memory. Often, it's just calling,
via P/Invoke, LocalFree(), but it needs to be clear. If you want to have
the native code return something directly that is a managed code string, you
need to do something like wrap the actual native call with your own managed
code one that, in turn, P/Invokes the native code, gets the string, copies
the contents to a managed string, and then frees the native string. Roughly
something like this:

-----

unsafe public string ManagedWrapperForNativeCall( int parameter, int
parameter2 )
{
// Make the native call and get the pointer to the native string
(Unicode), back.
Char *s = NativeCall( parameter, parameter2 );

// Now allocate and populate a managed code string for return to the
caller.
string ret = new string( s );

// Free the native string.
LocalFree( (IntPtr)s );

return ret;
}

[DllImport( "mydll.dll" )]
unsafe private static extern Char *NativeCall( int parameter, int
parameter2 );

[DllImport( "coredll.dll" )]
private static extern IntPtr LocalFree( IntPtr localh );

-----

It should be clear that the native code can't allocate a managed object of
*any* type, so you have to do this kind of wrapping in any case that you
want to have a clean, managed type of interface.

Paul T.
 
L

Lcubed

Depends. If you're targeting CF 2.0 or later, it probably not necessary to
hand-marshal the data, but again, without a concrete example of an actual
call signature you're trying to implement, it's really tough to say.

Well.... here's some typical functions (simplified so you don't have
to read all day). I haven't done anything to them to make them nice
for C#, but I can.

struct CUnitsInRange
{
CString cName;
ULONG uUnitID;
UCHAR ucStatus;
ULONG ulVerifyChk;
} ;

CUnitsInRange UnitList;

CUnitsInRange* FindCompatibleUnits()
{
// Clear Device Data structure & Device listing
// Validate devices
// Populate device list

return &UnitList;
// the C# GUI side only needs to see the units - not the other
stuff in struct
// so no reason to port it all over
}

bool GetTime(CString TimeStr)
{
CString str;
CTime rTime = CTime::GetCurrentTime();
str.Format(_T("%2d/%d/%4d %2d:%.2d:%.2d"), rTime.GetMonth(),
rTime.GetDay(),
rTime.GetYear(), rTime.GetHour(), rTime.GetMinute(),
rTime.GetSecond());

if(str.GetLength() > TimeStr.GetLength())
return false;

TimeStr = str;
return true;
}

// this one I moved over to c# but I'll have to put in place C++
functions with
// similar data (CStringArray) that I will have to pass into CSharp,
so would
// like to know how to do this without hand marshaling.
bool ListFiles(LPCTSTR pszPath, LPCTSTR pszFilter, CStringArray
&sFilesFound)
{
WIN32_FIND_DATA fData;
HANDLE hFile;
BOOL bFound;
CString sSearch(pszPath), sFile;

sSearch += pszFilter;

hFile = FindFirstFile(sSearch, &fData);
bFound = (hFile != INVALID_HANDLE_VALUE);

while(bFound)
{
sFile = fData.cFileName;
sFilesFound.Add(sFile);
bFound = FindNextFile(hFile, &fData);
}

return (sFilesFound.GetCount()>0);
}
 
L

Lcubed

Paul, Thanks for the great example!
I was hoping to make the unmanaged DLL friendly for the C# caller, but
perhaps a wrapper would be good on both sides.
 
P

Paul G. Tobey [eMVP]

Maybe. I see that you are using MFC or at least CString classes. That's
not a good choice for interoperability because such things frequently
include pointers to the actual string, etc. When passing around structures,
you really want the data to be *in* the structure, not pointed to be a
hidden pointer embedded in a class that is itself in the structure.

Paul T.
 
C

Chris Tacke, eMVP

Sure - you're returning CString classes - not _wchar_t pointers - there's a
*huge* difference. You can't marshal a native class across the P/Invoke
boundary.

--

Chris Tacke, Embedded MVP
OpenNETCF Consulting
Giving back to the embedded community
http://community.OpenNETCF.com
 
L

Lcubed

Maybe. I see that you are using MFC or at least CString classes. That's
not a good choice for interoperability because such things frequently
include pointers to the actual string, etc. When passing around structures,
you really want the data to be *in* the structure, not pointed to be a
hidden pointer embedded in a class that is itself in the structure.

Yeah, I was debating whether to do some rewrite and remove the MFC
references or just exclude them from DLL exposed functions.
 
S

super_beda

Hi ,
I'm using an unmanaged DLL that I can not modify, and I built a Wrapper in
C# to call its functions from .NET framework (not CF), using DllImport and
MarhalAs.
My problem is that one vital-importance function of this DLL takes as
arguments CString classes pointers. GHow can I manage them from C Sharp?
Here is the unmanaged function declaration code:

extern "C" Dll_Lib int DSP_UpdateTriggerSlot(unsigned int dsphandle,CString
ListURL,CString OrderListURL);

What can I do from C sharp?

[DllImport("MSS_SDK.dll",EntryPoint= "DSP_UpdateTriggerSlot")]
public static extern int _DSP_UpdateTriggerSlot(UInt32 dsphandle, ?????
ListURL,???? OrderListURL)

Thanks in advance
 
C

Chris Tacke, eMVP

The simple answer is "you don't.' You cannot marshal a managed class into a
native one in the CF (if you were a masochist maybe you coul dmanually
create the vtable and everything in a byte array, but I certainly wouldn't
recommend it.) In a case like this I recommend creating your own shim DLL
that has nothing but a nice, neat C API exposed that your managed app can
call, and have it do any ugliness requires to build classes for marshaling.


--

Chris Tacke, Embedded MVP
OpenNETCF Consulting
Giving back to the embedded community
http://community.OpenNETCF.com

super_beda said:
Hi ,
I'm using an unmanaged DLL that I can not modify, and I built a Wrapper in
C# to call its functions from .NET framework (not CF), using DllImport and
MarhalAs.
My problem is that one vital-importance function of this DLL takes as
arguments CString classes pointers. GHow can I manage them from C Sharp?
Here is the unmanaged function declaration code:

extern "C" Dll_Lib int DSP_UpdateTriggerSlot(unsigned int
dsphandle,CString
ListURL,CString OrderListURL);

What can I do from C sharp?

[DllImport("MSS_SDK.dll",EntryPoint= "DSP_UpdateTriggerSlot")]
public static extern int _DSP_UpdateTriggerSlot(UInt32 dsphandle, ?????
ListURL,???? OrderListURL)

Thanks in advance

Paul G. Tobey said:
Maybe. I see that you are using MFC or at least CString classes. That's
not a good choice for interoperability because such things frequently
include pointers to the actual string, etc. When passing around
structures,
you really want the data to be *in* the structure, not pointed to be a
hidden pointer embedded in a class that is itself in the structure.

Paul T.
 
S

super_beda

So I have to write something in C/C++ that deals with CString an calls the
API, and exposes for example normal char array to managed code? Could you
please provide a code snippet?
(Oh,I'm using full .NET 2.0(not CF))

Thank you again



Chris Tacke said:
The simple answer is "you don't.' You cannot marshal a managed class into a
native one in the CF (if you were a masochist maybe you coul dmanually
create the vtable and everything in a byte array, but I certainly wouldn't
recommend it.) In a case like this I recommend creating your own shim DLL
that has nothing but a nice, neat C API exposed that your managed app can
call, and have it do any ugliness requires to build classes for marshaling.


--

Chris Tacke, Embedded MVP
OpenNETCF Consulting
Giving back to the embedded community
http://community.OpenNETCF.com

super_beda said:
Hi ,
I'm using an unmanaged DLL that I can not modify, and I built a Wrapper in
C# to call its functions from .NET framework (not CF), using DllImport and
MarhalAs.
My problem is that one vital-importance function of this DLL takes as
arguments CString classes pointers. GHow can I manage them from C Sharp?
Here is the unmanaged function declaration code:

extern "C" Dll_Lib int DSP_UpdateTriggerSlot(unsigned int
dsphandle,CString
ListURL,CString OrderListURL);

What can I do from C sharp?

[DllImport("MSS_SDK.dll",EntryPoint= "DSP_UpdateTriggerSlot")]
public static extern int _DSP_UpdateTriggerSlot(UInt32 dsphandle, ?????
ListURL,???? OrderListURL)

Thanks in advance
 
C

Chris Tacke, eMVP

Something along these lines:

int UpdateTriggerSlot(unsigned int dsphandle, TCHAR *ListURL, TCHAR
*OrderListURL)
{
CString lu(ListUrl);
CString olu(OrderedListURL);

return DSP_UpdateTriggerSlot(lu, olu);
}


--

Chris Tacke, Embedded MVP
OpenNETCF Consulting
Giving back to the embedded community
http://community.OpenNETCF.com


super_beda said:
So I have to write something in C/C++ that deals with CString an calls the
API, and exposes for example normal char array to managed code? Could you
please provide a code snippet?
(Oh,I'm using full .NET 2.0(not CF))

Thank you again



Chris Tacke said:
The simple answer is "you don't.' You cannot marshal a managed class into
a
native one in the CF (if you were a masochist maybe you coul dmanually
create the vtable and everything in a byte array, but I certainly
wouldn't
recommend it.) In a case like this I recommend creating your own shim
DLL
that has nothing but a nice, neat C API exposed that your managed app can
call, and have it do any ugliness requires to build classes for
marshaling.


--

Chris Tacke, Embedded MVP
OpenNETCF Consulting
Giving back to the embedded community
http://community.OpenNETCF.com

super_beda said:
Hi ,
I'm using an unmanaged DLL that I can not modify, and I built a Wrapper
in
C# to call its functions from .NET framework (not CF), using DllImport
and
MarhalAs.
My problem is that one vital-importance function of this DLL takes as
arguments CString classes pointers. GHow can I manage them from C
Sharp?
Here is the unmanaged function declaration code:

extern "C" Dll_Lib int DSP_UpdateTriggerSlot(unsigned int
dsphandle,CString
ListURL,CString OrderListURL);

What can I do from C sharp?

[DllImport("MSS_SDK.dll",EntryPoint= "DSP_UpdateTriggerSlot")]
public static extern int _DSP_UpdateTriggerSlot(UInt32 dsphandle, ?????
ListURL,???? OrderListURL)

Thanks in advance
 
P

Paul G. Tobey [eMVP]

How did you end up posting to a .NET CF group?

Paul T.

super_beda said:
So I have to write something in C/C++ that deals with CString an calls the
API, and exposes for example normal char array to managed code? Could you
please provide a code snippet?
(Oh,I'm using full .NET 2.0(not CF))

Thank you again



Chris Tacke said:
The simple answer is "you don't.' You cannot marshal a managed class into
a
native one in the CF (if you were a masochist maybe you coul dmanually
create the vtable and everything in a byte array, but I certainly
wouldn't
recommend it.) In a case like this I recommend creating your own shim
DLL
that has nothing but a nice, neat C API exposed that your managed app can
call, and have it do any ugliness requires to build classes for
marshaling.


--

Chris Tacke, Embedded MVP
OpenNETCF Consulting
Giving back to the embedded community
http://community.OpenNETCF.com

super_beda said:
Hi ,
I'm using an unmanaged DLL that I can not modify, and I built a Wrapper
in
C# to call its functions from .NET framework (not CF), using DllImport
and
MarhalAs.
My problem is that one vital-importance function of this DLL takes as
arguments CString classes pointers. GHow can I manage them from C
Sharp?
Here is the unmanaged function declaration code:

extern "C" Dll_Lib int DSP_UpdateTriggerSlot(unsigned int
dsphandle,CString
ListURL,CString OrderListURL);

What can I do from C sharp?

[DllImport("MSS_SDK.dll",EntryPoint= "DSP_UpdateTriggerSlot")]
public static extern int _DSP_UpdateTriggerSlot(UInt32 dsphandle, ?????
ListURL,???? OrderListURL)

Thanks in advance
 

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