Automotive and Embedded Networks

cancel
Showing results for 
Search instead for 
Did you mean: 

Wrap nican.dll nctCreateMessage in C#

We are working with the PXI-8423 CAN bus card, and so far have been using nctInitStart and a CAN database file when starting our application. We would like to use nctCreateMessage so that the application is entirely self contained but are having trouble wrapping the method in C#. I have also not found an example of anyone that has wrapped this in C#.


We are getting the following error when we try to call nctCreateMsg: "NI-CAN: (Hex 0xBFF62207) You passed NULL for a required pointer. Solutions: Consult the Programmer Reference to ensure that you pass valid pointers to the function."

 

 

We have tried a lot of things to figure out the problem, but there are a lot of parameters for this method, and the error message is vague. I have attached the code that has led to this error, any help you can offer would be appreciated.

 

Thank You

0 Kudos
Message 1 of 9
(7,541 Views)
Hi SpaceVector,
Here are some resources that may help you:
 
 
CAN Hardware and Software Manual  Page 8-16 contains information about this function you are using.
 
If you have already seen these, please let me know the specifics of where you are having trouble.  The error you are getting is often caused by another part of your code erroring before the parameters are passed successfully.  Often times, errors will prevent parameters from even passing, so that is why the "NULL" may have been passed.  Please check this and let me know how it goes.
 
Have a great day!
Chris R.
Applications Engineer
National Instruments
0 Kudos
Message 2 of 9
(7,524 Views)
Also, the PXI-8423 is a serial device.  What CAN hardware are you using?
Chris R.
Applications Engineer
National Instruments
0 Kudos
Message 3 of 9
(7,526 Views)

Yes, I have already seen the CAN Hardware and Software Manual. I believe that the trouble is with the Marshaling of data from C# code, which I attached, not the method or use of the method itself.

 

I also made a mistake with the card number it is actually PXI-8464, the PXI-8423 is another card we are using for serial communications as you pointed out.

 

Thanks

Message Edited by SpaceVector on 01-12-2007 03:18 PM

0 Kudos
Message 4 of 9
(7,520 Views)
In the example I am initializing all of the parameters right before the call so I don't know why any of them would be null, this is part of why I am confused by the error code. I think the problem is here where I am importing the method from the dll, but I can not find the error.
 
Signature of the method to import from dll, it also returns an error code:

//cppCreateMessage(ncTypeMessageConfig MessageConfig, u32 NumberOfChannels, ncTypeChannelConfig* ChannelConfigList, i32 Interface, i32 Mode, f64 SampleRate, ncTypeTaskRef* TaskRef)

 

[DllImport("nican.dll")]

protected static extern int nctCreateMessage(MessageConfig messageConfig, int numberOfChannels, [In, Out] ChannelConfig[] ChannelConfigList, int pInterface, int mode, double sampleRate, ref IntPtr taskId);

0 Kudos
Message 5 of 9
(7,503 Views)
C# looks very similar to C++, but CLR 'causes a difference'  when you have to interface with unmanaged code. In VS 2003 marshalling does not support variable length strings.

This is my sample declaration
in VB:

    Private Structure NCTTYPE_CHANNEL_CONFIG
        Dim StartBit As Integer
        Dim NumBits As Integer
        Dim DataType As Integer
        Dim ByteOrder As Integer
        Dim ScalingFactor As Double
        Dim ScalingOffset As Double
        Dim MaxValue As Double
        Dim MinValue As Double
        Dim DefaultValue As Double

        <MarshalAs(UnmanagedType.ByValArray, SizeConst:=64)> _
        Dim Unit() As Byte
        Public Sub Initialize()
            ReDim Unit(63)
        End Sub
    End Structure

And you have to explicitly initialize the structure to allocate memory for Unit():

    Dim confList(0) As
NCTTYPE_CHANNEL_CONFIG
    confList(0).Initialize()

Maybe it will help.

Message Edited by YuGen on 01-17-2007 09:19 AM

Message 6 of 9
(7,492 Views)

Below is what I think is the C# equivalent to what you posted for the struct, which I tried but got the same error message (I did remember to call Initialize before passing it in). The only other parameter I think it may be talking about is the TaskRef, which is null when the method is called. I don't think that the TaskRef is the issue though because it is an out parameter, and we are temporarily using InitStart and we are passing null in for that TaskRef as well, and that method works fine.

 

Thanks for you suggestion, if anyone has any other ideas about what the error might be that would be appreciated.

public

struct ChannelConfig

    {

        public int startBits;

        public int numBits;

        public int dataType;

        public int byteOrder;

        public double scalingFactor;

        public double scalingOffset;

        public double maxValue;

        public double minValue;

        public double defaultValue;

        [MarshalAs(UnmanagedType.ByValArray, SizeConst=64)]

        public byte[] unit;

        public void Initialize()

        {

            unit = new byte[64];

        }

     }

 

0 Kudos
Message 7 of 9
(7,481 Views)
What I figured out from my experiments with VB.NET 2003:

1) The structure I described above worked fine when I sent a reference to a variable of this type.

2) But I could not send an array of structures of such type.

3) A trick which worked fine for arrays of structures: to replace the abovementioned structure with this one:

public struct ChannelConfig
{
    public int startBits;
    public int numBits;
    public int dataType;
    public int byteOrder;
    public double scalingFactor;
    public double scalingOffset;
    public double maxValue;
    public double minValue;
    public double defaultValue;
    // public byte[64] unit;
    // -- replaced with
16 variables (or maybe 8 of type int64)
    public int32 unit0;
    public int32 unit1;
    // ...
    public int32 unit14;
    public int32 unit15;
}

The C-declaration
int _stdcall MyFunction(struct ChannelConfig *p);

should be replaced with (VB)
Declare Function MyFunction(ByRef p As ChannelConfig) As Integer

I don't know anything more elegant.


P.S.
The TaskRef variable is an output parameter. Its initial value does not matter.

Message Edited by YuGen on 01-17-2007 02:21 PM

0 Kudos
Message 8 of 9
(7,474 Views)

thanks for the code Yugen, I was having some problems porting and existing vb6 program to vb.net

0 Kudos
Message 9 of 9
(2,806 Views)