Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsFree MagazinesWhite PapersSubmit Content
Discussion GroupsASP.NETWindows FormsLanguages.NET FrameworkVisual Studio.NET
Articles.NET FrameworkASP.NETToolsWindows Forms
.NET DirectoryOpen Source ProjectsUser GroupsWeb Resources
Related Topics
Visual Basic 6SQL ServerMS AccessOther DB ProductsMS Server ProductsMore Topics ...

.NET Forum / .NET Framework / Interop / June 2005

Tip: Looking for answers? Try searching our database.

passing string array to C++

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
Bruce Parker - 12 Jun 2005 02:11 GMT
I have an unmanaged api I need to call.  The definition for it is the
following:

DLL_API int Adapt( Global* g, char** strings, int numStrings);

I need to wrap this api in C++ and then pass a string array from c# to the
wrapper api.  Here is my attempt:

C++ wrapper
DLL_API long MyAdapt( long g, WCHAR **strings, long numStrings)
{
    char cbuf[2048];
               int x;
               //I believe this is wrong - what is the right way
    for (x=0; x<numStrings; x++)
        unicodeToAscii( cbuf, (WCHAR* )strings[x], sizeof(cbuf) );
   
    return( (long) ::Adapt( (Global* ) gr,(char**) cbuf, numStrings ))
}

c#
[DllImport("MyWrapper.dll", CharSet=CharSet.Auto)]
        private static extern int MyAdapt(int gr, string[]  MyStrings,int
numStrings);

When I execute MyAdapt I get an error telling me there is something wrong on
how I am passing my parameters.

I am using the .NET Compact framework for my c# application.

Question 1:  How do I pass a string array to unmanaged C++ (Embedded Visual
C++)?

Question 2:  What do the C++ parameters need to be?

Question 3:  I need to convert the string array with my unicodeToAscii
routine to make it a char**.  How do I do this, including I do not know the
size of the array until the size is passed to me through the numStrings
parameter.

My C++ is weak now, I haven't done it 8 years, so I am really rusty.
"Peter Huang" [MSFT] - 13 Jun 2005 08:56 GMT
Hi

The .NET P/Invoke Layer will help to pass the ansi version string to
unmanaged dll.
Here is a simple test. You may have a try and let me know the result.

[C++]
CPPDLL_API long MyAdapt( long g, char **strings, long numStrings)
{
    for(int i=0;i<numStrings;i++)
    {
        printf("%s \n",strings[i]);
        strings[i][2]='A'+i;//Change the string
    }
    return 0;
}

