Delphi 5 可以使用 C# .Net 库吗?

Can Delphi 5 use a C# .Net Library?

我正在更新遗留 Delphi 5 应用程序(我们有代码),该应用程序通过使用用户提供的凭据进行绑定来针对 LDAP/AD 进行身份验证。但是,我们使用的库无法通过端口 636 或 3269 绑定 LDAPS (LDAP/SSL)。

我看到在 C# 中针对 LDAP/AD 进行身份验证可以像这样简单:

PrincipalContext pc = new PrincipalContext(ContextType.Domain, "testnet.testad.org:636", "dc=testnet,dc=testad,dc=org");
bool validated = pc.ValidateCredentials(username, password, ContextOptions.Negotiate);

我正在考虑将必要的调用包装在一个 .DLL 中,然后从 Delphi 应用程序中调用该调用。但是,我假设存在 'gotchas' 的雷区会阻止它变得如此简单。

使用UnmanagedExports这真的很简单。

您从功能的界面开始,如下所示:

type
  IManagedInterface = interface
    ['{9F5A2431-5559-410C-BAB4-5144CA8C0B7B}']
    function CheckCredentials(AContextName, AContainerName, AUserName,
      APassword: WideString): integer; safecall;
  end;

这可能不是参数类型的最佳选择,因为您不能使用 NULL 来调用用户名和密码,并且您可能希望将其他参数(如上下文类型)传递为好吧,但你明白了。

然后在 VS 2019 中创建一个新的 Class 库 (.NET Framework) 项目,将构建目标设置为 x86(使其与 Delphi 5 兼容)。您为 UnmanagedExports 添加 NuGet 包。

在该项目中添加相同的界面:

[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);
}

和实现该接口的 class:

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));
    }
}

最后,您从创建 returns 这个 class:

的 DLL 中导出一个函数
static class Exports
{
    [DllExport]
    public static void CreateTheInterface(
        [MarshalAs(UnmanagedType.Interface)] out IManagedInterface instance)
    {
        instance = new Class1();
    }
}

现在您可以使用 Delphi 中的那个 DLL(为了保持简短,库不是按需加载的,我会在生产代码中这样做):

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.

所以,没有'gotchas'的雷区,真的很简单