Использовать DLL, скомпилированную в Delphi 7 в C #

Мне нужно использовать DLL (Hardware ID Extractor), сделанный в Delphi 7 в моем приложении C #.

Функции, экспортируемые этой DLL:

Экспортируемые функции:

<code>// CPU
function GetCPUSpeed: Double;
function CPUFamily: ShortString; { Get cpu identifier from the windows registry }
function GetCpuTheoreticSpeed: Integer; { Get cpu speed (in MHz) }
function IsCPUIDAvailable: Boolean; Register;
function GetCPUID (CpuCore: byte): ShortString;
Function GetCPUVendor: ShortString;

// RAM
function MemoryStatus (MemType: Integer): cardinal; { in Bytes }
function MemoryStatus_MB (MemType: Integer): ShortString; { in MB }

// HDD
function GetPartitionID (Partition : PChar): ShortString; { Get the ID of the specified patition. Example of parameter: 'C:' }
function GetIDESerialNumber(DriveNumber: Byte ): PChar; { DriveNr is from 0 to 4 }
</code>

Я знаю (очевидно), что строки в Delphi не заканчиваются нулем и являются байтовыми (ASCII). Но я понятия не имею, как отобразить эти строки Delphi в C #.

Благодарю.

 Joe White18 июн. 2009 г., 22:06
@ mghie, нет, OP не так. Вы правы в отношении длинных строк, но в примере кода используются короткие строки.
 mghie18 июн. 2009 г., 17:45
Вы не правы, длинные строкиare в Delphi заканчивается на нуль, так что можно привести их к типу PChar и использовать их как строки C.
 mghie18 июн. 2009 г., 23:17
Джо, вот почему я написалlong строки. Вопрос гласит, что «я знаю (очевидно), что строка (sic) в Delphi не заканчивается нулем».
 mghie18 июн. 2009 г., 23:23
И я не буду вдаваться в то, что я буду делать с разработчиком, работающим на меня, который придумалthat API! ShortString как результат функции DLL ???

Ответы на вопрос(3)

как вы спроектировали свои экспортируемые функции. Библиотеки DLL - это (помимо прочего) механизм предоставления кода таким образом, чтобы его можно было использовать из приложений (или других библиотек DLL), написанных на разных языках программирования.

Посмотрите на Windows API, есть много функций, возвращающих текст. К сожалению, это делается по-разному, в Windows API нет реального стандарта. Однако я совершенно уверен, что вы не найдете ни одной функции, которая возвращает «строку». (или Паскаль или строка C (с нулевым символом в конце)), как вы сделали. Причина проста: это сделает очень трудным или даже невозможным использование разных языков программирования для разных модулей. Ваша DLL будет выделять память для строки, и как только вызывающая сторона завершит работу со строкой, ей потребуется освободить память. Таким образом, оба модуля должны совместно использовать менеджер для этого фрагмента памяти. Как программа C # может использовать вашу DLL, видя, что они используют совершенно разные менеджеры памяти?

Обычный способ получить строковое значение из DLL - это вызвать функцию с предварительно выделенным буфером и длиной буфера в параметрах, позволить функции заполнить этот буфер содержимым строки и позволить результату функции обозначать успех или неудачу. Например, пропуск буфера недостаточного размера будет одной из причин сбоя. Различные функции Windows API справляются с этим по-разному, проще всего для вас, вероятно, определить максимальную длину строки с помощью константы, аналогичноMAX_PATH например.

Чтобы решить вашу проблему, вы должны взять одну функцию Windows API, которую вы знаете, как вызывать из C #, и которая возвращает строковый результат в буфер, как пример. Смоделируйте ваши экспортированные функции после этого примера, и их должно быть легко вызвать из программы на C #.

Edit:

Я вспомнил, что видел похожий вопрос (Как импортировать функцию из DLL, созданной в Delphi?) Некоторое время назад, и теперь, когда я посмотрел, я обнаружил, что это тоже ваше.

Тогда вы написали, что у вас нет исходного кода для этой DLL, поэтому об изменении экспортируемых функций не может быть и речи. Что вы можете сделать, это создать DLL-оболочку (или COM-объект) в Delphi, вызвать оригиналHardwareIDExtractor.dll и обеспечить разумный API поверх этого. Это позволит вам одновременно предоставлять версии AnsiChar и WideChar экспортируемых функций.

