4

I want to create a .NET assembly that can be accessed from unmanaged code (Delphi 5).

I have found Unmanaged Exports and followed the steps there but I am unable to successfuly compile even the basic example:

using RGiesecke.DllExport;

namespace DelphiNET
{
    public class Class1
    {
        [DllExport("add")]
        public static int Add(int left, int right)
        {
            return left + right;
        }
    }
}

DelphiNET.csproj project file:

...
<ItemGroup>
  <Compile Include="Class1.cs" />
  <Compile Include="DllExport\DllExportAttribute.cs" />
  <Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="DllExport\RGiesecke.DllExport.targets" />
...

Here is the error:

------ Build started: Project: DelphiNET, Configuration: Release Any CPU ------
c:\WINDOWS\Microsoft.NET\Framework\v3.5\Csc.exe /noconfig /nowarn:1701,1702 /errorreport:prompt /warn:4 /define:TRACE /debug:pdbonly /filealign:512 /optimize+ /out:obj\Release\DelphiNET.dll /target:library Class1.cs DllExport\DllExportAttribute.cs Properties\AssemblyInfo.cs

Compile complete -- 0 errors, 0 warnings
DelphiNET -> C:\DelphiNET\bin\Release\DelphiNET.dll
ILDasm: calling 'C:\Program Files\Microsoft SDKs\Windows\v6.0A\Bin\ildasm.exe' with /quoteallnames /nobar "/out:C:\Documents and Settings\Lukas\Local Settings\Temp\tmp29F\DelphiNET.il" "C:\DelphiNET\bin\Release\DelphiNET.dll"
C:\DelphiNET\bin\Release\DelphiNET.dll : warning EXP0009: Platform is AnyCpu, generating creating binaries for each CPU platform in a separate folder...
ILAsm: calling 'c:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\ILAsm.exe' with /nologo "/out:C:\DelphiNET\bin\Release\x86\DelphiNET.dll" "C:\Documents and Settings\Lukas\Local Settings\Temp\tmp29F\DelphiNET.x86.il" /DLL "/resource=C:\Documents and Settings\Lukas\Local Settings\Temp\tmp29F\DelphiNET.res"  /optimize  
C:\DelphiNET\DllExport\RGiesecke.DllExport.targets(8,5): error : 
C:\DelphiNET\DllExport\RGiesecke.DllExport.targets(8,5): error : Assembling 'C:\Documents and Settings\Lukas\Local Settings\Temp\tmp29F\DelphiNET.x86.il'  to DLL --> 'C:\DelphiNET\bin\Release\x86\DelphiNET.dll'
C:\DelphiNET\DllExport\RGiesecke.DllExport.targets(8,5): error : Source file is ANSI
C:\DelphiNET\DllExport\RGiesecke.DllExport.targets(8,5): error : 
C:\DelphiNET\DllExport\RGiesecke.DllExport.targets(8,5): error : Assembled method RGiesecke.DllExport.DllExportAttribute::.ctor
C:\DelphiNET\DllExport\RGiesecke.DllExport.targets(8,5): error : Assembled method RGiesecke.DllExport.DllExportAttribute::.ctor
C:\DelphiNET\DllExport\RGiesecke.DllExport.targets(8,5): error : Assembled method RGiesecke.DllExport.DllExportAttribute::.ctor
C:\DelphiNET\DllExport\RGiesecke.DllExport.targets(8,5): error : Assembled method RGiesecke.DllExport.DllExportAttribute::get_CallingConvention
C:\DelphiNET\DllExport\RGiesecke.DllExport.targets(8,5): error : Assembled method RGiesecke.DllExport.DllExportAttribute::set_CallingConvention
C:\DelphiNET\DllExport\RGiesecke.DllExport.targets(8,5): error : Assembled method RGiesecke.DllExport.DllExportAttribute::get_ExportName
C:\DelphiNET\DllExport\RGiesecke.DllExport.targets(8,5): error : Assembled method RGiesecke.DllExport.DllExportAttribute::set_ExportName
C:\DelphiNET\DllExport\RGiesecke.DllExport.targets(8,5): error : 
C:\DelphiNET\DllExport\RGiesecke.DllExport.targets(8,5): error : ***** FAILURE ***** 
C:\DelphiNET\DllExport\RGiesecke.DllExport.targets(8,5): error : 
Done building project "DelphiNET.csproj" -- FAILED.
========== Build: 0 succeeded or up-to-date, 1 failed, 0 skipped ==========

