第三方Delphi DLL消耗

时间:2014-03-27 23:19:02

标签: xml delphi dll pinvoke system-center

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

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

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

从System Center Orchestrator的角度来看,使用此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] 

看到它现在实际上正确地实现了第三方dll(我检查了返回的字符串并且很好),我已将此标记为已回答。我现在将尝试通过其他问题:)

感谢大家的投入,感谢您的帮助。

问候,丹

2 个答案:

答案 0 :(得分: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

答案 1 :(得分:-1)

声明函数

    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>'

使用passwordIn,serverName,userName datas

调用函数

EncryptPassword(inputString,outputString); 

如果函数返回true,你将在outputString中获取一个xml字符串,并在标记中找到你的密码