none
char* argument and return from a C++ DLL export function to a VB.net aplication RRS feed

  • Question

  • I have a C++ dll that that has a function with a char* argument and also with a return type of char*. The function definition is following-

     char * scanImage(char * fileDir){
        string dir(fileDir);
        string cvStr = cvScan(dir);
        char * scanReturn;
        scanReturn = (char*)malloc((sizeof(char)* cvStr.size()) + 1);
        strcpy(scanReturn, cvStr.c_str());
        return scanReturn;
    }

    DLL header definitionion:

    extern "C"  THEIA_OPENCV_DLL_API char * scanImage(char * fileDir);

    Now I want to call the function from a VB.net client application. I know there is complicacy to pass and get char* from native to .NET. I also know a little that I need to marshall the argument as well as the return. But I have no idea how to implement that code.

    I have been trying with various implementations so far. But none of that worked.

    Imports System
    Imports System.Runtime.InteropServices
    Public Class Form1
    
        Public Declare Function scanImage Lib "myDll.dll" (<MarshalAs(UnmanagedType.LPStr)> fileDir As String) As <MarshalAs(UnmanagedType.LPStr)> String
    
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            Try
                scanImage("directory/file.bmp")
            Catch err As Exception
                MsgBox(err.Message)
            End Try
    
        End Sub
    End Class

    Finally, this code has thrown the following error-

    error:

    System.AccessViolationException occurred
      HResult=0x80004003
      Message=Attempted to read or write protected memory. This is often an indication that other memory is corrupt.

    Now I need help to call the dll function from a vb.net application and read the return properly.


    Sayom Shakib




    Friday, January 5, 2018 3:49 PM

Answers

  • Thanks to everyone.

    Solved it:

    Public Class Form1
      
     <DllImport("Theia_OpenCV_Dll.dll", CallingConvention:=CallingConvention.Cdecl)>
        Public Shared Function scanImage(ByVal fileDir As String) As System.IntPtr
        End Function
    
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            Dim p As IntPtr = scanImage("image.bmp")
            Dim result As String = Marshal.PtrToStringAnsi(p)
            Label1.Text = result
        End Sub
    End Class


    <g class="gr_ gr_6 gr-alert gr_spell gr_inline_cards gr_run_anim ContextualSpelling" data-gr-id="6" id="6">nsssayom</g>


    • Marked as answer by Sayom Shakib Saturday, January 6, 2018 8:37 AM
    • Edited by Sayom Shakib Saturday, January 6, 2018 8:37 AM
    Saturday, January 6, 2018 8:37 AM

