2012-02-13 16 views
6

He agregado estos dos métodos a la primera unidad de mi aplicación Delphi 5.¿Puede Delphi solo usar un .dll si es necesario?

function Inp(PortAddress: Integer): Integer; stdcall; external 'inpout32.dll' name 'Inp32'; 

procedure Output(PortAddress, Value: Integer); stdcall; external 'inpout32.dll' name 'Out32'; 

Sin embargo, no quiero tener que emitir la biblioteca inpout32 con el software a menos que explícitamente lo necesitan. Actualmente, el programa dice "No encontrado" al ejecutar a menos que estén presentes en la raíz o System32.

Los usuarios solo llamarán a estos métodos si tienen una opción específica establecida, pero esto no se recopila desde el archivo .ini hasta que se use la biblioteca inpout.

¿Hay alguna manera de usar esta biblioteca solo cuando sea necesario, como lo hacen algunos componentes, en lugar de declararla de la manera en que lo hago?

+3

Sí, se puede hacer 'carga dinámica'. Use 'LoadLibrary' y' GetProcAddress', como se explica [aquí] (http://en.wikipedia.org/wiki/Dynamic_loading#Windows). –

Respuesta

15

En las versiones Delphi anteriores a 2010, debe utilizar la carga dinámica clásica. Considere esto típica (y simple) ejemplo llamando a la función Beep de Kernel32.dll (que debe no codificar el camino en el código real, por supuesto!):

type 
    TBeepFunc = function(dwFreq: DWORD; dwDuration: DWORD): BOOL; stdcall; 

procedure TForm4.FormClick(Sender: TObject); 
var 
    lib: HMODULE; 
    prc: TBeepFunc; 
begin 

    lib := LoadLibrary('C:\WINDOWS\System32\Kernel32.dll'); 
    if lib = 0 then RaiseLastOSError; 
    try 
    @prc := GetProcAddress(lib, 'Beep'); 
    if Assigned(prc) then 
     prc(400, 2000) 
    else 
     ShowMessage('WTF? No Beep in Kernel32.dll?!'); 
    finally 
    FreeLibrary(lib); 
    end; 
end; 
+6

+1 por el mensaje !! ((: – ComputerSaysNo

+0

Gracias @Andreas esto parece la solución más fácil. RaiseLastOSError no fue reconocido en mi Delphi5 sin embargo. ¿Puedo quitar la declaración If ya que el error siempre aparecerá en el segundo mensaje "WTF?" biblioteca no cargada ?! " – notidaho

+1

@notidaho: No, si' lib = 0' no debe ingresar el bloque 'try'. Puede reemplazar' RaiseLastOSError' con cualquier código que genere excepciones, como 'raise Exception.Create (' No se pudo cargar la biblioteca. ') '. Por supuesto, también puede reemplazar la línea en la pregunta por' if lib <> 0 then', de modo que todo el 'try..finally..end' se ejecutará solo si el 'lib' es válido. Pero probablemente sea mejor mostrar un mensaje de error. –

16

Esta instalación, conocida como delay loading, se añadió en Delphi 2010.

Usando su código como un ejemplo, usted podría escribir su importación como esto:

function Inp(PortAddress: Integer): Integer; stdcall; 
    external 'inpout32.dll' name 'Inp32' delayed; 

La unión a esta función externa será realizado solo cuando la función se llama por primera vez. Si el enlace falla, se genera una excepción en el tiempo de ejecución.

Puede usar SetDliNotifyHook y SetDliFailureHook para personalizar el comportamiento de carga de demora en caso de que necesite un control aún más preciso.

Algunos artículos de blog para complementar la documentación del producto:


En las versiones anteriores de Delphi que puede utilizar LoadLibrary y GetProcAddress. O, si quieres algo un poco astuto puedo recomendar encarecidamente la clase de carga de retraso de Hallvard Vassbotn que describe in this blog article. Este código cierra toda la placa de la caldera llamando al LoadLibrary y GetProcAddress y es un poco más engorroso de usar que la nueva característica incorporada de Delphi 2010.

Utilicé con éxito la biblioteca de Hallvard durante muchos años. Una advertencia menor es que no es seguro para el hilo, por lo que si varios hilos intentan unirse a una función al mismo tiempo, el código puede fallar. Esto es bastante fácil de solucionar agregando bloqueos internos al código de Hallvard.

+0

Oh, ¿entonces no hay necesidad de 'GetProcAddress' y todo eso más? Lástima, eso fue divertido ... –

+1

@Andreas Personalmente sigo usando GetProcAddress y mi propia clase para manejar la carga de retraso, pero no, agregaron esta nueva característica en D2010. Demasiado tarde para ti, temo. –

+0

Gracias David parece una buena idea, pero ¿hay alguna forma de que pueda hacer esto en Delphi5? – notidaho

Cuestiones relacionadas