none
Marshaling Char* when wrapping a custom COM Interface. How to get all characters RRS feed

  • Question

  • Hi!

    I'm not sure if this is the right place, but it is related to DirectShow, so I'll give it a try.

    I'm trying to create a .net wrapper for a custom COM Interface.

    The Interface is defined like this in C++:

    DECLARE_INTERFACE_(IDumpAsf, IUnknown) 
    { 
        STDMETHOD
    (get_UserParams) (THIS_ 
                   
    int *is_auto_start, 
                   
    int *fileSize,          
                   
    int *packetSize, 
                   
    char *baseName,  
                   
    char *filePath 
                 
    ) PURE; 
     
        STDMETHOD
    (set_UserParams) (THIS_ 
                   
    int is_auto_start, 
                   
    int fileSize,           
                   
    int packetSize, 
                   
    char *baseName,  
                   
    char *filePath 
                 
    ) PURE; 
     
        STDMETHOD
    (enable_Run) (THIS_ 
                   
    bool is_run 
                 
    ) PURE; 
    }; 

     

    And I have declared the interface like this in C#:

    public interface IDumpASF 
    { 
     
       
    [PreserveSig] 
       
    int get_UserParams( 
           
    [Out] out int is_auto_start, 
           
    [Out] out int fileSize, 
           
    [Out] out int packetSize, 
           
    [Out] out System.Sbyte baseName, 
           
    [Out] out System.SByte filePath 
           
    ); 
     
       
    [PreserveSig] 
       
    int set_UserParams( 
           
    [In] int is_auto_start, 
           
    [In] int fileSize, 
           
    [In] int packetSize, 
           
    [In] string baseName, 
           
    [In] string filePath 
           
    ); 
     
       
    [PreserveSig] 
       
    int enable_Run([In] bool a); 
     
    } 

     

    And her you got an example of use:

    int is_auto_start; 
    int fileSize; 
    int packetSize; 
    SByte baseName; 
    SByte filePath; 
     
    IDumpASF dump = (IDumpASF)asfWriter; 
     
    dump.get_UserParams(out is_auto_start, out fileSize, out packetSize, out baseName, out filePath); 

     

    I'm able to build and run the soulution, but I don't get how I'm suppose to get the all the characters for the baseName and filePath. When I send the SByte, it get the first character back, but how do I get the rest? I have tried several other types like Sbyte[], String, StringBuilder and IntPtr. Whenever I try to convert them into a string, I get an AccessViolationException.

    I bet there is some silly thing I have missed, but my patients is wearing thin here.

    Any help would be much appriciated!

    -Svein

    • Moved by Sheldon _Xiao Thursday, February 10, 2011 3:58 AM (From:Windows Presentation Foundation (WPF))
    Tuesday, February 8, 2011 1:13 PM

Answers

  • probably your are trying to access protected memory segment or unmanged code is in progress which cause the AccessViolationException to be thrown, so from my experience regarding such error you can try the following...

    1- pre allocate your designated memory for your code.

    2- try to allow unsafe code via visual studio project properties. 

    • Proposed as answer by Svein B Thursday, February 10, 2011 10:25 AM
    • Marked as answer by Svein B2 Thursday, February 10, 2011 1:09 PM
    Tuesday, February 8, 2011 2:08 PM
  • Hi Adham

    As you said, I needed to pre allocate some memory for my objects. I also had to make sure the data was marshaled in the correct way by adding the MarshalAs attribute.

    In this example, I have used a StringBuilder, and MarshalAs(UnmanagedType.LPStr). I have also tested with and array of SByte, and then you have to use MarshalAs(UnmanagedType.LPArray).

    This is what the test class looks like:

    System.Text.StringBuilder baseName = new System.Text.StringBuilder(256); 
    System.Text.StringBuilder filePath = new System.Text.StringBuilder(256); 
     
    EncirisWrapper.IDumpASF dump = (EncirisWrapper.IDumpASF)asfWriter; 
     
    dump.get_UserParams(out is_auto_start, out fileSize, out packetSize, baseName, filePath); 

    And this is how the wrapper looks:

    [PreserveSig] 
    int get_UserParams( 
       
    [Out] out int is_auto_start, 
       
    [Out] out int fileSize, 
       
    [Out] out int packetSize, 
       
    [MarshalAs(UnmanagedType.LPStr)] System.Text.StringBuilder baseName, 
       
    [MarshalAs(UnmanagedType.LPStr)] System.Text.StringBuilder filePath     
       
    ); 

    -Svein

    • Proposed as answer by Svein B Thursday, February 10, 2011 10:25 AM
    • Marked as answer by Svein B2 Thursday, February 10, 2011 1:09 PM
    Thursday, February 10, 2011 10:24 AM

All replies

  • probably your are trying to access protected memory segment or unmanged code is in progress which cause the AccessViolationException to be thrown, so from my experience regarding such error you can try the following...

    1- pre allocate your designated memory for your code.

    2- try to allow unsafe code via visual studio project properties. 

    • Proposed as answer by Svein B Thursday, February 10, 2011 10:25 AM
    • Marked as answer by Svein B2 Thursday, February 10, 2011 1:09 PM
    Tuesday, February 8, 2011 2:08 PM
  • Hi Adham

    As you said, I needed to pre allocate some memory for my objects. I also had to make sure the data was marshaled in the correct way by adding the MarshalAs attribute.

    In this example, I have used a StringBuilder, and MarshalAs(UnmanagedType.LPStr). I have also tested with and array of SByte, and then you have to use MarshalAs(UnmanagedType.LPArray).

    This is what the test class looks like:

    System.Text.StringBuilder baseName = new System.Text.StringBuilder(256); 
    System.Text.StringBuilder filePath = new System.Text.StringBuilder(256); 
     
    EncirisWrapper.IDumpASF dump = (EncirisWrapper.IDumpASF)asfWriter; 
     
    dump.get_UserParams(out is_auto_start, out fileSize, out packetSize, baseName, filePath); 

    And this is how the wrapper looks:

    [PreserveSig] 
    int get_UserParams( 
       
    [Out] out int is_auto_start, 
       
    [Out] out int fileSize, 
       
    [Out] out int packetSize, 
       
    [MarshalAs(UnmanagedType.LPStr)] System.Text.StringBuilder baseName, 
       
    [MarshalAs(UnmanagedType.LPStr)] System.Text.StringBuilder filePath     
       
    ); 

    -Svein

    • Proposed as answer by Svein B Thursday, February 10, 2011 10:25 AM
    • Marked as answer by Svein B2 Thursday, February 10, 2011 1:09 PM
    Thursday, February 10, 2011 10:24 AM