All replies

  • Can you post the C definition of scanImage? There must be a definition of it in a .h file. Having the definition will ensure someone can provide the correct answer.

    Also please check the documentation for what it does for errors. It probably does not throw an exception. I assume that you should be checking the return value for a null (is that "Nothing" in VB?). Are you sure that the return value is not null?



    Sam Hobbs
    SimpleSamples.Info


    Friday, January 5, 2018 4:32 PM
  • Can you post the C definition of scanImage? There must be a definition of it in a .h file. Having the definition will ensure someone can provide the correct answer.

    Also please check the documentation for what it does for errors. It probably does not throw an exception. I assume that you should be checking the return value for a null (is that "Nothing" in VB?). Are you sure that the return value is not null?



    Sam Hobbs
    SimpleSamples.Info


    I have included the header file defination of the function. 

    Sayom Shakib


    Friday, January 5, 2018 4:42 PM
  •  Perhaps try this...

        Public Declare Function scanImage Lib "myDll.dll" (<MarshalAs(UnmanagedType.LPStr)> fileDir As String) As <MarshalAs(UnmanagedType.LPStr)> System.Text.StringBuilder
    
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            Dim sb As System.Text.StringBuilder = scanImage("YourStringPath....")
            Label1.Text = sb.ToString
        End Sub

     Perhaps you may have to marshal the strings with the (UnmanagedType.LPTStr) or (UnmanagedType.LPWStr) types.

     You can also read through some of the link below if you have not seen it before.

    Default Marshaling for Strings

     

    If you say it can`t be done then i`ll try it

    • Edited by IronRazerz Friday, January 5, 2018 6:15 PM
    Friday, January 5, 2018 6:13 PM
  • According to https://social.msdn.microsoft.com/Forums/en-US/e03c925e-c094-40f1-9fb0-20ac8dc5972d, seems that you have to use a different allocator:

       scanReturn = (char*)CoTaskMemAlloc( ( cvStr.size() + 1 ) * sizeof( char ) );

    The System will free this memory.

    • Edited by Viorel_MVP Friday, January 5, 2018 7:22 PM
    Friday, January 5, 2018 7:10 PM
  • Since the DLL is expecting a pointer anyway I wonder if he can't declare the import parameters as IntPtr and then use Marshal.StringToBSTR to get a valid pointer... purely a guess at this point.

    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"

    Friday, January 5, 2018 8:13 PM
    Moderator
  • I have included the headfile defination of the function. 

    I am sorry but where is that? I don't see that anywhere in this thread. Other members are speculating about what might work but if we know the actual definition of the function then someone can tell you what will definitely work.


    Sam Hobbs
    SimpleSamples.Info

    Saturday, January 6, 2018 12:55 AM
  • I have included the headfile defination of the function. 

    I am sorry but where is that? I don't see that anywhere in this thread. Other members are speculating about what might work but if we know the actual definition of the function then someone can tell you what will definitely work.


    Sam Hobbs
    SimpleSamples.Info


    its in an edit of the original post

    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"

    Saturday, January 6, 2018 2:19 AM
    Moderator
  • Okay, sorry; I see it now. Just to be sure, what is THEIA_OPENCV_DLL_API? That probably does not make a difference but it could. Yes, I know that THEIA_OPENCV_DLL_API is a macro but what is it's definition?

    Reed Kimble was guessing when he suggested IntPtr but c# - PInvoke for C function that returns char * - Stack Overflow says we must use IntPtr for a string returned from C. The language is C# in that answer but I am sure you can apply it to VB too.



    Sam Hobbs
    SimpleSamples.Info

    Saturday, January 6, 2018 4:34 AM
  • Okay, sorry; I see it now. Just to be sure, what is THEIA_OPENCV_DLL_API? That probably does not make a difference but it could. Yes, I know that THEIA_OPENCV_DLL_API is a macro but what is it's definition?

    Reed Kimble was guessing when he suggested IntPtr but c# - PInvoke for C function that returns char * - Stack Overflow says we must use IntPtr for a string returned from C. The language is C# in that answer but I am sure you can apply it to VB too.



    Sam Hobbs
    SimpleSamples.Info

    #pragma once
    
    #include <Windows.h>
    #include <string>
    using namespace std;
    
    #ifdef THEIA_OPENCV_DLL_EXPORTS
    #define THEIA_OPENCV_DLL_API __declspec(dllexport)
    #else
    #define THEIA_OPENCV_DLL_API __declspec(dllimport)
    #endif
    
    extern "C"  THEIA_OPENCV_DLL_API int scanImage(char * fileDir, char *outPut);
    This is the complete header file code for the program. I hope this will help you more.


    Sayom Shakib

    Saturday, January 6, 2018 5:40 AM
  •  Perhaps try this...

        Public Declare Function scanImage Lib "myDll.dll" (<MarshalAs(UnmanagedType.LPStr)> fileDir As String) As <MarshalAs(UnmanagedType.LPStr)> System.Text.StringBuilder
    
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            Dim sb As System.Text.StringBuilder = scanImage("YourStringPath....")
            Label1.Text = sb.ToString
        End Sub

     Perhaps you may have to marshal the strings with the (UnmanagedType.LPTStr) or (UnmanagedType.LPWStr) types.

     You can also read through some of the link below if you have not seen it before.

    Default Marshaling for Strings

     

    If you say it can`t be done then i`ll try it

    Tried the code. The program gets terminated. 

    Sayom Shakib

    Saturday, January 6, 2018 6:17 AM
  • According to https://social.msdn.microsoft.com/Forums/en-US/e03c925e-c094-40f1-9fb0-20ac8dc5972d, seems that you have to use a different allocator:

       scanReturn = (char*)CoTaskMemAlloc( ( cvStr.size() + 1 ) * sizeof( char ) );

    The System will free this memory.

    Thanks for this tip. This will solve the memory leakage problem. But I still cannot call the DLL function from VB.NET.

    Sayom Shakib


    Saturday, January 6, 2018 6:18 AM
  • You already have everything you need. This is your project; I don't know VB syntax.


    Sam Hobbs
    SimpleSamples.Info

    Saturday, January 6, 2018 6:25 AM
  • Thanks to everyone.

    Solved it:

    Public Class Form1
      
     <DllImport("Theia_OpenCV_Dll.dll", CallingConvention:=CallingConvention.Cdecl)>
        Public Shared Function scanImage(ByVal fileDir As String) As System.IntPtr
        End Function
    
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            Dim p As IntPtr = scanImage("image.bmp")
            Dim result As String = Marshal.PtrToStringAnsi(p)
            Label1.Text = result
        End Sub
    End Class


    <g class="gr_ gr_6 gr-alert gr_spell gr_inline_cards gr_run_anim ContextualSpelling" data-gr-id="6" id="6">nsssayom</g>


    • Marked as answer by Sayom Shakib Saturday, January 6, 2018 8:37 AM
    • Edited by Sayom Shakib Saturday, January 6, 2018 8:37 AM
    Saturday, January 6, 2018 8:37 AM