【问题标题】:3rd Party Delphi DLL Consumption第 3 方 Delphi DLL 消耗
【发布时间】:2014-03-31 05:26:52
【问题描述】:

我已经用尽了我的谷歌搜索选项...

我们正在使用 System Center Orchestrator 在多个系统中自动创建用户。我们有一个第三方销售点应用程序,它以他们的应用程序可以读取的加密格式将用户密码存储在数据库中。为了自动插入用户数据库,我们需要能够插入加密密码以供应用程序识别。

他们不会向我们提供他们遵循的加密方法,而是创建了一个 DLL 供我们使用,用 Delphi 编写。它接受一个在 XML 包装器中传递的字符串,然后返回一个带有加密密码字符串的 XML 响应。

从 System Center Orchestrator 的角度来看,使用此 DLL 的最佳方式是什么,请记住我自己或实施此 DLL 的系统工程师以前从未做过类似的事情。

非常感谢任何建议。


编辑

一个字符串将被传递给包含以下格式的 XML 的可执行文件

<passwordEncryptionRequest>
<passwordIn>?</passwordIn>
<connectionDetails>
<serverName>?</serverName>
<serverInstance>?</serverInstance>
<userName>?</userName>
<connectionPassword>?</connectionPassword>
</connectionDetails>
</passwordEncryptionRequest>

将从包含以下格式的 XML 的可执行文件中返回一个字符串

<passwordEncryptionResponse> 
<passwordOut>?</passwordOut>
<passwordEncryptionErrorResponse>
<errorDescription>?</errorDescription>
</passwordEncryptionErrorResponse>
</passwordEncryptionResponse>

供应商回复我并提供了一些示例代码。

函数声明是(Delphi):

function EncryptPassword(inputString: PWideChar; var outputString: PWideChar): wordbool; export; stdCall;

