Call .NET 8.0 DLL from Clarion 10 application

Hello,

I have been using a .NET Framework DLL in our Clarion application for many years without issues. We were recently forced to upgrade our library to .NET 8.0 due to a dependency update. Since the update, the Clarion app instantly crashes instantly when calling any of the exported DLL functions.

To simplify testing and remove variables, I have created a test app in Clarion 10 (using the Win32 EXE template) and a test library using the “CLR Class Library (.NET)” template in Visual Studio 2022.

I have tested linking to the library both statically (using both the built-in LibMaker.exe and LibMakerPlus from https://github.com/CarlTBarnes/LibMakerPlus) and also dynamically using the LoadLibrary() APIs without success. Note that when I create the same library from the “CLR Class Library (.NET Framework)” template in VS, both of the linking methods work without crashing.

Is there some extra configuration that I need to make in the .NET library to be compatible with Clarion?

My current library code looks like the following…

// Net.h
#pragma once

extern "C" __declspec(dllexport) int GetSeven();


// Net.cpp
#include "pch.h"
#include "Net.h"

int GetSeven()
{
	return 7;
}

I am compiling in release mode targeting x86.

My Clarion app code looks like the following…

! Main procedure
Main                 PROCEDURE                             ! Declare Procedure

  CODE                                                     ! Begin processed code
		MESSAGE(GetSeven())
		MESSAGE('Done!')  ! This never gets called because Clarion crashes on the previous line

! Global map
MODULE('Net.lib')
	GetSeven(),LONG,RAW,C
END

I have generated the LIB file using LibMaker.exe (the function shows up correctly in the preview) and added the library in the Solution Explorer.

I have been stuck on this for weeks, so any help would be greatly appreciated!

Thank you,
Brandon

There’s a Nuget package called Unmanaged Exports that I’ve used for a long time to call . NET methods. There’s a ClarionMag article that covers its use.

https://clarionmag.jira.com/wiki/spaces/clarion/pages/400219/Clarion+and+C+.NET+Interop+without+COM

Maybe that will help.

I recently had to swap the UnmanagedExport for the DllExport package, because at some point of version of .net, it stopped exporting methods. Also, the DllExport is on github and seems actively supported.

2 Likes

Thank you for the suggestions. I attempted to create a brand new C# Class Library (using .NET 8.0 framework).

The UnmanagedExports package gives the following warning when installed…

Severity	Code	Description	Project	File	Line	Suppression State	Details
Warning	NU1701	Package 'UnmanagedExports 1.2.7' was restored using '.NETFramework,Version=v4.6.1, .NETFramework,Version=v4.6.2, .NETFramework,Version=v4.7, .NETFramework,Version=v4.7.1, .NETFramework,Version=v4.7.2, .NETFramework,Version=v4.8, .NETFramework,Version=v4.8.1' instead of the project target framework 'net8.0'. This package may not be fully compatible with your project.

I am struggling with the DllExport package. Do you remember which settings you configured in the GUI that pops up right after installation?

I am not using UnmanagedExports, but the DllExport package.
I found the DllExport.bat somewhere and put that in my project directory.
The most important thing is the x86 setting. I have used different values for namespace, I have had trouble with the one “System.Runtime.Interop.Services”, but not with the ones with projectname.

@Brandon - Seems we’re in the same boat - I’ve been succesfully exporting my DotNet 8 Library using DNNE - I’ve created a fork of it which also generates the necessary files to use the exported methods in a class inside Clarion itself - I also got it working to generate the LIB - so all in all it generates the .CLW, .INC and .LIB needed to consume the library - my fork is far from complete - currently working on a rewrite to make it easier to extend - if interrested though, I can give a small headsup on how to use it - but you’ll have to compile it locally and use a local Nuget Source to use it

1 Like

Also keep a eye out for Native AOT from Microsoft - they are working on support for x86 (there is basic support now it seems) - but when Clarion 12 lands (with x64 support) you can just use Native AOT instead

Just to clarify your roadmap; 64bit support has been discussed but is -not- on the roadmap for Clarion 12 . It is slated for some later version.

Hi Bruce - The graphic on this post seems to state otherwise.

Oh. My mistake. It says “Clarion 2024”.

Will any of us be alive when Clarion 2024 is released? :wink:

1 Like

Newbie here, so hello to all!
I’ve been using .Net framework made DLLs in Clarion solution for a long time by utilizing UnmanagedExports by Robert Giesecke.
Now I have to upgrade my .Net framework DLL to .Net 8. So I stumbled upon this thread and tried to solve my problem but to no avail. (DllExport3F and DNNE)
Does anyone know if there is any example avilable that includes both Clarion and C# code on how to make this connection working? Is someone willing to make one? Thank you in advance!

The package that @Bjarne_Havnen mentioned in this thread looks promising. See his comments.

Here is a link to the package. GitHub - 3F/DllExport: .NET DllExport with .NET Core support (aka 3F/DllExport aka DllExport.bat)

I tried it but my Clarion exe just crashes. So I am apparently doing something wrong.

I couldn’t get DllExport working either. I have also played around with DNNE and the fork that @ThaDaSoft developed. I was able to get that working but couldn’t get it to cooperate with some of the libraries I was using.

Here are my notes for getting raw DNNE working (these steps seemed to work good without external libraries)…

- Create new C# Class Library project
- Install DNNE NuGet package
- Add x86 configuration
- Edit project file
    <PropertyGroup>
      <RuntimeIdentifier>win-x86</RuntimeIdentifier>
      <DnneSelfContained_Experimental>true</DnneSelfContained_Experimental>
    </PropertyGroup>
    
      <SelfContained>false</SelfContained>
      <PublishTrimmed>false</PublishTrimmed>

(I think the properties in the section were required and I was trying to play with the other settings to lower the amount of output files [which I didn’t have a whole lot of success with].)

NativeAOT definitely seems like the most reliable method. I was able to get some tests working with some of the more complex libraries enabled. The 32-bit support is added in .NET 9.0 which is currently in release candidate stage. I believe the final release is targeting a Microsoft conference later this month? If you can hold off until then, I was planning on sharing some test code and notes at that time. My attention is currently shifted onto other projects until the final release is out.

1 Like

I currently switched from DNNE to NativeAOT, it’s luckily working without issues, except one thing I am trying to diagnose which is when I call my dll from “Program Setup” embed (so not the main Window/Frame), when I close the application it seems to crash and log to the event log noting that a file cannot be found.

Aside from that, I am trying to figure out how Clarion Templates are made for easier distribution of my library

1 Like

I must be doing something wrong.
This is c# project file:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
    <Platforms>x86</Platforms>
    <RuntimeIdentifier>win-x86</RuntimeIdentifier>
    <DnneSelfContained_Experimental>true</DnneSelfContained_Experimental>
    <SelfContained>false</SelfContained>
    <PublishTrimmed>false</PublishTrimmed>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="DNNE" Version="2.0.7" />
  </ItemGroup>

</Project>

This is class:

using System.Runtime.InteropServices;

namespace ProboDllExport;

public class Class1
{
    [UnmanagedCallersOnly(CallConvs = new[] { typeof(System.Runtime.CompilerServices.CallConvCdecl) })]
    public static int ExportedFunc (int args) 
    {  
        return 0; 
    }
}

This is Clarion inside global maps (I made lib with LibMaker.exe):

     module('ProboDllExportNE.lib')
ExportedFunc           procedure(long),long,pascal,raw,dll(1),name('ExportedFunc')
     end 

And this crashes exe:

LongParam = 2
LongResult = ExportedFunc(LongParam)

Same scenario worked with UnmanagedExports by Robert Giesecke.

What am I missing here?

Shouldn’t CallConvCdecl match C convention, not PASCAL?

I tried c and pascal, Cdecl and Stdcall, but result is the same. Only difference is that with Stdcall exported function is stated as _ExportedFunc@4

I think this test worked…

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
    <Platforms>x86</Platforms>
	<!--<PlatformTarget>x86</PlatformTarget>-->
	<RuntimeIdentifier>win-x86</RuntimeIdentifier>
  </PropertyGroup>

  <PropertyGroup Label="DNNE">
    <DnneSelfContained_Experimental>true</DnneSelfContained_Experimental>
    <!--<DnneAddGeneratedBinaryToProject>true</DnneAddGeneratedBinaryToProject>-->
    <!--<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>-->
    <!--<InvariantGlobalization>true</InvariantGlobalization>-->
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="DNNE" Version="2.0.6" />
  </ItemGroup>

</Project>
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

namespace TestDnneC
{
    public class Exports
    {
        [UnmanagedCallersOnly(CallConvs = [typeof(CallConvCdecl)], EntryPoint = "FancyName")]
        public static int MyExport(int a)
        {
            return a;
        }
    }
}
MODULE('TestDnneC.lib')
	FancyName(LONG),LONG,RAW,C
END

The additional steps I had to do was to create the .lib file using LibMaker.exe and add the library reference in the Solution Explorer. Unfortunately, I didn’t save some of the code from the test and these code snippets are from comments I had left lying around. Hopefully this will get you on the right path.

1 Like