<body><script type="text/javascript"> function setAttributeOnload(object, attribute, val) { if(window.addEventListener) { window.addEventListener('load', function(){ object[attribute] = val; }, false); } else { window.attachEvent('onload', function(){ object[attribute] = val; }); } } </script> <div id="navbar-iframe-container"></div> <script type="text/javascript" src="https://apis.google.com/js/plusone.js"></script> <script type="text/javascript"> gapi.load("gapi.iframes:gapi.iframes.style.bubble", function() { if (gapi.iframes && gapi.iframes.getContext) { gapi.iframes.getContext().openChild({ url: 'https://www.blogger.com/navbar.g?targetBlogID\x3d6566853\x26blogName\x3d1%25+inspiration\x26publishMode\x3dPUBLISH_MODE_BLOGSPOT\x26navbarType\x3dBLUE\x26layoutType\x3dCLASSIC\x26searchRoot\x3dhttp://patke.blogspot.com/search\x26blogLocale\x3den\x26v\x3d2\x26homepageUrl\x3dhttp://patke.blogspot.com/\x26vt\x3d8220196945898414734', where: document.getElementById("navbar-iframe-container"), id: "navbar-iframe" }); } }); </script>
Archives
Subscribe


Wednesday, July 28, 2004

The other day I wrote a quick posts about passing a string array from C++ to a C# program on Pocket PC.  So today I thought I would go over a bit of code showing the opposite.  How to get a string[] into C++ from managed C#.

Sounds complicated, but the process is actually quite simple.  First create a struct in C++ which contains a wide character pointer.  Then create the struct in C# - the trick here is to use unmanaged code in C# to create the char pointer.  From there, the rest is easy.  Just pass an array of the struct type into the C++ program.

Something like this:

//c++
typedef struct _STR
{
   WCHAR* command;
} STR;

//C#
public unsafe struct CMD
{
   public char* command;
   public CMD(char* cmd)
   {
      command = cmd;
   }
}

Looks good you say, but doesn't quite work because C# doesn't support character pointers.  ...but notice the "unsafe" key word - that is where the magic is.

So to generate our array of pointers, we have code like...


internal class PInvokeStringArray
{
   private string[] ary = {" ", " ", " ", " ", " "}; //length = 5 - initialized with default values.
   public int Length = 0;
  
   public string[] getArray()
   {
      return ary;
   }
   
   public PInvokeStringArray(string[] array)
   {
      if(array==null) return; //use the defaults.
      Length = array.Length;
      if(Length > 5)
         throw new ArgumentException("Unable to perform the operation " + 
            "requested because too many directory commands were specified. " +
            "This program can only accept a maximum of 5 directory commands.");
      for(int i=0;i Length;i++)    
      {
         ary[i] = array[i] + "\0";
      }
   }
}


PInvokeStringArray psa = new PInvokeStringArray(cmdsStr);
cmdsStr = psa.getArray();
CMD[] cmds = new CMD[5];
unsafe
{
   fixed(char* temp1 = cmdsStr[0].ToCharArray(), 
      temp2 = cmdsStr[1].ToCharArray(), 
      temp3 = cmdsStr[2].ToCharArray(), 
      temp4 = cmdsStr[3].ToCharArray(),
      temp5 = cmdsStr[4].ToCharArray())
   {
   cmds[0] = new CMD(temp1);
   cmds[1] = new CMD(temp2);
   cmds[2] = new CMD(temp3);
   cmds[3] = new CMD(temp4);
   cmds[4] = new CMD(temp5);
   myPInvokeFunction(cmds);
   }
}

Anyone looking at this code for more then two seconds can see the obvious downside.  The array passed into C++ must be of a limited size.  Because of the nature of the "fixed" command, I couldn't see a way around this, but would really appreciate any suggestions.  ...but at any rate, it works for me.

Permalink
Comments: Post a Comment