0

My VB.NET 2017 windows forms app needs to interface to Visual-C++ DLL (also VS2017) function Read_Parameters() that takes two arguments: board# and pointer to a parameter array of 256 elements, where each parameter is an unsigned short. How do I declare matching VB.NET pointer to unsigned short table?

VISUAL-C++ DECLARATION:

int Read_Parameters(unsigned char board, unsigned short *params)
{
   ...
   return something;
}

CORRESPONDING VB.NET DECLARATION

<DllImport("MuseDll.dll")>
Public Shared Function test_Read_Parameters(ByVal board As Byte, ByVal params As UShort()) As Int32
End Function

VB.NET CODE....

Private Sub Button_test_main_board_Click(sender As Object, e As EventArgs) Handles Button_test_main_board.Click
    Dim return_status As Int32
    Dim board_index As Byte
    Dim parameter_table(256) As UShort

parameter_table(0) = 2
board_index = 1
return_status = main_board_interface.NativeMethods.test_Read_Parameters( board_index, parameter_table)
If return_status = 513 Then
    TextBox_main_board_comm.Text &= "test_return_int return OK =" & return_status & vbCrLf
Else
    TextBox_main_board_comm.Text &= "test_return_int return FAULT!! = " & return_status & vbCrLf
    Return
End If

return_status SHOULD BE 513 BUT IS A DIFFERENT LARGE # EACH TIME

Doug Null
  • 7,989
  • 15
  • 69
  • 148
  • It is very likely to be an array given the function name, so ByVal UShort(). Note that it does not know how large the array is. That's pretty risky, if the array you pass is too short then it will corrupt the GC heap. Aim high. The *board* argument should be Byte. Talk to the owner of the native code, pretty likely that somebody already did this. – Hans Passant Jul 21 '17 at 15:59
  • "I have met the enemy and they is us." I have control of both DLL & VB source. Thanks yet again, Hans! – Doug Null Jul 21 '17 at 22:08
  • Actually, I don't want to pass the array, I want to pass a pointer to the array, for obvious reasons. – Doug Null Jul 21 '17 at 22:18
  • Your answer (and Vincent's 4th scenario), Hans. And I assume it is passing merely pointer and not entire short array. – Doug Null Jul 21 '17 at 22:51
  • @DougNull : Technically you can never pass _the entire array_. Arrays are reference types, which means that once you create a new array it will have a specific location in memory, and you alwyas access _that specific array_ via its _reference pointer_. The opposite of reference types is _value types_ (such as `Integer`s and other structures). A value type doesn't have a specific location in memory, so every time you try to access one a copy is created. [**This answer of mine**](https://stackoverflow.com/a/45043490/3740093) includes a rather basic demonstration of what I just explained. – Visual Vincent Jul 22 '17 at 00:16
  • So to verify your assumption: Both yes and no. You are giving the C++ method _access_ to the whole array, but you are merely passing it the array's reference pointer. -- The thing here though is that in C++ pointers can, _**in some cases**_, be used like arrays due to how arrays work: Arrays actually point to the very first item of the array. Combining that with the fact that arrays can only hold one type at a time, makes it rather easy to figure out where the another array item is located in memory. – Visual Vincent Jul 22 '17 at 00:42
  • You just need to take the address of the first item (which is what the array points to) and add that with the index of the item you want to get, multiplied with the item size: `baseaddr + (index * size)`. -- Say you have an array of shorts where the first item has _the address_ `10`. Each short takes 2 bytes of memory. Now given the pointer to the array (which points to the first item) you can get the short at index 3 via: `10 + (3 * 2)` - which results in address `16`. -- This is basically what happens if you'd do: `unsigned short i = params[3];` in your C++ code. – Visual Vincent Jul 22 '17 at 00:54
  • (Sorry for spamming the comments) Correcting myself: `Arrays actually point to the very first item of the array` should be: _"Pointers to arrays actually point to the very first item of the array"_. – Visual Vincent Jul 22 '17 at 01:02

1 Answers1

1

There are a few different scenarios depending on what the C++ code uses the parameters for...

The first parameter isn't necessarily a Char. unsigned char can also be mapped to a Byte (again, it all depends on what the C++ code does with the parameter).

The second parameter could either be:

  • A reference to a UShort, in which case ByRef params As UShort should be used, or:

  • An array of UShorts, in which case it is mapped to ByVal params As UShort(). -- Seeing as the parameter is named params ("parameters") I find this option the most likely one.

All four scenarios:

<DllImport("MuseDll.dll")>
Public Shared Function Read_Parameters(ByVal board As Char, ByRef params As UShort) As Integer
End Function


<DllImport("MuseDll.dll")>
Public Shared Function Read_Parameters(ByVal board As Byte, ByRef params As UShort) As Integer
End Function


<DllImport("MuseDll.dll")>
Public Shared Function Read_Parameters(ByVal board As Char, ByVal params As UShort()) As Integer
End Function


<DllImport("MuseDll.dll")>
Public Shared Function Read_Parameters(ByVal board As Byte, ByVal params As UShort()) As Integer
End Function
Visual Vincent
  • 18,045
  • 5
  • 28
  • 75
  • 1
    4th scenario was it, Vincent. Thanks! (BTW, I'm 1/4 Swede, which ain't too shabby) – Doug Null Jul 21 '17 at 22:49
  • @DougNull : Glad I could help! "Lycka till!" ;) -- I'm curious to know how you are 1/4 Swede though? (I would've understood if you were 1/2) - Do you have a Swedish grandparent? – Visual Vincent Jul 21 '17 at 23:59