[C#]
[DllImport(@"..\..\..\CPPDLL\Debug\CPPDLL.dll",EntryPoint="MyAdapt",CharSet=
CharSet.Ansi,SetLastError=true)]
private static extern int MyAdapt(int g,[In,Out] string[] users, int
numUsers);

public static void InteropStringArray()
{
    string[] strs = new string[]{"Hello","World"};
    int rt = MyAdapt(2,strs,2);
    foreach(string s in strs)
    {
        Console.WriteLine(s);
    }
}
[STAThread]
static void Main(string[] args)
{
    InteropStringArray();
}

BTW:
I am not very familar with Embeded develop very much, the code above should
work but I tested only on .NET framework.
For compactframework or evc issue, you may try to post in the newsgroup
below.

microsoft.public.dotnet.framework.compactframework
microsoft.public.pocketpc.developer
microsoft.public.windowsce.embedded.vc
Best regards,

Peter Huang
Microsoft Online Partner Support

Signature

Get Secure! - www.microsoft.com/security
This posting is provided "AS IS" with no warranties, and confers no rights.

Bruce Parker - 14 Jun 2005 01:01 GMT
The .NET Compact framework does not support Charset.Ansi.  I need to be able
to do this with Charset.Auto which is the same as Charset.Unicode.  How would
you do this using the Charset.Unicode.  A WCHAR ** seems to be incorrect on
the C++ side.
 

> Hi
>
[quoted text clipped - 50 lines]
> Get Secure! - www.microsoft.com/security
> This posting is provided "AS IS" with no warranties, and confers no rights.
"Peter Huang" [MSFT] - 14 Jun 2005 07:12 GMT
Hi

Based on my research, all the System API on the WinCE is of Unicode
version, so it is common to handle all the string in the winCE of unicode
version.
I think it is better for you to convert your dll to handle Unicode version
string all the time.

Here is the WCHAR version P/Invoke for your  reference.

[C++]
CPPDLL_API long MyAdapt( long g, WCHAR **strings, long numStrings)
{
    for(int i=0;i<numStrings;i++)
    {
        printf("%S \n",strings[i]);
        strings[i][2]='A'+i;
    }
    return 0;
}
extern "C" CPPDLL_API long MyAdapt( long g, WCHAR **strings, long
numStrings);

[C#]
       
[DllImport(@"..\..\..\CPPDLL\Debug\CPPDLL.dll",EntryPoint="MyAdapt",CharSet=
CharSet.Unicode,SetLastError=true)]
        private static extern int MyAdapt(int g,[In,Out] string[] users, int
numUsers);
        public static void InteropStringArray()
        {
            string[] strs = new string[]{"Hello","World"};
            int rt = MyAdapt(2,strs,2);
            foreach(string s in strs)
            {
                Console.WriteLine(s);
            }
        }
        [STAThread]
        static void Main(string[] args)
        {
            InteropStringArray();
        }

Best regards,

Peter Huang
Microsoft Online Partner Support

Signature

Get Secure! - www.microsoft.com/security
This posting is provided "AS IS" with no warranties, and confers no rights.

Bruce Parker - 15 Jun 2005 00:47 GMT
I have tried myself the way you indicate below on how to pass the strings.  
Unfortunately it appears the .NET Compact framework marshalling does not
support this.  Can you verify this with the Microsoft team responsible for
this and what is their response?  I would think passing an array of strings
from the .NET Compact framework to Embedded Visual C++ would work, but it
doesn't.  The error message I get back from .NET is "Bad arguments or
incorrect declaration".  I really need this mystery solved.

> Hi
>
[quoted text clipped - 47 lines]
> Get Secure! - www.microsoft.com/security
> This posting is provided "AS IS" with no warranties, and confers no rights.
"Peter Huang" [MSFT] - 15 Jun 2005 09:20 GMT
Hi

So far I am contacting the related embeded support engineer.
I will update you with new information ASAP.

Best regards,

Peter Huang
Microsoft Online Partner Support

Signature

Get Secure! - www.microsoft.com/security
This posting is provided "AS IS" with no warranties, and confers no rights.

"Peter Huang" [MSFT] - 17 Jun 2005 03:12 GMT
Hi

Sorry for delay response, so far we are still investigating the issue, I
will update you ASAP.

Thanks for your understanding!

Best regards,

Peter Huang
Microsoft Online Partner Support

Signature

Get Secure! - www.microsoft.com/security
This posting is provided "AS IS" with no warranties, and confers no rights.

Yan-Hong Huang[MSFT] - 20 Jun 2005 03:41 GMT
Hello,

I am reviewing this issue thread. We need to submit it to compact framework
support team and discuss it with them. That may need some more days. The
support team may need some more information if necessary. Could you please
post a reply here to let us know you are still monitoring it? So we will go
ahead to process it.

Thanks very much.

Best regards,
Yanhong Huang
Microsoft Community Support

Get Secure! ¨C www.microsoft.com/security
Register to Access MSDN Managed Newsgroups!
-http://support.microsoft.com/default.aspx?scid=/servicedesks/msdn/nospam.as
p&SD=msdn

This posting is provided "AS IS" with no warranties, and confers no rights.
Bruce Parker - 21 Jun 2005 03:03 GMT
Yes, I am still monitoring this.  

> Hello,
>
[quoted text clipped - 16 lines]
>
> This posting is provided "AS IS" with no warranties, and confers no rights.
Yan-Hong Huang[MSFT] - 21 Jun 2005 08:24 GMT
Thanks very much for the quick update. I am contacting CE support team
today and we will reply here with more information as soon as possible.

Thanks again for your patience.

Best regards,
Yanhong Huang
Microsoft Community Support

Get Secure! ¨C www.microsoft.com/security
Register to Access MSDN Managed Newsgroups!
-http://support.microsoft.com/default.aspx?scid=/servicedesks/msdn/nospam.as
p&SD=msdn

This posting is provided "AS IS" with no warranties, and confers no rights.
"Peter Huang" [MSFT] - 21 Jun 2005 08:35 GMT
Hi

Thank you for your response, so far our related support team is looking
into the issue.
I will update you with new information ASAP.

Best regards,

Peter Huang
Microsoft Online Partner Support

Signature

Get Secure! - www.microsoft.com/security
This posting is provided "AS IS" with no warranties, and confers no rights.

Gary Lewis - 22 Jun 2005 00:23 GMT
Greetings!

Unfortunately, as you've already seen, the .NET Compact Framework (NETCF)
does not support passing a string array to unmanaged code. That said, I am
working on some sample code to workaround the issue but it will take me a
bit of time to complete. Look for a reply on Wednesday afternoon or
Thursday morning after I've tested the code.

Cheers!

Gary Lewis MCAD
Technical Lead
Microsoft Mobile & Embedded Devices Developer Support
Gary Lewis - 22 Jun 2005 21:34 GMT
OK, this may seem a bit convoluted, but here is the solution:

The normal code signature to be called would look like this:

   private static extern int MyAdapt( int gbl, string[] strings, int count
);
   
   where strings is an array of strings and count is the number of
strings. gbl is irrelevant in this context.

This signature cannot be used directly because NETCF 1.0 does not support
it. The solution is to write C# code to convert the string array into a
single delimited string (using a StringBuilder) and have C++ code convert
it back into the desired form. Here is the C# code:

       //  I assume you have code to fill this
       private string[] m_strings;

       //    Signature of the C++ wrapper function
       [DllImport("Unmanaged.DLL")]
       private static extern int MyAdapt( int gbl, StringBuilder
stringList, int count );

       //  Compute size of StringBuilder (or guess :-)
       int size = 1;   //  Allows for terminator

       foreach ( string sz in m_strings )
           size += sz.Length + 1;

       //  Fill a StringBuilder
       StringBuilder sb = new StringBuilder( size );

       foreach ( string sz in m_strings )
       {
           sb.Append( sz );
           sb.Append( '\0' );
       }

       sb.Append( '\0' );

       //  Call the unmanaged code
       int rc = MyAdapt( 42, sb, m_strings.Length );

Next, we create a C++ wrapper function that converts the string back into
an array of strings. Note that this implementation converts the Unicode
strings from NETCF to ANSI strings. The code can be simplified a good deal
if this is not required. Just allocate pStrs as a WCHAR** and fill in the
pointers directly by computing the proper offsets into stringList. No
additional memory allocations are required in this case.  If your C++ code
can work with Unicode this I recommend NOT converting them to ANSI.

Here is C++ code that includes conversion:

UNMANAGED_API int MyAdapt( int gbl, LPCWSTR stringList, int count  )
{
       int     ix, iy, iz;              //  Indexes
       int     retCode = 0;    //  Return code to caller

       //  Allocate array of string pointers
       char**  pStrs =   new char * [ count ];

       //  Scan the embedded strings
       for ( ix = iz = 0; stringList[ ix ] != 0; ix++ )
       {
           //  Compute start and length of current Unicode string
           LPCWSTR  pszBegin =  &stringList[ ix ];

           //  Look for end of string
           for ( iy = 0; stringList[ ix + iy ] != 0; iy++ )
               ;

           //  Allocate ANSI string area allowing for string termination
           pStrs[ iz ] =   new char[ iy + 1 ];

           //  Translate the string
           int ret = WideCharToMultiByte( CP_ACP, 0, pszBegin, iy + 1,
pStrs[ iz ], iy + 1, NULL, NULL );

           //  Set up for next string
           iz      += 1;       //  Next output string
           ix      += iy;        //  Next input string
       }

       //  Now call the internal function (the function we are wrapping)

//      retcode = InternalMyAdapt( gbl, pStrs, count );

       //  Must free strings we allocated - skip this if the internal
function
       //  is responsible for the string array.
       for ( ix = 0; ix < count; ix++ )
           delete [] pStrs[ ix ];

       //  Delete the array itself (see above)
       delete pStrs;

       //  Return result
       return retCode;
}

Disclaimer for all above code:

// THIS CODE AND INFORMATION IS PROVIDED "AS-IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
Bruce Parker - 23 Jun 2005 18:49 GMT
Thanks for the help.  

Does this apply to all marshalling of passing arrays of pointers?  I have
other challenges in this area such as passing an array of pointers to class
instances.  I am at the point where I am going to let Embedded C++ managed
these arrays and provide C++ methods for the C# to work with them.  

In addition, will we see any improvements in this area with NETCF 2.0?  

> OK, this may seem a bit convoluted, but here is the solution:
>
[quoted text clipped - 102 lines]
> // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
> // PARTICULAR PURPOSE.
Gary Lewis - 27 Jun 2005 19:44 GMT
You wrote "Does this apply to all marshalling of passing arrays of
pointers? "

Arrays of references to objects are problematic for NETCF 1.0 since we don't
have the MarshalAs attribute to tell the CLR how to marshal the data that
the
data is referencing.

I suspect that the most straightforward implementation is the one I used -
let C
(not C++) manage the array and expose only array elements to Managed code
via C-language wrapper functions. If you use C++ you will need to deal with
keeping
a copy of the "this" pointer around in your C# code during the life of your
C++ class
and handle (or alias) mangled names. Writing a set of C-language collection
management functions should be fairly simple.

Gary
Gary Lewis - 29 Jun 2005 18:44 GMT
To follow up in your other question: yes, NETCF 2.0 P/Invoke has MarshalAs
and is much closer to the desktop in functionality.

Rate this thread:







Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.