External function byref argument doesn't contain the result

Hello,

I want to use zkemkeeper.dll to communicate with an access control device.
I can successfully connect to it, I can read some log data data from it.

I wanted to develop my software and add more features.
I began implementing some basic features like reading the device’s MAC address, or IP address, and others.
Calling the functions are resulting empty string.

The demo programs that came with the SDK are running well. (they are written in C# and VB).

This is the code that calls the external function:

    Dim sIP As String = ""
If AxCZKEM1.GetDeviceIP(iMachineNumber, sIP) = True Then
      txtShow.Text = sIP
    Else
      AxCZKEM1.GetLastError(idwErrorCode)
      MsgBox("Operation failed,ErrorCode=" + str(idwErrorCode))
    End If

I don’t really understand how external libraries work with XOJO, but I suppose when compiling XOJO reads the functions from the DLL and creates invoke functions.
This is the invokefunction for GetDeviceIP:

Function GetDeviceIP(dwMachineNumber_Param As Integer, ByRef IPAddr_Param As String) As Boolean
  If mThis = Nil Then Raise New NilObjectException
  Dim func As New GetDeviceIP_Func3(mThis.Ptr( 0 ).Ptr(204 ))
  Dim resultCode As Integer
  Dim Local_IPAddr_Param As Ptr
  Dim Return_pVal_Param As Int16
  resultCode = func.Invoke(mThis, dwMachineNumber_Param, Local_IPAddr_Param, Return_pVal_Param)
  If resultCode = 0 Then
    Return COM.VARIANTBOOLToRBBoolean(Return_pVal_Param)
  Else // Throw Exception
    Raise New COM.COMException("Failed on GetDeviceIP", resultCode)
  End If
  
End Function

I’m not so professional with these, but doesn’t miss a line where Local_IPAddr_Param is set to the pointer of IPAddr_Param argument?
Because Local_IPAddr_Param remaing empty while this functions runs.

I need to mention that I’m using an old 2014 version of RealStudio, but I hope it doesn’t matter.

If you can post a link to the sdk with the c#/vb source from the manufacturer I’ll take a look and see if I can help.

Absolutely. As Tim said, please post the API description. From the code I would guess Local_IPAdr_Param would be a Cstring or similar. You should try to assign Local_IPAddr_Param.Cstring(0) to IPAddr_Param (or whatever the type is) before returning after If Resultcode = 0.

Hello,

Here is the download link for the SDK. In the zip file there are the demos too.

https://server.zkteco.eu/ddfb/standalonesdk-6.3.1.37-doc-2.1.0-demo-1.1.15.zip

In the meantime I checked another function invoke which is working, the connection function invoke:

Function Connect_Net(IPAdd_Param As String, Port_Param As Integer) As Boolean
  If mThis = Nil Then Raise New NilObjectException
  Dim func As New Connect_Net_Func3(mThis.Ptr( 0 ).Ptr(184 ))
  Dim resultCode As Integer
  Dim Local_IPAdd_Param As Ptr
  Local_IPAdd_Param = COM.SysAllocString( IPAdd_Param )
  Dim Return_pVal_Param As Int16
  resultCode = func.Invoke(mThis, Local_IPAdd_Param, Port_Param, Return_pVal_Param)
  COM.SysFreeString(Local_IPAdd_Param)
  If resultCode = 0 Then
    Return COM.VARIANTBOOLToRBBoolean(Return_pVal_Param)
  Else // Throw Exception
    Raise New COM.COMException("Failed on Connect_Net", resultCode)
  End If
  
End Function

There is a line Local_IPAdd_Param = COM.SysAllocString( IPAdd_Param ), which sets the result pointer to the appropriate argument pointer. But in GetDeviceIP function the same line, with the correct parameters doesn’t work.

Try this:

Public Function GetDeviceIP(dwMachineNumber_Param As Integer, ByRef IPAddr_Param As String) As Boolean
  If mThis = Nil Then Raise New NilObjectException
  Dim func As New GetDeviceIP_Func3(mThis.Ptr( 0 ).Ptr(204 ))
  Dim resultCode As Integer
  
  '---
  'Dim Local_IPAddr_Param As Ptr
  Dim Local_IPAddr_Param As New MemoryBlock(COM.SIZEOF_VARIANT)
  '---
  
  Dim Return_pVal_Param As Int16
  resultCode = func.Invoke(mThis, dwMachineNumber_Param, Local_IPAddr_Param, Return_pVal_Param)
  If resultCode = 0 Then
    
    '---
    Dim IPAddr As Variant = COM.VARIANTToRBVariant(Local_IPAddr_Param)
    IPAddr_Param = IPAddr
    COM.FreeVARIANT(Local_IPAddr_Param)
    '---
    
    Return COM.VARIANTBOOLToRBBoolean(Return_pVal_Param)
  Else // Throw Exception
    Raise New COM.COMException("Failed on GetDeviceIP", resultCode)
  End If
  
End Function

Hello,

Unfortunately the invoke requires Ptr, not a memoryBlock

Did you try it? MemoryBlocks can be passed as Ptr’s

In the meantime I figured out that there are some functions that are resulting an integer, not a string.
These are working perfectly.
So the problem is the string result, which is very strange, because the invoke function resulting an integer looks the same as the invoke function resulting a string:

Function QueryState(ByRef State_Param As Integer) As Boolean
  If mThis = Nil Then Raise New NilObjectException
  Dim func As New QueryState_Func2(mThis.Ptr( 0 ).Ptr(408 ))
  Dim resultCode As Integer
  Dim Return_pVal_Param As Int16
  resultCode = func.Invoke(mThis, State_Param, Return_pVal_Param)
  If resultCode = 0 Then
    Return COM.VARIANTBOOLToRBBoolean(Return_pVal_Param)
  Else // Throw Exception
    Raise New COM.COMException("Failed on QueryState", resultCode)
  End If
  
End Function

  

I tried the code, and gives typemissmatch error

Change the Delegate of GetDeviceIP_Func3 to use a MemoryBlock in the parameter or create a variable called p and assign the memoryblock to it to get its pointer?

Dim p as Ptr = Local_IPAddr_Param 

Where did you get your CZKEM OLEContainer code from? Was it automatically generated when you inserted the ActiveX component into the project?

I just did it in 2018r1.1 which was the last 32bit edition and the code it generated is vastly different to the one you posted.

Try what I mentioned above, if that doesn’t work, try this which is auto generated by inserting the 32bit activex component in 2018r1.1

If mThis = Nil Then Raise New NilObjectException
Dim func As New GetDeviceIP_Func3(mThis.Ptr( 0 ).Ptr(51 * COM.SIZEOF_PTR ))
Dim resultCode As Integer
Dim Local_IPAddr_Param As Ptr = COM.SysAllocString( IPAddr_Param )
Dim Return_pVal_Param As Int16
resultCode = func.Invoke(mThis, dwMachineNumber_Param, Local_IPAddr_Param, Return_pVal_Param)
IPAddr_Param = COM.BSTRToRBString(Local_IPAddr_Param)
COM.SysFreeString(Local_IPAddr_Param)
If resultCode = 0 Then
  Return COM.VARIANTBOOLToRBBoolean(Return_pVal_Param)
Else // Throw Exception
  Raise New COM.COMException("Failed on GetDeviceIP", resultCode)
End If

JulianS’s code works with a little modification.
In my version there is no COM.SIEOF_PTR() function. But I just replaced the original .Ptr(204) and works fine.
Now I can modify all the invoke functions according to this example.

Thank you very much for your support guys.

1 Like