Use of delegate

B

Bob Simoneau

I am having a hard time with delegates, but here I must pass a delegate and
a pointer to a structure. I am totally lost. Passing the pointer to
rlistsys_resp_func and RLISTSYS_DETAIL is where I am lost. Any hint would
be highly appreciated.

C Header:
_declspec(dllexport) extern void rlistsys(RLISTSYS_PARMS *rlistsys_parms,
RLISTSYS_RESP *rlistsys_resp, void (*rlistsys_resp_func)(RLISTSYS_DETAIL
*));

VB.NET
Dim RLISTSYS_DETAIL As New TRLISTSYS_DETAIL
Dim objDelegate As RLISTSYS_FUNC
objDelegate = AddressOf RLISTSYS_FUNC_RUN
rlistsys(RLISTSYS_PARMS, RLISTSYS_RESP, objDelegate, RLISTSYS_DETAIL)

Module1
Public Delegate Sub RLISTSYS_FUNC(ByRef RLISTSYS_DETAIL As
TRLISTSYS_DETAIL)
Public Sub RLISTSYS_FUNC_RUN(ByRef RLISTSYS_DETAIL As TRLISTSYS_DETAIL)
frmMain.grd.Rows.Add(CleanInput(RLISTSYS_DETAIL.name), CleanInput
(RLISTSYS_DETAIL.description))
End Sub

Public Declare Function rlistsys Lib "remotapi.dll" (ByRef RLISTSYS_PARMS
As TRLISTSYS_PARMS, ByRef RLISTSYS_RESP As TRLISTSYS_RESP, ByRef
objDelegate As RLISTSYS_FUNC, ByRef RLISTSYS_DETAIL As TRLISTSYS_DETAIL) As
Integer


Error:

System.ArgumentException was unhandled
Message="Type could not be marshaled because the length of an embedded
array instance does not match the declared length in the layout."
Source="Chainlinkwork"
StackTrace:
at Chainlinkwork.Module1.rlistsys(TRLISTSYS_PARMS& RLISTSYS_PARMS,
TRLISTSYS_RESP& RLISTSYS_RESP, RLISTSYS_FUNC& objDelegate, TRLISTSYS_DETAIL&
RLISTSYS_DETAIL)
 
B

Brad Rogers

I tried to rewrite that into vb.net and am having difficulty

So can you re-word the problem? does it have to be written as the C part
there? Can you explain the goal?

The tradeoff (apparently) with unmanaged code is flexibility, maybe it cant
be done the same?
 
B

Bob Simoneau

I have a DLL that was written in C many,many years ago. I do not have the
source code. I do have the C header file which has the declaration below.
_declspec(dllexport) extern void rlistsys(RLISTSYS_PARMS *rlistsys_parms,
RLISTSYS_RESP *rlistsys_resp, void (*rlistsys_resp_func)(RLISTSYS_DETAIL
*));

I rewote the header into Delphi several years ago. Its declaration is
below:
function rlistsys(var INRLISTSYS_PARMS: TRLISTSYS_PARMS; var
INRLISTSYS_RESP: TRLISTSYS_RESP; INListSYSFunc: TRListSysFunc): integer;
cdecl;

Now my company is changing to VB.NET 2005 and I am having trouble converting
the code
I basically have to call the rlistsys function passing two structures and a
pointer to a callback function which take a structure as a parameter.
 
B

Bob Simoneau

I am really suffering with the use of delegates. The Listsys function is
getting to me now. The C header
declaration looks like below. Any clue on what a am doing wrong?

_declspec(dllexport) extern void rlistsys(RLISTSYS_PARMS *rlistsys_parms,
RLISTSYS_RESP *rlistsys_resp, void (*rlistsys_resp_func)(RLISTSYS_DETAIL
*));


In the Module I declare the delegate
Public Delegate Sub RLISTSYS_FUNC(ByRef RLISTSYS_DETAIL As TRLISTSYS_DETAIL)

In the main form I create the procedure
Private Sub RLISTSYS_POPULATE(ByRef RLISTSYS_DETAIL As TRLISTSYS_DETAIL)
grd.Rows.Add(CleanInput(RLISTSYS_DETAIL.name),
CleanInput(RLISTSYS_DETAIL.description))
End Sub

