能否基于预定义函数类型TMyFunc声明函数doit,避免重复定义?
Great question! This is a common pain point when working with multiple DLLs that share identical interfaces—duplicating function declarations is error-prone and a maintenance nightmare. Let's break down how to solve this properly in Delphi, using your TMyFunc type to avoid redundant code.
First, let's start with a corrected version of your function type definition—don't forget the calling convention (this is critical to match how your DLLs export functions, e.g., stdcall, cdecl):
type // Match the calling convention to your DLLs' export settings! TMyFunc = function(inP: Integer): Boolean; stdcall;
Solution 1: Dynamic Loading (Recommended)
Instead of statically declaring external functions for each DLL, use a function pointer variable typed as TMyFunc. This lets you reuse the type definition across all DLLs, and you only update the type once if the interface changes.
Here's a complete implementation:
- Declare the function pointer and DLL handle variables:
var doit: TMyFunc; hActiveDLL: HMODULE; // Track the currently loaded DLL to avoid leaks
- Load the DLL and assign the function pointer at runtime:
procedure LoadTargetDLL(const DLLPath: string); begin // Clean up any previously loaded DLL first if hActiveDLL <> 0 then begin FreeLibrary(hActiveDLL); hActiveDLL := 0; @doit := nil; // Reset the function pointer to avoid invalid calls end; hActiveDLL := LoadLibrary(PChar(DLLPath)); if hActiveDLL <> 0 then begin // Fetch the exported function's address (match the exact name from the DLL) @doit := GetProcAddress(hActiveDLL, 'doit'); // Optional: Add error handling if the function isn't found if not Assigned(doit) then raise Exception.CreateFmt('Function "doit" not found in DLL: %s', [DLLPath]); end else raise Exception.CreateFmt('Failed to load DLL: %s', [DLLPath]); end;
- Use the function just like a regular declared function:
procedure TestDoit; var OperationResult: Boolean; begin if Assigned(doit) then OperationResult := doit(42); // Pass your input value here end;
Why This Works
By using a function pointer variable of type TMyFunc, you're enforcing that doit strictly adheres to the interface defined in TMyFunc. If you ever need to change the function signature (e.g., add a parameter, modify the return type), you only update the TMyFunc definition—every place using this type will either compile correctly (if updated) or throw a compile error (if not), which is exactly the safety and efficiency you want.
Solution 2: Static Loading (If You Prefer Compile-Time Binding)
If you need static linking (using external), Delphi doesn't let you directly use a function type to declare an external function. But you can centralize the function signature in an include file to avoid duplication:
- Create a
SharedFuncDecls.incfile with the shared signature:
// SharedFuncDecls.inc function doit(inP: Integer): Boolean; stdcall;
- Include this file when declaring external functions for each DLL (rename functions to avoid naming conflicts):
// For first DLL {$INCLUDE SharedFuncDecls.inc} external 'FirstLogic.dll'; // For second DLL (rename to avoid name clashes) function doit_DLL2; {$INCLUDE SharedFuncDecls.inc} external 'SecondLogic.dll';
Now, if the interface changes, you only update the .inc file, and all declarations will reflect the change immediately.
Why Your Initial Attempt Didn't Work
When you wrote function doit: TMyFunc;, you were declaring a function that returns a TMyFunc pointer, not a function that is of type TMyFunc. That's why it didn't behave as expected—you need a variable of type TMyFunc (for dynamic loading) or a centralized signature (for static loading) instead.
内容的提问来源于stack exchange,提问作者Mark Walker