Если вы хотите уменьшить беспорядок (необходимо две DLL вместо одной), вы также можете поставить оригиналHardwareIDExtractor.dll как ресурс в вашей DLL-оболочке, как описано в этой записи блога:Использование библиотек DLL, хранящихся в виде ресурсов в программах Delphi

 18 июн. 2009 г., 23:13
"Тогда вы писали, что у вас нет исходного кода для этой библиотеки DLL" Я не могу найти, где на пути ОП сказал, что ...... Кстати, включение DLL, хранящихся в качестве ресурсов, действительно здорово. ;-)
 18 июн. 2009 г., 23:18
В связанном предыдущем вопросе: «У меня нет исходного кода для этой библиотеки DLL, поэтому я должен адаптировать свою программу на C к этой библиотеке DLL, а не наоборот».
Решение Вопроса

class Program
{
    [DllImport("the_name_of_the_delphi_library.dll")]
    public static extern double GetCPUSpeed();

    static void Main(string[] args)
    {
        double cpuSpeed = GetCPUSpeed();
        Console.WriteLine("CPU speed: {0}", cpuSpeed);
    }
}

И есть другие объявления, которые вы можете попробовать:

[DllImport("the_name_of_the_delphi_library.dll")]
public static extern string CPUFamily();

[DllImport("the_name_of_the_delphi_library.dll")]
public static extern int GetCpuTheoreticSpeed();

[DllImport("the_name_of_the_delphi_library.dll")]
public static extern bool IsCPUIDAvailable();

[DllImport("the_name_of_the_delphi_library.dll")]
public static extern string GetCPUID(byte cpuCore);

[DllImport("the_name_of_the_delphi_library.dll")]
public static extern string GetCPUVendor();

[DllImport("the_name_of_the_delphi_library.dll")]
public static extern uint MemoryStatus(int memType);

[DllImport("the_name_of_the_delphi_library.dll")]
public static extern string MemoryStatus_MB(int memType);

[DllImport("the_name_of_the_delphi_library.dll")]
public static extern string GetPartitionID(char partition);

[DllImport("the_name_of_the_delphi_library.dll")]
public static extern string GetIDESerialNumber(byte driveNumber);

вы можете изменить экспортированную функцию, чтобы сделать Функция ShortString для возврата PChar. Вы можете создавать новые функции, которые вызывают исходные и выполняют приведение типов - это самый простой путь. Если вы следуете по этому пути, сделайте то же самое с типами Integer и Cardinal (приведите их к LongInt и LongWord соответственно). Некоторый код ниже (я думаю, что маги, такие как г-н Хаусладен, имеют более элегантный подход, но это работает :-))

var
  SInput: ShortString;
  POutput: PAnsiChar;
  Tam: Integer;
  pt: Pointer;
begin
  SInput := 'Alphabet'; //ShortString
  pt := @SInput[1]; // Points to the first char of the string;
  Tam := (Length(SInput))+1; // Size the string
  POutput := StrAlloc(tam); // Allocate;
  CopyMemory(POutput,pt,tam); // Do the copy
  POutput[tam-1] := #0; // Put the null to finish
  MessageBox(0, POutput, 'Algo', MB_ICONWARNING or MB_OK);
  StrDispose(POutput);

end;

Это работает, потому что внутренне ShortString является массивом [0..255] Char. У меня нет D2009 под рукой, чтобы увидеть, нужно ли сменить SizeOf (char) на SizeOf (AnsiChar).BUT принцип тот же: выделите PAnsiChar, получите указатель на первый символ ShortString и сделайте Copy (в этом случае я сделал с CopyMemory) PAnsiChar. И поместите нуль в его & apos; место.

Или вы можете пойтиmghie & APOS; s Пройдите и создайте обертку и сделайте слепки там.

 18 июн. 2009 г., 23:59
Некоторый код выше
 18 июн. 2009 г., 23:20
& quot; вернуть PChar & quot; - Но на какую память должен указывать PChar?

Ваш ответ на вопрос