Using Pinvoke with C++ DLL and ByRef RRS feed

  • Question

  • I've been fumbling my way through this issue for several weeks and could use some help.  I have read several topics on this, but nothing seems to work. Please forgive me, as I'm not much of a VB programmer but helping someone out with a problem they are having.

    I have a C++ DLL, written by someone in Sweden, that I need to call from  I think I have 99% of it right, but something isn't quite working.  I am trying to pass Doubles and Strings byRef.  

    Here is what I'm trying to do in VB:

    Imports System.Runtime.InteropServices 
    Imports System.IO 
    Public Class Form1 
        Public Declare Function libjwa_Connect Lib "libjwa.dll" (ByVal mode As Integer, ByVal logmode As Integer, ByVal logfile As String) As Integer 
        Declare Auto Function libjwa_debugformShow Lib "libjwa.dll" () As Integer 
        'Declare Auto Function libjwa_EntityIOCTL_ByString Lib "libjwa.dll" (ByVal entity_id As Integer, ByVal IOCTLMODE_READ As Integer, ByVal ENTITY_NAME As Integer, ByRef buf As String) As Integer 
        Public Declare Auto Function libjwa_EntityData_ByDouble Lib "libjwa.dll" (ByVal signal_nr As Integer, ByVal mode As Integer, ByRef buffer As Double, ByVal data_length As Integer) As Integer 
        Public Declare Auto Function libjwa_EntityIOCTL_ByString Lib "libjwa.dll" (ByVal entity_id As Integer, ByVal IOCTLMODE_READ As Integer, ByVal ENTITY_NAME As Integer, ByRef buf As String) As Integer 
        Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load 
        End Sub 
        Public strVal As String = "" 
        Dim logFile As String = System.AppDomain.CurrentDomain.BaseDirectory() & "logData.txt" 
        Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click 
            MsgBox(libjwa_Connect(1, 1, logFile)) 
            libjwa_EntityIOCTL_ByString(7, 1, 1, strVal) 
            For i = 0 To 8 
                Dim gsrreading As Double = i 
                Dim returnval3 As Integer = i 
                returnval3 = libjwa_EntityData_ByDouble(7, 1, gsrreading, 0) 
                MsgBox("returnval3: " & returnval3 & "   gsrreading: " & gsrreading & "   i: " & i) 
         End Sub 
        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) 
        End Sub 
    End Class 

    And here is the hpp for the dll:

    // This file is copyright (c) JWA Systems 2004 
    extern "C" __declspec(dllexport) unsigned __stdcall libjwa_impedanceMeasure(double *resistance, double *reactance); 
    extern "C" __declspec(dllexport) unsigned __stdcall libjwa_impedanceProgress(); 
    extern "C" __declspec(dllexport) unsigned __stdcall libjwa_debugformShow(void); 
    extern "C" __declspec(dllexport) unsigned __stdcall libjwa_ProgramTarget(void); 
    extern "C" __declspec(dllexport) unsigned __stdcall libjwa_Reconnect(char *commport, char *commsettings); 
    extern "C" __declspec(dllexport) unsigned __stdcall libjwa_connection_alive(); 
    extern "C" __declspec(dllexport) unsigned __stdcall libjwa_impedanceReset(void); 
    extern "C" __declspec(dllexport) unsigned __stdcall libjwa_EntityIOCTL(unsigned signal_nr, unsigned mode, unsigned operation, void* buf); 
    extern "C" __declspec(dllexport) unsigned __stdcall libjwa_EntityData(unsigned signal_nr, unsigned mode, void* buf, unsigned data_length); 
    extern "C" __declspec(dllexport) unsigned __stdcall libjwa_Connect(unsigned mode, unsigned log_mode, char *logfile_name); 
    extern "C" __declspec(dllexport) unsigned __stdcall libjwa_Database(unsigned mode, void* buf, unsigned data_length); 
    extern "C" __declspec(dllexport) unsigned __stdcall libjwa_EntityIOCTL_ByString(unsigned signal_nr, unsigned mode, unsigned operation, char* buf); 
    extern "C" __declspec(dllexport) unsigned __stdcall libjwa_EntityIOCTL_ByUnsigned(unsigned signal_nr, unsigned mode, unsigned operation, unsigned* tempintptr); 
    extern "C" __declspec(dllexport) unsigned __stdcall libjwa_EntityData_ByDouble(unsigned signal_nr, unsigned mode, double* buf, unsigned data_length); 
    #define MODE_NOTSPECIFIED 0        // Placeholder for common error in parameter. 
    #define MODE_BLOCKING 1            // Wait for the connection to complete or return with a timeout error. 
    #define MODE_NONBLOCKING 2        // Return immediately. 
    #define IOCTLMODE_UNDEFINED 0           // Placeholder for common error in parameter. 
    #define IOCTLMODE_READ 1                // The ioctl operation will read, and maybe reset the requested item 
    #define IOCTLMODE_PEEK 2                // The ioctl operation will read, but not alter the requested item 
    #define IOCTLMODE_WRITE 3               // The ioctl operation will update the item specified 
    #define IOCTLMODE_CAPABILITIES 4        // If defined this will yield a record describing the possible values for the item specified. 
    #define ENTITYDATA_UNKNOWN 0        // Placeholder for common error in parameter. 
    #define ENTITYDATA_READ 1        // Read data from the entity, act like a fifo queue. The data will be returned in the format defined in the target, no conversions, no scaling and no offset corrections will be carried out 
    #define ENTITYDATA_WRITE 2        // Write data to the entity, act like a fifo queue 
    #define ENTITYDATA_READCOOKED 3        // Read data from the entity, act like a fifo queue. 
                        // A double will be returned, converted using calibration data present in the target. 
    // Statuscodes and error messages 
    // Entity properties 
    #define ENTITY_NAME 1            // A zero terminated string of max. 255 characters long. 
    #define ENTITY_MODIFIED 3        // Has data been communicated since the last call ? 
    #define ENTITY_CONVERSION 4        // A conversion factor between internal data (e.g. AD counts) and a real world value (e.g. volts) 
    #define ENTITY_UNIT 5            // The unit (volt, ohm etc.) 
    #define ENTITY_SYNC 6            // A way of signalling events. 
    #define ENTITY_SYNCSOURCE 7        // A way of signalling events. 
    #define ENTITY_DATATYPE 8        // int double etc 
    #define ENTITY_DATASIZE 9        // number of bytes for each datum 
    #define ENTITY_BYTESRECEIVED 12        // Counter for the total number of bytes received 
    #define ENTITY_BYTESSENT 13        // Counter for the total number of bytes send 
    #define ENTITY_SAMPLERATE 14        // Sets the number of samples per second that should be communicated between target and host. 
    #define ENTITY_RUNFLAG 15        // Control the dataflow between target and host. 
    #define ENTITY_STATUS 16 
    #define ENTITY_CLASS 17            // Defines the functionality of the entity 
    // Each entity falls into a class. 
    #define ENTITYCLASS_UNDEFINED 255    // Serves also as a flag for last entity in target-pc communications at startup. 
    #define ENTITYCLASS_SAMPLEDSIGNAL 1        // Streams of data can be read 
    #define ENTITYCLASS_OUTPUT 2               // Streams of data can be written 
    #define ENTITYCLASS_CONTROLLER 3    // Setpoints can be written, current values can be read, status exist. 
    #define ENTITYCLASS_STORAGE 4              // Streams of data can read and written, IOCTL can touch a filepointer 
    #define ENTITYDATATYPE_FLOAT64 10 
    #define ENTITYUNIT_VOLT 1 
    #define ENTITYUNIT_TIME 2 
    #define ENTITYUNIT_AMP 3 
    #define ENTITYUNIT_MHO 5 
    #define ENTITYUNIT_OHM 6 
    #define MAX_ENTITY 32 
    #define ENTITYRUNFLAG_STOP 0        // Stop the data communications for this entity (stop sampling) 
    #define ENTITYRUNFLAG_START 1        // Start the data communications for this entity (stop sampling) 
    #define ENTITYRUNFLAG_SIMULATE 2    // Let the target generate simulated data for this entity. Useful for testing. 
    #define DATABASE_CREATE 1 
    #define DATABASE_SET 2 
    #define DATABASE_ABANDON 3 
    #define DATABASE_LISTNEXT 5 
    #define LOGGING_UNDEFINED 0 
    #define LOGGING_RECORD 1        // Record all target <--> pc communications into a file using timestamps to retain the original (relative) spatial position of the messages. 
    #define LOGGING_PLAYBACK 2 
    #define LOGGING_DISABLED 3 
    #define LOGGING_CLOSE 4            // Stop recording the data but continue communications 
    #define def_entity_unitnames {"undefined", "volt", "time", "amp", "mAh", "mho", "ohm"}; 
    #define def_entity_datatypenames {"unsigned8", "unsigned16", "unsigned32", "unsigned64", "signed8", "signed16", "signed32", "signed64", "string", "float32", "float64"}; 
    #define def_entity_classnames {"undefined", "sampled signal", "output", "controller", "storage"}; 

    Everything runs without errors and compiles fine, but I can't get the values of the Double or String to change.  Something is preventing the DLL from altering these values.  Is it my code or something native to the language that prevents this?  Am I doing something wrong? 

    Thanks in advance for any help you can provide.

    • Edited by Tys0n Tuesday, June 17, 2008 3:28 PM formatted code
    • Moved by Martin Xie - MSFT Thursday, June 26, 2008 3:25 AM Move from VB General forum to CLR forum for better responses.
    Tuesday, June 17, 2008 3:26 PM

All replies