Using UnmanagedExports this is really quite easy.
You start with an interface for the functionality, like so:
type
IManagedInterface = interface
['{9F5A2431-5559-410C-BAB4-5144CA8C0B7B}']
function CheckCredentials(AContextName, AContainerName, AUserName,
APassword: WideString): integer; safecall;
end;
This is probably not the best choice of parameter types, as you can't call that with NULL for user and password, and you would probably want to pass the other parameters (like context type) as well, but you get the idea.
Then you create a new Class Library (.NET Framework) project in VS 2019, setting the build target to x86 (for it to be compatible with Delphi 5). You add the NuGet package for UnmanagedExports.
Within that project you add the same interface:
[ComVisible(true)]
[Guid("9F5A2431-5559-410C-BAB4-5144CA8C0B7B")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IManagedInterface
{
int CheckCredentials(
[MarshalAs(UnmanagedType.BStr)] string contextname,
[MarshalAs(UnmanagedType.BStr)] string container,
[MarshalAs(UnmanagedType.BStr)] string username,
[MarshalAs(UnmanagedType.BStr)] string password);
}
and a class which implements that interface:
public class Class1 : IManagedInterface
{
public int CheckCredentials(string contextname, string container,
string username, string password)
{
var pc = new PrincipalContext(ContextType.Domain, contextname, container);
return Convert.ToInt32(pc.ValidateCredentials(username, password,
ContextOptions.Negotiate));
}
}
Finally you export a function from the DLL that creates and returns an instance of this class:
static class Exports
{
[DllExport]
public static void CreateTheInterface(
[MarshalAs(UnmanagedType.Interface)] out IManagedInterface instance)
{
instance = new Class1();
}
}
Now you can use that DLL from Delphi (to keep this short the library is not loaded on demand, which I would do in production code):
procedure CreateTheInterface(out AInstance: IManagedInterface); stdcall;
external 'ClassLibrary1.dll';
var
Imi: IManagedInterface;
context, container, username, password: string;
begin
CreateTheInterface(Imi);
if Imi <> nil then try
context := 'testnet.testad.org:636';
container := 'dc=testnet,dc=testad,dc=org';
username := 'someguy';
password := 'password';
Writeln('call returned: ',
Imi.CheckCredentials(context, container, username, password));
except
on E: Exception do
Writeln(E.Message);
end;
Readln;
end.
So, no minefield of 'gotchas' and it is really quite easy.