OS: WinXPSP3, Microsoft Visual C# 2008 Express Edition with SP1, .NET 3.5 SP1

Any idea what's wrong? Thanks.


Edit 23:40:

I have found the bug. It is in the name of the function - add and Add are too same. When you change one of them, it works.

Lukas Cenovsky
  • 5,476
  • 2
  • 31
  • 39

4 Answers4

8

Incidentally, I just updated the archive. You can even get it all laid out for you, when you take this instead.

It's a project template that sets everything up and should work just fine.

I did find some points in the previous version, where I made some assumptions that weren't always true. And one potential problem with my previous implementation was the /optimize switch which is used for release configurations. Sometimes ILAsm would choke on the IL in that case, I haven't seen that with the new version.

Robert Giesecke
  • 4,314
  • 21
  • 22
  • +1 Good stuff! Did you use Brian Long's articles (http://www.blong.com/Articles/DotNetInteropD8/Interop1/Win32AndDotNetInterop.htm and http://www.blong.com/Conferences/BorConUK2002/Interop1/Win32AndDotNetInterop.htm) for this? – Jeroen Wiert Pluimers Jan 11 '10 at 19:09
  • No, but I did see things like this mentioned from time to time, so I knew it's possible and tried to make it to work transparently. I used the book ".Net 2.0 IL Assembler" to make sure that I didn't end up doing any cargo cult stuff. ;-) – Robert Giesecke Jan 11 '10 at 19:26
  • This is a really nice coincidence :-) The template does not work with Visual Studion 2008 Express SP1 on WinXp SP3 but it works with VS 2010 beta 2 on Windows 7 64bit (bot run in VirtualBox) – Lukas Cenovsky Jan 11 '10 at 19:55
  • Sorry, don't know the Express editions too well. Could it be that they use other folders? Can you create a simple project and click on "File/Export template" to export the open project as a template? In which folder does it end up? – Robert Giesecke Jan 11 '10 at 19:59
  • IKVM.Reflection supports [exporting static managed methods as unmanaged DLL exports](http://weblog.ikvm.net/PermaLink.aspx?guid=aeaa0190-2b32-45e6-a249-3c3cf126372b) now; it should be possible to use it's high-level API instead of ILDasm. – user423430 Mar 26 '11 at 00:24
  • So does Mono.Cecil from what I've read a couple of months ago. However, I do use the ILDasm/IlAsm of your project's targetframework SDK for a reason: To ensure that the thing still creates perfect IL, even for newer CLR versions w/o the immediate necessity to update the tool or get an updated version as a user. Thx for the hint anyways, IKVM.Reflection does look cool but more for other projects of mine :-) – Robert Giesecke Mar 26 '11 at 07:02
  • @RobertGiesecke Any plans to update this template so it can also run on .Net Core projects? I'm pretty sure this concept should also work on .Net Core and it would be a great addition. I've been trying to figure out how to hack the dependencies so it won't require the full .Net Framework. – Doug Oct 11 '16 at 00:56
  • @Doug I would have to read up on the specs as to whether Core even supports it. My guess is, it doesn't. – Robert Giesecke Oct 11 '16 at 06:58
1

Just in case someone will meet the same problems...

Some errors on my side:

file: DllExportAttribute.cs

public CallingConvention CallingConvention { get; set; }
public string ExportName { get; set; }

file: $projectname$.csproj

<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets"/>  <!-- not working -->
<!-- change to -->
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets"/> <!-- working -->

Those are easy to fix.

Here is one pretty serious. When making implib from resulting \x86\MyDll.dll - the name of dll in lib changes to \MyDll.dll ... you can make tdump MyDll.dll and will get in exports section "\MyDll.dll" instead of "MyDll.dll".

Because of this problem dll can't be found by the soft that use resulting lib... in my situation it can be found only in c:\MyDll.dll

Solved by making "coff2omf -lib:ca MyDll.lib" on the initial lib. But before that spent a day for looking solution...

Adruin
  • 11
  • 1
0

If anyone also encounters it , i also got this error when the exported function name was "init" so changing the name fixed the problem.

So this produces such an error:

[DllExport("init")]

Ohad
  • 166
  • 1
  • 6
0

It seems that [DllExport("...)] with the export name "add" throws an error, same with "sub". Message in vs 2010 from ilasm is "assembling filename to dll ... Source file is UNICODE".

Thanks for this really great work!