0

We have a 32-bit application written in Delphi. We also have a Windows Forms Class Library written in C#. To export the library functions we use NuGet DllExport package. Everything works fine with .Net Framework 4.8.1 library. But in .Net 8 library an exception occurs if function shows form.

To localize the problem, we created test projects.

Delphi code:

unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm1 = class(TForm) Button1: TButton; Button2: TButton; procedure Button1Click(Sender: TObject); procedure Button2Click(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form1: TForm1; function AddOne(n: integer): integer; cdecl; external 'DllExportTest.dll'; cdecl; function AddOneAndShowMessage(n: integer): integer; cdecl; external 'DllExportTest.dll'; cdecl; implementation {$R *.dfm} procedure TForm1.Button1Click(Sender: TObject); var n: integer; begin n := AddOne(1); ShowMessage(inttostr(n)); end; procedure TForm1.Button2Click(Sender: TObject); var n: integer; begin n := AddOneAndShowMessage(1); ShowMessage(inttostr(n)); end; end. 

.Net Framework 4.8.1 Class Library code

using System.Runtime.InteropServices; using System.Windows.Forms; namespace DllExportTest { public class Class1 { [DllExport(CallingConvention = CallingConvention.Cdecl)] public static int AddOne(int n) { return n + 1; } [DllExport(CallingConvention = CallingConvention.Cdecl)] public static int AddOneAndShowMessage(int n) { MessageBox.Show("AddOneAndShowMessage function called"); return n + 1; } } } 

We have created a Class Library (.Net Framework) and added a dependency on System.Windows.Forms. Then we installed the NuGet package DllExport. DllExport settings for this project:

 <DllExportIdent>5F111A67-5D02-4672-9983-C3F0762C3FE6</DllExportIdent> <DllExportMetaLibName>DllExport.dll</DllExportMetaLibName> <DllExportNamespace>DllExportTest</DllExportNamespace> <DllExportDDNSCecil>true</DllExportDDNSCecil> <DllExportSkipOnAnyCpu>false</DllExportSkipOnAnyCpu> <DllExportPlatform>Auto</DllExportPlatform> <DllExportOrdinalsBase>1</DllExportOrdinalsBase> <DllExportGenExpLib>false</DllExportGenExpLib> <DllExportOurILAsm>true</DllExportOurILAsm> <DllExportSysObjRebase>false</DllExportSysObjRebase> <DllExportLeaveIntermediateFiles>false</DllExportLeaveIntermediateFiles> <DllExportTimeout>30000</DllExportTimeout> <DllExportPeCheck>6</DllExportPeCheck> <DllExportPatches>0</DllExportPatches> <DllExportRefreshObj>false</DllExportRefreshObj> <DllExportILAsmExternAsm /> <DllExportILAsmTypeRef /> <DllExportTypeRefOptions>0</DllExportTypeRefOptions> <DllExportRefPackages /> <DllExportPreProcType>0</DllExportPreProcType> <DllExportPostProcType>0</DllExportPostProcType> <DllExportDir>$(MSBuildProjectDirectory)\..\</DllExportDir> 

Both functions (AddOn and AddOneAndShowMessage) work fine. When calling AddOneAndShowMessage, a MessageBox appears with a message "AddOneAndShowMessage function called".

We then created a .Net8 Windows Forms Class Library with the same functions. DllExport settings for this project:

 <DllExportIdent>6E6B4E9D-2474-49CD-B8F9-5BA6C3B7AD59</DllExportIdent> <DllExportMetaLibName>DllExport.dll</DllExportMetaLibName> <DllExportNamespace>DllExportTest</DllExportNamespace> <DllExportDDNSCecil>true</DllExportDDNSCecil> <DllExportSkipOnAnyCpu>false</DllExportSkipOnAnyCpu> <DllExportPlatform>Auto</DllExportPlatform> <DllExportOrdinalsBase>1</DllExportOrdinalsBase> <DllExportGenExpLib>false</DllExportGenExpLib> <DllExportOurILAsm>true</DllExportOurILAsm> <DllExportSysObjRebase>true</DllExportSysObjRebase> <DllExportLeaveIntermediateFiles>false</DllExportLeaveIntermediateFiles> <DllExportTimeout>30000</DllExportTimeout> <DllExportPeCheck>6</DllExportPeCheck> <DllExportPatches>0</DllExportPatches> <DllExportRefreshObj>false</DllExportRefreshObj> <DllExportILAsmExternAsm /> <DllExportILAsmTypeRef /> <DllExportTypeRefOptions>0</DllExportTypeRefOptions> <DllExportRefPackages /> <DllExportPreProcType>0</DllExportPreProcType> <DllExportPostProcType>0</DllExportPostProcType> <DllExportDir>$(MSBuildProjectDirectory)\..\</DllExportDir> 

The AddOne function works. But calling the AddOneAndShowMessage function raises the еxternal exception E0434352.

Logging has shown that the exception occurs before entering the function.

If the "DllExportSysObjRebase" parameter set to false, the "AddOne" function also raises external exception E0434352.

Question: how to use DllExport correctly with .NET8.0 Windows Forms Class Library, if there is a function showing a form?

Development tools used: Embarcadero® Delphi® 2010 Microsoft Visual Studio Community 2022

4
  • Tested from C++ (LoadLibrary / GetProcAddress), works using the 1.8.0 library, with the Rebase System Object option, <DllExportOurILAsm>false</DllExportOurILAsm>, <DllExportSysObjRebase>true</DllExportSysObjRebase>, <DllExportRefreshObj>true</DllExportRefreshObj>, the other options are the same -- As a note, I used __stdcall Commented Apr 15 at 13:23
  • Thanks for the reply! Unfortunately, it doesn't work with these settings either. If I set <DllExportOurILAsm>false</DllExportOurILAsm>, even the AddOne function (without MessageBox) stops working. I tried testing from C++, but ieverything is the same. However, when testing, I saw more details about the error. Unhandled exception at 0x7592B5E2 (KernelBase.dll) in DesktopApp.exe: 0xE0434352 (parameters: 0x80131522, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x5F9B0000). As I understand, error 0x80131522 indicates that some module could not be loaded. Commented Apr 16 at 9:12
  • I can confirm that <DllExportOurILAsm> is set to false. But I don't really think that it matters. As mentioned, I used __stdcall and I haven't tested __cdecl, but what matters most - and of course I forgot to say it, probably because it felt obvious - in the pre-processing tab I've selected ILMerge. Without that, it doesn't work (generates the same exception you've described) Commented Apr 16 at 21:49
  • Thank you so much for your help! Indeed the ILMerge parameter should be selected. I am new to using DllExport, so I didn't know that. Now my .Net8 library can show forms. Commented Apr 17 at 8:34

1 Answer 1

0

The issue has been tested with the DllExport library v. 1.8.0.

The reported exception E0434352 is caused by missing reference modules of the generated assembly (targeting .NET 9.0 in this test, it's the same targeting .NET 8, of course).
This can be solved by instructing the DllExport configuration applet to use the ILMerge package to pack the final assembly.
ILMerge is added to the C# Project as a <PackageReference> in the Library's Project file.

ILMerge makes sure that the entry point of the target assembly is the same as the original.

NOTE: Select the Target Platform, x86 or x64, explicitly in the C# Project. With both the Debug and Release profiles.


These screenshots show what options has been selected (nothing else was changed):

Options 1:
DllExport Options Screenshot 1

Option 2:
DllExport Options Screenshot 2

Resulting in these settings in the Project file (the meaningful ones):

<DllExportDDNSCecil>false</DllExportDDNSCecil> <PlatformTarget>x64</PlatformTarget> <DllExportOrdinalsBase>1</DllExportOrdinalsBase> <DllExportGenExpLib>false</DllExportGenExpLib> <DllExportOurILAsm>false</DllExportOurILAsm> <DllExportSysObjRebase>true</DllExportSysObjRebase> <DllExportLeaveIntermediateFiles>false</DllExportLeaveIntermediateFiles> <DllExportPeCheck>6</DllExportPeCheck> <DllExportPatches>0</DllExportPatches> <DllExportRefreshObj>true</DllExportRefreshObj> <DllExportTypeRefOptions>0</DllExportTypeRefOptions> <DllExportPreProcType>1</DllExportPreProcType> <DllExportPostProcType>0</DllExportPostProcType> 

The simple C# test class Library:

using System.Windows.Forms; using System.Runtime.InteropServices; namespace DllExportTest { public static class DllExportDemo { [DllExport(CallingConvention = CallingConvention.StdCall)] public static int AddOne(int n) { return ++n; } [DllExport(CallingConvention = CallingConvention.StdCall)] public static int AddOneAndShowMessage(int n) { int nres = ++n; MessageBox.Show("AddOneAndShowMessage function called\r\nResult is:" + nres); return nres; } } } 

Tested from a C++ Console app:

#include "stdafx.h" #include <iostream> int main() { typedef int(__stdcall* AddOne)(int n); typedef int(__stdcall* AddOneAndShowMessage)(int n); const wchar_t* dllPath = L"The:\\Full\\DLL\\Path\\someLibrary.dll"; HMODULE lib = LoadLibrary(dllPath); if (lib) { auto pAddOne = (AddOne)GetProcAddress(lib, "AddOne"); int res1 = pAddOne(10); std::cout << res1; auto pAddOneAndShowMessage = (AddOneAndShowMessage)GetProcAddress(lib, "AddOneAndShowMessage"); int res2 = pAddOneAndShowMessage(10); std::cout << res2; } } 
Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.