none
Interop Marshalling Array of C Strings element[0] = NULL RRS feed

  • Question

  • I have a COM dll function I'd like to call that takes an array of pre-allocated C strings as a parameter. The function writes the strings, and returns to the caller. The signature is:

    void AT91Boot_Scan(char *pDevList);

    I am using the same dll, and identical code as in the related topic, "How to marshal a 'C' array of strings in c# (COM interop)". However, while I expect to get back an array of strings from the function dll.AT91Boot_Scan(table), unfortunately, the first element, table[0] is a NULL reference. 

    I can get it to work if I pass a pointer to an array of C strings which I allocate with Marshal.AllocHGlobal(); the first element of the returned array points to a valid string. However, this uses "unsafe" code, which i'd like to avoid. So, I know something is going awry with the marshalling, somehow. Here is the code:

    private void scanButton_Click(object sender, EventArgs e)
    {
       string[] table = new string[10];
    
       for (int i = 0; i < table.Length; i++)
       {
          table[i] = new string(new char[255]);
       }
    
       dll.AT91Boot_Scan(table);
    
       foreach (string s in table)
       {
          // addition throws an exception, because first string
          // is NULL.
          listBox1.Items.Add(s);
        }
    }
    


    I had to modify the .il code to change the default marshalling, and actually had to do it in two places, as the method appears twice, once with the "abstract" keyword in front of it (don't know if this is related):

    .method public hidebysig newslot virtual 
              instance void  AT91Boot_Scan([in][out] string[] marshal(lpstr[]) pDevList) runtime managed internalcall
    
    
    .method public hidebysig newslot abstract virtual
              instance void  AT91Boot_Scan([in][out] string[] marshal(lpstr[]) pDevList) runtime managed internalcall
    I am very thankful for any assistance on this problem!

    Sincerely,
    Karl Kessler

    Monday, February 8, 2010 3:52 PM

Answers

  • Karl Kessler ,

    It's odd, and somewhat ironic because I am working with the exact same DLL, and the Exact same function right now. The exception that I'm hitting overlaps your situation. I was wondering if you wouldn't mind posting your code for:

    "I can get it to work if I pass a pointer to an array of C strings which I allocate with Marshal.AllocHGlobal()"

    The reason why I asked this is twofold:
    1) I implemented it initially in C# (with the below), but upon hardware being removed or added, I obtained an exception of RPC_E_...
    2) I further implemented it in C++ and received the same issue.
    instance void  AT91Boot_Scan([in][out] string[] marshal(lpstr[]) pDevList) runtime managed internalcall



    From my understanding when a null is returned the parsing of the list is not to continue. IE there is no hardware afterwords. The odd part is there are at minimum two more fields on my system that are populated. In the event that is true -- no more should be listed you can easily do the following to stop the procedure:

     
    private void scanButton_Click(object sender, EventArgs e)
    {
       string[] table = new string[10];
    
       for (int i = 0; i < table.Length; i++)
       {
          table[i] = new string(new char[255]);
       }
    
       dll.AT91Boot_Scan(table);
    
       foreach (string s in table)
       {
          if (s == null || s == String.Empty)
          {
              break;
          }
          listBox1.Items.Add(s);
        }
    }
    
    I understand this isn't really what you're after but from my understanding this is true.


    I forgot to mention: If your exception is occurring within the COM dll, then the exception isn't because the string is null. It's something else, and that is where I am stuck. It also means that it's not the addition that is throwing the exception it's the DLL.
    • Marked as answer by SamAgain Monday, February 22, 2010 8:59 AM
    Monday, February 8, 2010 8:51 PM
  • I know - double post. Please forgive me I prefer to isolate my answers:

    Basically I had an issue with the DLL crashing about the same area as you are. I'm not sure exactly how you're implementing your code (as in who is executing the scanButton.Click()) but you could be encountering the same problem as I did in another way. Be sure not to execute the AT91Boot_Scan from another thread. IE. call it once from one thread and then call it again from another.

    I started invoking the function from the main thread and it seems to be behaving as it should.

    Neither method requires "Unsafe".


    • Marked as answer by SamAgain Monday, February 22, 2010 8:59 AM
    Monday, February 8, 2010 10:42 PM

All replies

  • Karl Kessler ,

    It's odd, and somewhat ironic because I am working with the exact same DLL, and the Exact same function right now. The exception that I'm hitting overlaps your situation. I was wondering if you wouldn't mind posting your code for:

    "I can get it to work if I pass a pointer to an array of C strings which I allocate with Marshal.AllocHGlobal()"

    The reason why I asked this is twofold:
    1) I implemented it initially in C# (with the below), but upon hardware being removed or added, I obtained an exception of RPC_E_...
    2) I further implemented it in C++ and received the same issue.
    instance void  AT91Boot_Scan([in][out] string[] marshal(lpstr[]) pDevList) runtime managed internalcall



    From my understanding when a null is returned the parsing of the list is not to continue. IE there is no hardware afterwords. The odd part is there are at minimum two more fields on my system that are populated. In the event that is true -- no more should be listed you can easily do the following to stop the procedure:

     
    private void scanButton_Click(object sender, EventArgs e)
    {
       string[] table = new string[10];
    
       for (int i = 0; i < table.Length; i++)
       {
          table[i] = new string(new char[255]);
       }
    
       dll.AT91Boot_Scan(table);
    
       foreach (string s in table)
       {
          if (s == null || s == String.Empty)
          {
              break;
          }
          listBox1.Items.Add(s);
        }
    }
    
    I understand this isn't really what you're after but from my understanding this is true.


    I forgot to mention: If your exception is occurring within the COM dll, then the exception isn't because the string is null. It's something else, and that is where I am stuck. It also means that it's not the addition that is throwing the exception it's the DLL.
    • Marked as answer by SamAgain Monday, February 22, 2010 8:59 AM
    Monday, February 8, 2010 8:51 PM
  • I know - double post. Please forgive me I prefer to isolate my answers:

    Basically I had an issue with the DLL crashing about the same area as you are. I'm not sure exactly how you're implementing your code (as in who is executing the scanButton.Click()) but you could be encountering the same problem as I did in another way. Be sure not to execute the AT91Boot_Scan from another thread. IE. call it once from one thread and then call it again from another.

    I started invoking the function from the main thread and it seems to be behaving as it should.

    Neither method requires "Unsafe".


    • Marked as answer by SamAgain Monday, February 22, 2010 8:59 AM
    Monday, February 8, 2010 10:42 PM
  • Hi, Karl:
        How is your problem going on? Could you share your progress?
    Please mark the right answer at right time.
    Thanks,
    Sam
    Wednesday, February 17, 2010 8:54 AM