DLL-библиотека Delphi стороннего производителя

Я исчерпал свои возможности поиска в Google...

Мы используем System Center Orchestrator для автоматизации создания пользователей в нескольких системах. У нас есть стороннее приложение для точек продаж, которое хранит пароли пользователей в БД в зашифрованном формате, который их приложение может прочитать. Для наших автоматических вставок в пользовательскую БД мы должны иметь возможность вставить зашифрованный пароль для распознавания приложения.

Они не предоставили бы нам методологию шифрования, которой они следовали, но создали библиотеку DLL для использования в Delphi. Он принимает строку, переданную в оболочке 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 ответа

Решение

Функция, предоставленная этими разработчиками, не может быть надежно вызвана. И, конечно, он не может быть вызван из 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

Объявить функцию как

    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, вы получите XML-строку в outputString, проанализируете ее и найдете свой пароль в теге.

Другие вопросы по тегам