Use DLL comstackdo en Delphi 7 en C #

Necesito usar un DLL (Extractor de ID de hardware) hecho en Delphi 7 en mi aplicación C #.

Las funciones exportadas por esta DLL son:

Funciones exportadas:

// 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 } 

Sé (obviamente) que la cadena en Delphi no está terminada en nulo y es byte (ASCII). Pero no tengo idea de cómo asignar estas cadenas de Delphi a C #.

Gracias.

Este es un ejemplo de cómo podría declarar la función GetCPUSpeed ​​en C #:

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

Y hay otras declaraciones que podrías probar:

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

El problema viene de la forma en que diseñó sus funciones exportadas. Las DLL son (entre otras cosas) un mecanismo para proporcionar código de manera que se pueda usar desde aplicaciones (u otras DLL) escritas en diferentes lenguajes de progtwigción.

Eche un vistazo a la API de Windows, hay muchas funciones que devuelven texto. Desafortunadamente, esto se hace de muchas maneras diferentes, la API de Windows no tiene un estándar real para ello. Sin embargo, estoy bastante seguro de que no encontrará una sola función que devuelva una “cadena” (ya sea una cadena Pascal o una C (terminada en nulo)) de la forma en que lo hizo. La razón es simple: esto haría muy difícil o incluso imposible utilizar diferentes lenguajes de progtwigción para diferentes módulos. Su DLL asignará la memoria para la cadena, y una vez que la persona que llama haya terminado con la cadena, necesitará liberar la memoria. Por lo tanto, ambos módulos necesitan compartir el administrador para esta porción de memoria. ¿Cómo podría el progtwig C # usar su DLL, ya que usan administradores de memoria completamente diferentes?

La forma habitual de obtener un valor de cadena de una DLL es llamar a la función con un búfer preasignado y la longitud del búfer en los parámetros, dejar que la función llene ese búfer con el contenido de la cadena y dejar que el resultado de la función denote éxito o fracaso. Pasar un búfer de tamaño insuficiente, por ejemplo, sería una causa de falla. Las diferentes funciones de la API de Windows tratan esto de diferentes maneras, la más fácil para usted probablemente sería definir su longitud máxima de cadena con una constante, similar a MAX_PATH por ejemplo.

Para resolver su problema, debe tomar una función de la API de Windows a la que sepa cómo llamar desde C #, y que devuelva un resultado de cadena en un búfer, como ejemplo. Modele sus funciones exportadas después de este ejemplo, y debería ser fácil llamarlas desde el progtwig C #.

Editar:

Recordé que había visto una pregunta similar ( ¿Cómo importar una función desde una DLL creada en Delphi? ) Hace algún tiempo, y ahora que la busqué, encontré que también era tuya.

Luego escribió que no tiene el código fuente para esa DLL, por lo que cambiar las funciones exportadas está fuera de discusión. Lo que podría hacer es crear una DLL de envoltorio (o un objeto COM) en Delphi, llame al HardwareIDExtractor.dll original y proporcione una API sana en la parte superior. Eso le permitiría proporcionar las versiones AnsiChar y WideChar de las funciones exportadas al mismo tiempo.

Si desea reducir el desorden (dos archivos DLL necesarios en lugar de uno), también puede poner el HardwareIDExtractor.dll original como un recurso en su DLL envoltorio, como se describe en esta publicación del blog: Uso de archivos DLL almacenados como Recursos en progtwigs de Delphi

Si tiene la fuente de la dll D7, puede cambiar la función exportada para hacer que la función ShortString devuelva PChar. Puede crear nuevas funciones que llamen a las originales y realicen el encasillado: esa es la ruta más fácil. Si sigue este camino, haga lo mismo con los tipos Integer y Cardinal (conviértalos en LongInt y LongWord, respectivamente). Algún código a continuación (me imagino que magos como el señor Hausladen tienen un enfoque más elegante, pero esto funciona :-))

 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; 

Esto funciona porque internamente ShortString es una matriz [0..255] de Char. No tengo un D2009 a la mano para ver si el SizeOf (char) debe cambiarse a SizeOf (AnsiChar). PERO el principio es el mismo: asigne el PAnsiChar, lleve el puntero al primer carácter del ShortString y haga Copiar (en este caso, lo he hecho con CopyMemory) al PAnsiChar. Y poner el nulo en su lugar.

O puede ir por el camino de la mghie y crear una envoltura y hacer los moldes allí.