On the button click I create a function variable, assign the address of the
populate procedure, and then call the function

Dim RLISTSYS_DETAIL As New TRLISTSYS_DETAIL
Dim objDelegate As RLISTSYS_FUNC
objDelegate = AddressOf RLISTSYS_POPULATE
rlistsys(RLISTSYS_PARMS, RLISTSYS_RESP, objDelegate)

The progran errors on the line above with

"Type could not be marshaled because the length of an embedded array
instance does not match the declared length in the layout"
 
B

Brad Rogers

This one is tricky. Im not familiar enough with procedure on asking this in
the forum, but you could send me the code, nda, etc, I would have to see the
error message generated on my machine and try some things

The length gives errors ?? if you use ildasm does it give you any hints on
length? because its involved with other code types, how do we know sizes?

The delegate part seems to be okay, youre just calling it from addressof,
but in vb.net its not just a pointer to function, but a type safe reference,
from what I know they are not directly interchangeable.
 
P

Peter Huang [MSFT]

Hi Bob,

Thanks for your email.
We did not have the declaration of the unmanaged dll and we did not have
the source code, we did not provide support for a third party dll without
source code to P/Invoke.

In my test code, I try to pass the callback function point without another
structure as the parameter. But the principle should be same.
NOTE:
a.return_text = New String("A", 200)
a.size = Marshal.SizeOf(a)

I create a string with 200 as we declare in the vb.net, if the value is
less than 200, we will get the error.

[.NET code]
Imports System.Runtime.InteropServices
Public Class Form1
Public Structure TRVERSION_PARMS
Dim size As Integer ' REQUIRED Size of structure
End Structure

Public Structure TRVERSION_RESP
Dim size As Integer ' REQUIRED Size of structure
Dim return_code As Integer ' 0 if ( no error, != 0 if ( error
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=200)> _
Dim return_text() As Char ' Contains error text if return code !=
0
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=11)> _
Dim version() As Char ' DLL version
End Structure

Public RVERSION_PARMS As TRVERSION_PARMS
Public RVERSION_RESP As TRVERSION_RESP
Public Delegate Function MyDelegate(ByRef RVERSION_RESP As
TRVERSION_RESP) As Integer

Public Declare Function fnTestDLL Lib "TestDLL.dll" (ByRef
RVERSION_PARMS As TRVERSION_PARMS, ByRef RVERSION_RESP As TRVERSION_RESP,
ByVal md As MyDelegate) As Integer
Public Declare Function fnTest1 Lib "TestDLL.dll" (ByRef RVERSION_RESP
As TRVERSION_RESP) As Integer
Public Function CallBackTest(ByRef RVERSION_RESP As TRVERSION_RESP) As
Integer
MsgBox(RVERSION_RESP.return_text)
End Function
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button1.Click
RVERSION_PARMS.size = Marshal.SizeOf(RVERSION_PARMS)
RVERSION_RESP.size = Marshal.SizeOf(RVERSION_RESP)
MsgBox(fnTestDLL(RVERSION_PARMS, RVERSION_RESP, AddressOf
CallBackTest).ToString())
If (RVERSION_RESP.return_code <> 0) Then
TextBox1.Text = "RVERSION ERROR: " & RVERSION_RESP.return_text
Else
TextBox1.Text = "RVERSION: " & RVERSION_RESP.version
End If
End Sub
Dim a As TRVERSION_RESP
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button2.Click
a.return_text = New String("A", 200)
a.size = Marshal.SizeOf(a)
fnTest1(a)
End Sub
End Class


[C++ Test dll]

#ifdef TESTDLL_EXPORTS
#define TESTDLL_API __declspec(dllexport)
#else
#define TESTDLL_API __declspec(dllimport)
#endif

// This class is exported from the TestDLL.dll
class TESTDLL_API CTestDLL {
public:
CTestDLL(void);
// TODO: add your methods here.
};

#define REQUEST_DECLINED -2

typedef struct rversion_parms_set_1 RVERSION_PARMS;
typedef struct rversion_resp_set_1 RVERSION_RESP;

#pragma pack(1)

struct rversion_parms_set_1
{
int size; /* REQUIRED Size of structure */
};

struct rversion_resp_set_1
{
int size; /* REQUIRED Size of structure */
int return_code; /* = 0 if no error, != 0 if error */
char return_text[200]; /* Contains error text if return code != 0 */
char version[11]; /* DLL version */
};