使用示例(c#):

[DllImport("PasswordEncrypt.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode)]
private static extern bool EncryptPassword(string inputString, ref string outputString);

public FormTestEncryption()
{
    InitializeComponent();
}

private void buttonTest_Click(object sender, EventArgs e)
{

    string outputString = string.Empty;
    string inputString = string.Format(
         "<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
         "<passwordEncryptionRequest>" +
             "<passwordIn>{0}</passwordIn>" +
             "<connectionDetails>" +
                 "<serverName>{1}</serverName>" +
                 "<serverInstance>{2}</serverInstance>" +
                 "<userName>{3}</userName>" +
                 "<connectionPassword>{4}</connectionPassword>" +
             "</connectionDetails>" +
         "</passwordEncryptionRequest>", 
    textPassword.Text, textServer.Text, textInstance.Text, textDBUser.Text, textDBPassword.Text);

    textOutput.Clear();

    bool result = EncryptPassword(inputString, ref outputString);

    textOutput.Text = outputString;
}

编辑 2:在实现了建议的定义和调用之后,我实际上得到了一个返回字符串,但是只有当我启用本机代码调试并继续通过两个断点时。堆栈跟踪是;

ntdll.dll!_RtlReportCriticalFailure@8() Unknown
ntdll.dll!_RtlpReportHeapFailure@4()    Unknown
ntdll.dll!_RtlpLogHeapFailure@24()  Unknown
ntdll.dll!_RtlFreeHeap@12() Unknown
ole32.dll!76f96e6a()    Unknown
[Frames below may be incorrect and/or missing, no symbols loaded for ole32.dll] 
[External Code] 
WindowsFormsApplication2.exe!WindowsFormsApplication2.Form1.button1_Click(object sender, System.EventArgs e) Line 52    C#
[External Code] 
WindowsFormsApplication2.exe!WindowsFormsApplication2.Program.Main() Line 20    C#
[External Code] 

看到它现在实际上正确地实现了第 3 方 dll(我检查了返回的字符串并且很好),我已将其标记为已回答。我现在会努力解决这些其他问题:)

感谢大家的意见,感谢您的帮助。

问候,丹

【问题讨论】:

  • 您没有提供有关他们提供给您的 DLL、XML 包装器或它返回的 XML 响应的信息。我们应该如何提供帮助?调用他们提供的 DLL 的已发布 API 是什么? (DLL 的函数定义,通常在 C 中。它通常在 C 头文件 (something.h) 中提供,但它必须至少在文档中。)请从该头文件中发布函数定义,或他们提供的文档中的文字引用。否则,这里没有足够的信息来帮助您,您可能会被转介给供应商支持。
  • 嗨,肯。根据他们提供的功能规范,XML 参数如下;一个字符串将被传递给包含以下格式的 XML 的可执行文件: ?? ???
  • 一个字符串将从包含以下格式的 XML 的可执行文件中返回。 ??
  • 我正在阅读文档的其余部分,但它非常简单,没有提供任何有关 API 的信息
  • edit 您的问题并在此处提供该信息,该信息可以正确格式化并且随时可用。很难通过评论形式中的所有混乱来理解它。谢谢。

标签: xml delphi dll pinvoke system-center


【解决方案1】:

这些开发人员提供的函数无法可靠调用。它当然不能使用您提供的代码从 C# 调用。提供给您的函数是这样声明的:

function EncryptPassword(inputString: PWideChar; 
  var outputString: PWideChar): WordBool; stdcall;

返回值确实应该是LongBool,但这并不重要。

主要问题是第二个参数。这需要 Delphi 代码分配一个字符串,并在outputString 中返回指向该字符串的指针。调用代码无法解除分配该字符串。可以调用该函数的 C# 代码如下所示:

[DllImport("PasswordEncrypt.dll", CharSet = CharSet.Unicode)]
private static extern bool EncryptPassword(string inputString, 
    out IntPtr outputString);

你可以这样称呼它:

IntPtr outputStringPtr;
if (!EncryptPassword(inputString, out outputStringPtr))
    // handle error
string outputString = Marshal.PtrToStringUni(outputStringPtr);

这使得outputStringPtr 仍然分配的内存无法让您解除分配。

当然,即使这样也假设 Delphi 开发人员分配内存的方式比对 EncryptPassword 的调用更持久。他们很可能像这样实现EncryptPassword

function EncryptPassword(inputString: PWideChar; 
  var outputString: PWideChar): WordBool; stdcall;
var
  output: UnicodeString;
begin
  output := InternalEncryptPassword(string(intputString));
  outputString := PWideChar(output);
  Result := True;
end;

这个函数一返回就释放outputString指向的内存。

因此,底线是您提供的代码并不好。它应该是这样的:

function EncryptPassword(inputString: WideString; 
  out outputString: WideString): LongBool; stdcall;

该功能可能会这样实现:

function EncryptPassword(inputString: WideString; 
  out outputString: WideString): LongBool; stdcall;
begin
  outputString := InternalEncryptPassword(intputString);
  Result := True;
end;

在 C# 端它看起来像这样:

[DllImport("PasswordEncrypt.dll", CharSet = CharSet.Unicode)]
private static extern bool EncryptPassword(
    [MarshalAs(UnmanagedType.BStr)]
    string inputString, 
    [MarshalAs(UnmanagedType.BStr)]
    out string outputString
);

然后这样称呼它:

string outputString;
if (!EncryptPassword(inputString, out outputString))
    // handle error

【讨论】:

  • 感谢大卫的详细回复。我会按照你的建议实施,看看效果如何!在我的时区可能要到今天下午,但我会尽快提供反馈。干杯!
  • 但请记住,我的回答表明您很可能需要其他开发人员来修复他们的 Delphi 代码。
  • 该实施大部分工作。当我在调试模式下运行时,我确实得到了我想要的输出字符串。但是,在正常执行期间,我遇到了应用程序崩溃(stackhash)。我会说是 DEP 造成的,但我暂时禁用了它,但仍然出现错误。
  • 我相信 Delphi DLL 从根本上被破坏了。我不相信你能做的任何事情都可以解决它。你需要回到最初的开发者。在这里向他们展示我的答案。
【解决方案2】:

像这样声明函数

    function EncryptPassword(inputString: PWideChar; var outputString: PWideChar)
: wordbool; stdcall; external 'PasswordEncrypt.dll';

建立一个

inputstring := '<passwordEncryptionRequest>
<passwordIn>?</passwordIn>
<connectionDetails>
<serverName>?</serverName>
<serverInstance>?</serverInstance>
<userName>?</userName>
<connectionPassword>?</connectionPassword>
</connectionDetails>
</passwordEncryptionRequest>'

带有密码输入、服务器名、用户名数据

调用函数

EncryptPassword(inputString,outputString); 

如果函数返回 true,你会在 outputString 中得到一个 xml 字符串,解析它并在标签中找到你的密码

【讨论】:

  • 提问者正在尝试使用 C# 使用 Delphi DLL。即使在 Delphi 中,上面的代码也可能会失败。
猜你喜欢
  • 2010-10-21
  • 1970-01-01
  • 2012-07-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多