Hello everybody!
I need your help again.
I'm having trouble converting a function pointer from VO to a delegate in XSharp.
The function worm_export_tar of the WORMAPI.DLL of the german "Kassensicherungsverordnung" needs a functionpointer to export data from the securitymodul (TSE = technische Sicherheitseinrichtung).
WORMAPI.DLL was created by Swissbit who developed the TSE system.
WORMAPI.DLL is not under my control and I assume that the functions it contains will work correctly.
The worm_export_tar function makes multiple calls to a callback function and passes a memory pointer containing the data to be written to the export file.
In VO the following code works fine:
METHOD ExportTar(cDateiname AS STRING) AS INT PASCAL CLASS WormAccess
LOCAL hFile AS PTR
LOCAL nRet AS INT
nRet := -1
IF !(SELF:hWormContext == NULL_PTR)
hFile := FCreate(cDateiname, FC_NORMAL)
IF !(hFile == F_ERROR)
//The pointer to the callback function is passed here
nRet := worm_export_tar(SELF:hWormContext, @CallbackExportWormTar(), hFile)
FClose(hFile)
ELSE
nRet := -2
ENDIF
ENDIF
RETURN nRet
//This is the callback-funkction which writes the data to the export-file:
STATIC FUNCTION CallbackExportWormTar(hDaten AS PTR, nLen AS DWORD, hFile AS PTR) AS INT
LOCAL nRet AS INT
IF FWrite3(hFile, hDaten, nLen) == nLen
nRet := 0
ELSE
nRet := -1
ENDIF
RETURN nRet
STATIC GLOBAL hProc_worm_export_tar AS TF_worm_export_tar PTR
FUNCTION TF_worm_export_tar(hWormContext AS PTR, hCallbackFunktion AS PTR, hFile AS PTR) AS INT PASCAL
RETURN 0
FUNCTION worm_export_tar(hWormContext AS PTR, hCallbackFunktion AS PTR, hFile AS PTR) AS INT PASCAL
RETURN PCALL(hProc_worm_export_tar, hWormContext, hCallbackFunktion, hFile)
In XSharp, the following code crashes exactly and reproducibly the third time the callback function is called. No error box is displayed, the program is simply terminated. The only difference between VO and XSharp is that XSharp uses the delegate to invoke the callback function.
DELEGATE CallbackExportWormTar_delegate(hDaten AS PTR, nLen AS DWORD, hFile AS PTR) AS INT
METHOD ExportTar(cDateiname AS STRING) AS INT PASCAL
LOCAL hFile AS PTR
LOCAL nRet AS INT
STATIC LOCAL oCallbackExportWormTarDelegate AS CallbackExportWormTar_Delegate
nRet := -1
IF !(SELF:hWormContext == NULL_PTR)
hFile := FCreate(cDateiname, FC_NORMAL)
IF !(hFile == F_ERROR)
oCallbackExportWormTarDelegate := CallbackExportWormTar
nRet := worm_export_tar(SELF:hWormContext, System.Runtime.InteropServices.Marshal.GetFunctionPointerForDelegate(oCallbackExportWormTarDelegate), hFile)
FClose(hFile)
ELSE
nRet := -2
ENDIF
ENDIF
RETURN nRet
STATIC FUNCTION CallbackExportWormTar(hDaten AS PTR, nLen AS DWORD, hFile AS PTR) AS INT
LOCAL nRet AS INT
IF FWrite3(hFile, hDaten, nLen) == nLen
nRet := 0
ELSE
nRet := -1
ENDIF
RETURN nRet
STATIC GLOBAL hProc_worm_export_tar AS TF_worm_export_tar PTR
FUNCTION TF_worm_export_tar(hWormContext AS PTR, hCallbackFunktion AS PTR, hFile AS PTR) AS INT PASCAL
RETURN 0
FUNCTION worm_export_tar(hWormContext AS PTR, hCallbackFunktion AS PTR, hFile AS PTR) AS INT PASCAL
RETURN PCALL(hProc_worm_export_tar, hWormContext, hCallbackFunktion, hFile)
In both cases (VO and XSharp) the hProc_worm_export_tar variable is initialized once when the TSE system is started:
hLibWorm := LoadLibrary(String2Psz("wormapi.dll"))
hProc_worm_export_tar := GetProcAddress(hLibWorm, String2Psz("worm_export_tar"))
So the question is: What is wrong with the delegate or the callback-function in XSharp what works fine in VO? What's weird is that it works twice and crashes on the third call in XSharp.
Regards
Kai
Question about converting a function pointer to a delegate
Question about converting a function pointer to a delegate
Hi Kai,
Try running the app in debug mode (Debug->Start integrated debugging). you should get some runtime error message when the crash occurs.
I assume you have set your app to be x86 mode? Also try changing the PTR in the delegate to IntPtr, should not make a difference, but just in case.
Finally, can you produce a sample?
.
Try running the app in debug mode (Debug->Start integrated debugging). you should get some runtime error message when the crash occurs.
I assume you have set your app to be x86 mode? Also try changing the PTR in the delegate to IntPtr, should not make a difference, but just in case.
Finally, can you produce a sample?
.
Chris Pyrgas
XSharp Development Team
chris(at)xsharp.eu
XSharp Development Team
chris(at)xsharp.eu
Question about converting a function pointer to a delegate
Hi Kai,
I have created a X# COM library for this API for someone else and have used the C# WormCApi.dll for the interface to this DLL,
Maybe it could be an idea to do the same and not do all work again.
Wolfgang
I have created a X# COM library for this API for someone else and have used the C# WormCApi.dll for the interface to this DLL,
Maybe it could be an idea to do the same and not do all work again.
Wolfgang
Wolfgang Riedmann
Meran, South Tyrol, Italy
wolfgang@riedmann.it
https://www.riedmann.it - https://docs.xsharp.it
Meran, South Tyrol, Italy
wolfgang@riedmann.it
https://www.riedmann.it - https://docs.xsharp.it
Question about converting a function pointer to a delegate
Hi Kai,
Try removing the STATIC modifier:
STATIC FUNCTION CallbackExportWormTar
As far as I understand, in X# it is equivalent to INTERNAL. This may block its call even though it is essentially converted to a direct pointer.
Best regards,
Leonid
Try removing the STATIC modifier:
STATIC FUNCTION CallbackExportWormTar
As far as I understand, in X# it is equivalent to INTERNAL. This may block its call even though it is essentially converted to a direct pointer.
Best regards,
Leonid
Best regards,
Leonid
Leonid
Question about converting a function pointer to a delegate
Hi!
Removing static modifier didn't work.
Unfortunately, changing PTR to intPtr didn't work either.
The debugger reports:
System.Reflection.TargetInvocationException
Ein Aufrufziel hat einen Ausnahmefehler verursacht.
Callstack :
CCTouchpad.Boolean CCTouchpad.Klick(System.Int32 x, System.Int32 y)() : C:XSharpKassePPKasseSharePPKasseShareCCTouchpad.prg : 1169
CCTouchpad.__Usual CCTouchpad.Dispatch(XSharp.__Usual[] Xs$Args)() : C:XSharpKassePPKasseSharePPKasseShareCCTouchpad.prg : 699
XAPP.__Usual XAPP.Start(XSharp.__Usual[] Xs$Args)() : C:XSharpKassePPKasseGastroStart.prg : 386
static Int32 PPKasseGastro.Exe.Functions.Start()() : C:XSharpKassePPKasseGastroStart.prg : 13
None of the lines in the callstack seem to have anything to do with the callback function or the export
Chris, I can produce a sample but you can't run it without a TSE.
Removing static modifier didn't work.
Unfortunately, changing PTR to intPtr didn't work either.
The debugger reports:
System.Reflection.TargetInvocationException
Ein Aufrufziel hat einen Ausnahmefehler verursacht.
Callstack :
CCTouchpad.Boolean CCTouchpad.Klick(System.Int32 x, System.Int32 y)() : C:XSharpKassePPKasseSharePPKasseShareCCTouchpad.prg : 1169
CCTouchpad.__Usual CCTouchpad.Dispatch(XSharp.__Usual[] Xs$Args)() : C:XSharpKassePPKasseSharePPKasseShareCCTouchpad.prg : 699
XAPP.__Usual XAPP.Start(XSharp.__Usual[] Xs$Args)() : C:XSharpKassePPKasseGastroStart.prg : 386
static Int32 PPKasseGastro.Exe.Functions.Start()() : C:XSharpKassePPKasseGastroStart.prg : 13
None of the lines in the callstack seem to have anything to do with the callback function or the export
Chris, I can produce a sample but you can't run it without a TSE.
Question about converting a function pointer to a delegate
Hi Kai,
Does your Start() function have a [STAThread] attribute? If not, please add it and see it it makes a difference.
Also what is the code around line 1169 in CCTouchpad.prg ?
Does your Start() function have a [STAThread] attribute? If not, please add it and see it it makes a difference.
Also what is the code around line 1169 in CCTouchpad.prg ?
Chris Pyrgas
XSharp Development Team
chris(at)xsharp.eu
XSharp Development Team
chris(at)xsharp.eu
Question about converting a function pointer to a delegate
Hi Chris!
To make sure that the error has nothing to do with my custom control buttons (CCTouchpad), I created a simple application with just one standard button from the toolbox which starts te export from the TSE. When I click the button, the debugger reports:
System.Reflection.TargetInvocationException
Ein Aufrufziel hat einen Ausnahmefehler verursacht.
Callstack :
DialogHauptfenster.__Usual DialogHauptfenster.Dispatch(XSharp.__Usual[] Xs$Args)() : C:XSharpKasseApplicationsTestPrgDialogHauptfenster.prg : 12
XApp.__Usual XApp.Start(XSharp.__Usual[] Xs$Args)() : C:XSharpKasseApplicationsTestPrgStart.prg : 17
static Int32 Test.Exe.Functions.Start()() : C:XSharpKasseApplicationsTestPrgStart.prg : 6
The start-function has a [STAThread]; attribute
[STAThread];
FUNCTION Start() AS INT
LOCAL oXApp AS XApp
TRY
oXApp := XApp{}
oXApp:Start()
CATCH oException AS Exception
ErrorDialog(oException)
END TRY
RETURN 0
CLASS XApp INHERIT App
METHOD Start()
LOCAL oWin AS DialogHauptfenster
oWin := DialogHauptfenster{SELF}
oWin:Show()
SELF:Quit()
RETURN SELF
END CLASS
To make sure that the error has nothing to do with my custom control buttons (CCTouchpad), I created a simple application with just one standard button from the toolbox which starts te export from the TSE. When I click the button, the debugger reports:
System.Reflection.TargetInvocationException
Ein Aufrufziel hat einen Ausnahmefehler verursacht.
Callstack :
DialogHauptfenster.__Usual DialogHauptfenster.Dispatch(XSharp.__Usual[] Xs$Args)() : C:XSharpKasseApplicationsTestPrgDialogHauptfenster.prg : 12
XApp.__Usual XApp.Start(XSharp.__Usual[] Xs$Args)() : C:XSharpKasseApplicationsTestPrgStart.prg : 17
static Int32 Test.Exe.Functions.Start()() : C:XSharpKasseApplicationsTestPrgStart.prg : 6
The start-function has a [STAThread]; attribute
[STAThread];
FUNCTION Start() AS INT
LOCAL oXApp AS XApp
TRY
oXApp := XApp{}
oXApp:Start()
CATCH oException AS Exception
ErrorDialog(oException)
END TRY
RETURN 0
CLASS XApp INHERIT App
METHOD Start()
LOCAL oWin AS DialogHauptfenster
oWin := DialogHauptfenster{SELF}
oWin:Show()
SELF:Quit()
RETURN SELF
END CLASS
Question about converting a function pointer to a delegate
Hi Kai,
I created the following in Vulcan and ported it to X# some time ago as a test and there were no errors. Maybe there is something that will help you.
I created the following in Vulcan and ported it to X# some time ago as a test and there were no errors. Maybe there is something that will help you.
Code: Select all
[DllImport("WormAPI.dll", CallingConvention:=CallingConvention.Cdecl)] FUNCTION worm_export_tar(context AS IntPtr, callback AS WormExportTarCallback, callbackData AS IntPtr) AS INT PASCAL
METHOD exportTar(callback AS WormExportTarCallback) AS VOID
LOCAL result AS INT
result := worm_export_tar(_MEMVARVO():worm_context, callback, IntPtr.Zero)
IF (result != 0)
THROW System.Exception{"Fehler beim Export: " + AllTrim(STR(result))} //springt in die nächst darübergelegene Catch-Fehler-Anzeige + RETURN
ENDIF
RETURN
EXPORT worm_context AS IntPTR //TSE Variable in übergeordneterStartklasse definiert
METHOD btnExportTAR( ) //bei click auf Export-Button
LOCAL saveFile AS SaveFileDialog
LOCAL cfileOut AS STRING
LOCAL MyExport AS WormExportTarCallback
IF !btnZugriff()
RETURN NIL
ENDIF
TRY
saveFile := SaveFileDialog{}
saveFile:FileName := "tse.tar"
saveFile:Filter := "TAR archive (*.tar)|*.tar|All files (*.*)|*.*"
IF (saveFile:ShowDialog() != DialogResult.OK)
RETURN
ENDIF
cfileOut := saveFile:FileName
stream2 := System.IO.FileStream{cfileOut,System.IO.FileMode.OpenOrCreate, System.IO.FileAccess.Write}
exportSize:=exportSize0:= myWorm:Info():tarExportSize()
exportedSize := 0
oDCProgressBar1:Range := Range{1, 100} //exportProgress.Value := 0
oDCProgressBar1:UnitSize := 10 // Setting the Unitsize
oDCProgressBar1:Position := 1 // Setting the thumb to the start of the progress bar
oDCProgressBar1:show() //exportProgress.Visible := TRUE
MyExport := WormExportTarCallback{SELF,@WormExportTarCallback()} //bei größeren Datenmengen wird ggf. WormExportTarCallback()von der LIB mehrfach gerufen
myWorm:exportTar(MyExport)
// stream2:Close()
CATCH e AS Exception
ErrorBox{ NIL, e:Message }:Show()
oDCtxtResult:TextValue := e:Message
RETURN
FINALLY
MessageBox.Show("Es wurden "+Str(exportedSize)+" Bytes exportiert.", "Export-Ergebnis:" , MessageBoxButtons.OK, MessageBoxIcon.Information)
oDCProgressBar1:Hide() // exportProgress.Visible = FALSE
END TRY
RETURN NIL
METHOD WormExportTarCallback(chunk AS IntPtr, chunkLength AS DWORD, callbackData AS IntPtr ) AS INT
//hier sollten die Daten aus dem Callback landen...
LOCAL bytes AS BYTE[]
LOCAL Len AS INT
Len := (INT)chunkLength //int Len = (int)chunkLength;
IF (exportSize < chunkLength) // IF (mTSEExportSize < chunkLength)
Len := (INT)exportSize // Len = (INT)mTSEExportSize;
ENDIF
bytes := BYTE[] {Len} // BYTE[] ARRAY = new BYTE[Len]; //chunkLength
Marshal.Copy(chunk, bytes, 0, Len) // Marshal.Copy(chunk, ARRAY, 0, Len); //(INT)chunkLength
stream2:Write(bytes, 0, Len) // mTSETarExport.Write(ARRAY, 0, Len); //System.Buffer.ByteLength(bytes)
exportedSize += (UInt64)Len //chunkLength
exportSize -= (UInt64)Len //mTSEExportSize -= (UInt64)Len //chunkLength
bytes := NULL_OBJECT
IF (exportSize == 0) // IF (mTSEExportSize == 0)
stream2:Close() // mTSETarExport.Close();
ENDIF
oDCProgressBar1:Position := (INT) (100 * exportedSize / exportSize0) //exportProgress.Value = (int) (100 * exportedSize / exportSize);
ApplicationExec( ExecWhileEvent ) //Zeit zum Balken zeichnen
RETURN 0
Question about converting a function pointer to a delegate
Hi Kai,
What's the code around line 12 of DialogHauptfenster.prg ?
What's the code around line 12 of DialogHauptfenster.prg ?
Chris Pyrgas
XSharp Development Team
chris(at)xsharp.eu
XSharp Development Team
chris(at)xsharp.eu
Question about converting a function pointer to a delegate
Chris, line 12 invokes the method ExportTar() from the code in my first post.
Here is the full code of DialogHauptfenster:
CLASS DialogHauptfenster INHERIT DialogHauptfensterAbstrakt
CONSTRUCTOR(oOwner)
SUPER(oOwner)
RETURN
METHOD ButtonTest AS VOID PASCAL
LOCAL oWormAccess AS WormAccess
LOCAL oTB AS TextBox
oWormAccess := WormAccess{"T"}
IF oWormAccess:nWormError == WORM_ERROR_NOERROR
oWormAccess:ExportTar( "c:testexport.tar") //Cris: Line 12
oWormAccess:Destroy()
oTB := TextBox{, "test", "OK"}
oTB:Show()
ELSE
oTB := TextBox{, "test", "fehler"}
oTB:Show()
ENDIF
METHOD Dispatch(oEvent)
IF oEvent:Message == WM_COMMAND
IF oEvent:wParam == IDCANCEL
SELF:Enddialog()
ENDIF
ENDIF
RETURN SUPER:Dispatch(oEvent)
END CLASS
If I remove the Dispatch-Method from the code the debugger reports:
System.Reflection.TargetInvocationException
Ein Aufrufziel hat einen Ausnahmefehler verursacht.
Callstack :
XApp.__Usual XApp.Start(XSharp.__Usual[] Xs$Args)() : C:XSharpKasseApplicationsTestPrgStart.prg : 17
static Int32 Test.Exe.Functions.Start()() : C:XSharpKasseApplicationsTestPrgStart.prg : 6
Here is the full code of DialogHauptfenster:
CLASS DialogHauptfenster INHERIT DialogHauptfensterAbstrakt
CONSTRUCTOR(oOwner)
SUPER(oOwner)
RETURN
METHOD ButtonTest AS VOID PASCAL
LOCAL oWormAccess AS WormAccess
LOCAL oTB AS TextBox
oWormAccess := WormAccess{"T"}
IF oWormAccess:nWormError == WORM_ERROR_NOERROR
oWormAccess:ExportTar( "c:testexport.tar") //Cris: Line 12
oWormAccess:Destroy()
oTB := TextBox{, "test", "OK"}
oTB:Show()
ELSE
oTB := TextBox{, "test", "fehler"}
oTB:Show()
ENDIF
METHOD Dispatch(oEvent)
IF oEvent:Message == WM_COMMAND
IF oEvent:wParam == IDCANCEL
SELF:Enddialog()
ENDIF
ENDIF
RETURN SUPER:Dispatch(oEvent)
END CLASS
If I remove the Dispatch-Method from the code the debugger reports:
System.Reflection.TargetInvocationException
Ein Aufrufziel hat einen Ausnahmefehler verursacht.
Callstack :
XApp.__Usual XApp.Start(XSharp.__Usual[] Xs$Args)() : C:XSharpKasseApplicationsTestPrgStart.prg : 17
static Int32 Test.Exe.Functions.Start()() : C:XSharpKasseApplicationsTestPrgStart.prg : 6