#pragma pack()
typedef int (__stdcall *pfnTest)(RVERSION_RESP* pt);

extern TESTDLL_API int nTestDLL;

extern "C" TESTDLL_API int fnTestDLL(RVERSION_PARMS *rversion_parms,
RVERSION_RESP *rversion_resp,pfnTest pfn);
extern "C" TESTDLL_API int fnTest1(RVERSION_RESP* pt);



BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}

#ifdef _MANAGED
#pragma managed(pop)
#endif

// This is an example of an exported variable
TESTDLL_API int nTestDLL=0;
pfnTest p;
// This is an example of an exported function.
TESTDLL_API int fnTestDLL(RVERSION_PARMS *rversion_parms, RVERSION_RESP
*rversion_resp,pfnTest pfn)
{
rversion_resp->return_code = 0;
strcpy(rversion_resp->return_text,"Hello");
strcpy(rversion_resp->version,"World");
p= pfn;
return 42;
}

TESTDLL_API int fnTest1(RVERSION_RESP* pt)
{
(*p)(pt);
return 1;
}
// This is the constructor of a class that has been exported.
// see TestDLL.h for the class definition
CTestDLL::CTestDLL()
{
return;
}


Best regards,

Peter Huang
Microsoft Online Partner Support

Get Secure! - www.microsoft.com/security
This posting is provided "AS IS" with no warranties, and confers no rights.
 
B

Bob Simoneau

Thank you so much for your previous help. I hope you don't mind me dipping
into the well of your knowledge again. I am really suffering with the use
of delegates. I am using that same dll as you last helped me with. The
Listsys function is getting to me now. The C header declaration looks like
below. Any clue on what a am doing wrong?

_declspec(dllexport) extern void rlistsys(RLISTSYS_PARMS *rlistsys_parms,
RLISTSYS_RESP *rlistsys_resp, void (*rlistsys_resp_func)(RLISTSYS_DETAIL
*));

In the Module I declare the delegate
Public Delegate Sub MyDelegate(ByRef RLISTSYS_DETAIL As TRLISTSYS_DETAIL)
Public Declare Function rlistsys Lib "remotapi.dll" (ByRef RLISTSYS_PARMS As
TRLISTSYS_PARMS, ByRef RLISTSYS_RESP As TRLISTSYS_RESP, ByVal myva As
MyDelegate) As Integer

In the main form I create the procedure

Private Sub RLISTSYS_POPULATE(ByRef RLISTSYS_DETAIL As TRLISTSYS_DETAIL)
Debug.write((RLISTSYS_DETAIL.name)
End Sub

On the button click I create a function variable, assign the address of the
populate procedure, and then call the function

Dim mydel As myDelegate
mydel = AddressOf RLISTSYS_POPULATE
rlistsys(RLISTSYS_PARMS, RLISTSYS_RESP, myDel)

The progran errors on the line above with

"Type could not be marshaled because the length of an embedded array
instance does not match the declared length in the layout"
 
B

Bob Simoneau

I have a small project which shows the problem which I can send to anyone
who thinks they might be able to help. I did not want to burden the dial-up
people, so I did not attach it. Thanks in advance.
 
P

Peter Huang [MSFT]

Hi Bob,

Did you mean you test with the C++ as I post in my last post and you get
the error?
If so, can you send the C++ code to me? As I said before, without the C++
code it is hard to troubleshoot the problem and we did not support third
party DLL without source code.

Also as I said in my last post, we may need to fill the char array with the
correct length, you may have a try.
e.g.
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles cmdListSys.Click
Dim RLISTSYS_PARMS As New TRLISTSYS_PARMS
Dim RLISTSYS_RESP As New TRLISTSYS_RESP
RLISTSYS_PARMS.size = Marshal.SizeOf(RLISTSYS_PARMS)
RLISTSYS_RESP.size = Marshal.SizeOf(RLISTSYS_RESP)
RLISTSYS_PARMS.hostname = edtHost.Text & New String(Chr(0), 101 -
Len(edtHost.Text))
RLISTSYS_PARMS.system_user = "CHAINLNK" & New String(Chr(0), 101 -
8)
RLISTSYS_PARMS.system_password = "CHAINLNK" & New String(Chr(0),
101 - 8)
RLISTSYS_PARMS.system_select = edtSysSelect.Text & New
String(Chr(0), 11 - Len(edtSysSelect.Text))
RLISTSYS_PARMS.system_name = "*" & New String(Chr(0), 11 - 1)
Dim RLISTSYS_DETAIL As New TRLISTSYS_DETAIL
Dim objDelegate As RLISTSYS_FUNC
objDelegate = AddressOf RLISTSYS_POPULATE
rlistsys(RLISTSYS_PARMS, RLISTSYS_RESP, objDelegate)
If RLISTSYS_RESP.return_code <> 0 Then
grd.AllowUserToAddRows = False
grd.Columns.Clear()
grd.Columns.Add("Response", "Response")
grd.Rows.Add("RLISTSYS ERROR: " &
CleanInput(RLISTSYS_RESP.return_text))
Else
grd.AllowUserToAddRows = False
grd.Columns.Clear()
grd.Columns.Add("Name", "Name")
grd.Columns.Add("Description", "Description")
End If
End Sub

Best regards,

Peter Huang
Microsoft Online Partner Support

Get Secure! - www.microsoft.com/security
This posting is provided "AS IS" with no warranties, and confers no rights.
 
B

Bob Simoneau

I included the remotapi.h in this projects zip, which I just e-mailed to
you. I only have the header source, I do not have the source for the DLL.
The code you last put on this newsgroup helped. I get all the way to the
function call now (I no longer get the error: Type could not be marshaled
because the length of an embedded array instance does not match the declared
length in the layout.) But the dll does not like the data passed. In
delphi I have the data such as HUB01 padded on the right with #0 which is an
ansi null. The vb code is padded with [Nothing] how do a pad the array with
ansi nulls. host_name = 'HUB01" & new String(chr(0),11) does not seem to
work with the DLL.
 
P

Peter Huang [MSFT]

Hi

Based on my test with my C++ dll in in the post before last.
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button2.Click
a.return_text = "Test" & New String(chr(0), 200 - 4)
a.size = Marshal.SizeOf(a)
fnTest1(a)
End Sub

If I pass a string as above code, in the C++ DLL side I set a debug point
in the C++ side.
And find that what I have passed into the C++ side as below.
T
e
s
t
0
0
0
0
...
0

Which is just we are want to pass in the C++.

That is why I said without the C++ source code we can not do further
troubleshooting. Because we did not know what the C++ side want and know
what we are passing into unmanaged code exactly.

Best regards,

Peter Huang
Microsoft Online Partner Support

Get Secure! - www.microsoft.com/security
This posting is provided "AS IS" with no warranties, and confers no rights.
 
B

Bob Simoneau

OK. Thanks for all your help. I understand that without the C++ source code,
it is hard to debug. I do know what the C++ side wants, as I have a working
Delphi application which I wrote. I can clearing see that the array elements
are passed padded with ansi nulls(#0). The managed code shows "h"c, "u"c,
"b"c, "0"c, "1"c, nothing, nothing, nothing, nothing, nothing, nothing. The
delphi code is passing 'h','u','b','0','1',#0, #0, #0, #0, #0, #0. I do
appreciate all your time and effort, I can see from your code sample below,
that they should be the same. I will re-group and re-examine my code. There
has to be something changing, as it works with the Delphi code, but not the
VB.NET The whole project of the Point of Sale conversion from Delphi to
VB.NET relies on that Chainlink DLL, and is now on hold.

Hi

Based on my test with my C++ dll in in the post before last.
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e

System.EventArgs) Handles Button2.Click
a.return_text = "Test" & New String(chr(0), 200 - 4)
a.size = Marshal.SizeOf(a)

End Sub

If I pass a string as above code, in the C++ DLL side I set a debug
point in the C++ side.
And find that what I have passed into the C++ side as below.











Which is just we are want to pass in the C++.

That is why I said without the C++ source code we can not do further
troubleshooting. Because we did not know what the C++ side want and
know what we are passing into unmanaged code exactly.

Best regards,

Peter Huang
Microsoft Online Partner Support

Get Secure! - www.microsoft.com/security This posting is provided "AS
IS" with no warranties, and confers no rights.
 
P

Peter Huang [MSFT]

Hi Bob,

Thanks for your update and feedback.
Because I am not familar with the Delphi, I did not know what is the
internal mechanism of the Delphi to call an C++ DLL.
But I think you may try to write a C++ dll and use a Delphi to call the dll
to see what will be passed into the dll. That way you will have a source
code and you will compare the different between delphi and vb.net.

Thanks for your understanding!

Best regards,

Peter Huang
Microsoft Online Partner Support

Get Secure! - www.microsoft.com/security
This posting is provided "AS IS" with no warranties, and confers no rights.
 
B

Bob Simoneau

Thanks once again for the help. I do not know c++ well enough to write a
DLL. The previous problem was because I had two parameters reversed. I now
have the callback being preformed. The problem is that the callback only
occurs once. What I mean is. If I run the Delphi program, the grid gets
populated with four rows of data. If I run the VB code below, only one row
gets populated, which is the first row shown in the delphi program. Any
hints?


Imports System.Runtime.InteropServices
Imports System.Text

Public Class frmMain
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load
End Sub
Private Sub RLIST_POPULATE(ByRef inRLIST_DETAIL As TRLIST_DETAIL)
Try
Dim source As String
Dim RegNum As String
Dim Target As String
Dim ref_id_1 As String
Dim ref_id_2 As String
Dim lvDate As String
Dim lvTime As String
source = StripNull(inRLIST_DETAIL.source_name)
RegNum = StripNull(inRLIST_DETAIL.request_nbr)
Target = StripNull(inRLIST_DETAIL.target_name)
ref_id_1 = StripNull(inRLIST_DETAIL.ref_id_1)
ref_id_2 = StripNull(inRLIST_DETAIL.ref_id_2) & " "
lvDate = StripNull(inRLIST_DETAIL.creation_date)
lvTime = StripNull(inRLIST_DETAIL.creation_time)
Dim row1 As String() = {source, RegNum, Target, ref_id_1,
ref_id_2, lvDate, lvTime}
grd.Rows.Add(row1)
Catch
MessageBox.Show("Error in Populate")
End Try
End Sub
Private Sub cmdList_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles cmdList.Click
grd.AllowUserToAddRows = False
grd.Columns.Clear()
grd.Columns.Add("Source", "Source")
grd.Columns.Add("RegNum", "RegNum")
grd.Columns.Add("Target", "Target")
grd.Columns.Add("Ref_id_1", "Ref_id_1")
grd.Columns.Add("Ref_id_2", "Ref_id_2")
grd.Columns.Add("Date", "Date")
grd.Columns.Add("Time", "Time")
RLIST_PARMS.size = Marshal.SizeOf(RLIST_PARMS)
RLIST_RESP.size = Marshal.SizeOf(RLIST_RESP)
RLIST_PARMS.ref_id_1 = edtRef1.Text & New String(Chr(0), 11 -
Len(edtRef1.Text))
RLIST_PARMS.hostname = edtHost.Text & New String(Chr(0), 101 -
Len(edtHost.Text))
RLIST_PARMS.system_user = "CHAINLNK" & New String(Chr(0), 101 - 8)
RLIST_PARMS.system_password = "CHAINLNK" & New String(Chr(0), 101 -
8)
RLIST_PARMS.system_select = edtStore.Text & New String(Chr(0), 11 -
Len(edtStore.Text))
RLIST_PARMS.target_name = edtStore.Text & New String(Chr(0), 11 -
Len(edtStore.Text))
RLIST_PARMS.proc_status_code = "REA" & New String(Chr(0), 4 - 3)
RLIST_PARMS.source_name = edtSource.Text & New String(Chr(0), 11 -
Len(edtSource.Text))
Dim cb As New ListDelegate(AddressOf RLIST_POPULATE)
Try
rlist(RLIST_PARMS, RLIST_RESP, cb)
Catch
End Try
If RLIST_RESP.return_code <> 0 Then
grd.AllowUserToAddRows = False
grd.Columns.Clear()
grd.Columns.Add("Response", "Response")
grd.Rows.Add("RLIST ERROR: " &
StripNull(RLIST_RESP.return_text))
End If
End Sub
End Class

Imports System.Runtime.InteropServices
Imports System.Text.RegularExpressions
Module Module1
<StructLayout(LayoutKind.Sequential, Pack:=1, CharSet:=CharSet.Ansi)> _
Public Structure TRLIST_DETAIL
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=4)> _
Public compress_code() As Char
Public container_size As Integer
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=4)> _
Public contents_code() As Char
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=11)> _
Public creation_date() As Char
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=9)> _
Public creation_time() As Char
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=11)> _
Public failure_reason() As Char
Public image_size As Integer
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=51)> _
Public object_title() As Char
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=31)> _
Public original_file_name() As Char
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=11)> _
Public original_file_date() As Char
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=9)> _
Public original_file_time() As Char
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=4)> _
Public proc_status_code() As Char
Public record_count As Integer
Public record_len As Integer
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=11)> _
Public ref_id_1() As Char
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=31)> _
Public ref_id_2() As Char
Public request_nbr As Integer
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=11)> _
Public source_name() As Char
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=11)> _
Public target_name() As Char
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=4)> _
Public xmit_status_code() As Char
Public imm_xmit_tries As Byte
Public reg_xmit_tries As Byte
End Structure
<StructLayout(LayoutKind.Sequential, Pack:=1, CharSet:=CharSet.Ansi)> _
Public Structure TRLIST_PARMS
Public size As Integer
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=101)> _
Public hostname() As Char
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=4)> _
Public proc_status_code() As Char
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=11)> _
Public ref_id_1() As Char
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=31)> _
Public ref_id_2() As Char
Public request_nbr As Integer
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=11)> _
Public source_name() As Char
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=11)> _
Public old_system_password() As Char
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=11)> _
Public old_system_user() As Char
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=11)> _
Public target_name() As Char
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=101)> _
Public system_password() As Char
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=101)> _
Public system_user() As Char
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=11)> _
Public system_select() As Char
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=4)> _
Public xmit_status_code() As Char
End Structure
<StructLayout(LayoutKind.Sequential, Pack:=1, CharSet:=CharSet.Ansi)> _
Public Structure TRLIST_RESP
Public size As Integer ' REQUIRED Size of structure
Public return_code As Integer ' 0 if no error, != 0 if error
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=200)> _
Public return_text() As Char ' Contains error text if return code
!= 0
End Structure
Public RLIST_PARMS As New TRLIST_PARMS
Public RLIST_RESP As New TRLIST_RESP
Public Delegate Sub ListDelegate(ByRef RLIST_DETAIL As TRLIST_DETAIL)
Public Declare Sub rlist Lib "remotapi.dll" (ByRef RLIST_PARMS As
TRLIST_PARMS, ByRef RLIST_RESP As TRLIST_RESP, ByVal myvli As ListDelegate)
Public Function StripNull(ByVal InString As String) As String
Dim iNull As Integer
Dim wrkstr As String
wrkstr = ""
If Len(InString) > 0 Then
iNull = InStr(InString, vbNullChar)
Select Case iNull
Case 0
wrkstr = InString
Case 1
wrkstr = ""
Case Else
wrkstr = Left$(InString, iNull - 1)
End Select
End If
Return wrkstr
End Function
End Module
 
P

Peter Huang [MSFT]

Hi Bob,

Since the callback is called by C++ code, if we did not dig into the C++
source code, we have no idea about what may be the error.
I suggest you contact the C++ DLL development for the source code.

Thanks for your understanding!

Best regards,

Peter Huang
Microsoft Online Partner Support

Get Secure! - www.microsoft.com/security
This posting is provided "AS IS" with no warranties, and confers no rights.
 
B

Bob Simoneau

The developers are long out of business. It must have something to do with
Marshaling, as a call from other languages perform properly. I suspect that
after the delegate is used by the DLL, that the procedure pointed to in
memory gets moved. Does that make sense?
 
B

bobsimoneau

The callback appears to work, but when it trys to update the
TLIST_RESP.return_text it errors with: Attempted to read or write
protected memory. This is often an indication that other memory is
corrupt.
 
P

Peter Huang [MSFT]

Hi Bob,

Thanks for your feedback. It seems that you have opened a new thread for
this problem.
We will follow up in that thread.
Thanks!

Best regards,

Peter Huang
Microsoft Online Partner Support

Get Secure! - www.microsoft.com/security
This posting is provided "AS IS" with no warranties, and confers no rights.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top