Reputation: 119
I apologise if this is a trivial question, but I have searched as much as I can and cannot find any solution.
I have a Delphi/FMX application that creates a DLL for Win32 and a DYLIB for macOS (High Sierra), 32 bits.
In a unit, I was simply using GetModuleName(hInstance)
to get the name of the module that used the unit, and that works fine in Win32 and Win64. For example, if the main program is using the unit it will return the main program name. If however, a DLL used by the main program uses the unit, it will return the DLL name. I'm using this to create separate log files for the main program and any DLLs it calls and using the name retuned in the log file name.
The code that works (which is in a unit used by a DYLIB (OSX)/DLL (Win32) created with FMX) in Windows is:
sModuleName := TPath.GetFileNameWithoutExtension(GetModuleName(hInstance));
GetModulename
is in the System.SysUtils unit and AFAIK there is no conditional define for Windows/OSX etc. My assumption, obviously wrong, is that it should work when built for OSX. It doesn't, it hangs on that line with no error, just an '(Not Responding)' in FORCE QUIT window. I have tried this on both a macOS VM and on a hard macOS system with the same result.
Is there something (else) I need to do to get GetModuleName working with OSX?
and/or
Is there something (similar) that will retrieve the module name if I build for OSX?
Upvotes: 0
Views: 473
Reputation: 4730
GetModuleName
also exists on MacOS. I think your problem is not that the function doesn't exist, but that you should not call it from within the initialization
section. In general you must avoid calling into other dlls/dylibs in the initialization section so that you don't trigger the loader lock.
Upvotes: 0
Reputation: 119
As noted, the problem is really that the log file Unit has no idea where it was referenced from, but the Unit/Module that did the referencing knows it's own name?
So the workaround (and it is a workaround) was to move the actual call to the function that does the log file creation out of the Initialze Block in the log file unit (ie. putting it in a function called LogFileSetup with a single parameter: the calling unit name) and put a call to that function at the beginning of the calling unit's Initialize Block. So in the calling unit, for example:
initialization
// Setup the log file
if not(LogFileSetup('MyModuleName')) then
ShowMessage('Logfile setup error');
And the function in the LogFile unit (for reference I'm using Log4Pascal which is free, simple and works):
function LogFileSetup(sModuleName : string): Boolean;
begin
try
Result := True;
{$IFDEF MSWINDOWS}
sLogFolder := IncludeTrailingPathDelimiter(ExtractFilePath(ParamStr(0))) + 'logs';
{$ENDIF MSWINDOWS}
{$IFDEF MACOS}
sLogFolder := IncludeTrailingPathDelimiter(GetHomePath) + 'Library/Logs/MyAppName';
{$ENDIF MACOS}
if not(DirectoryExists(sLogFolder)) then
ForceDirectories(sLogFolder);
sLogFile := IncludeTrailingPathDelimiter(sLogFolder) + sModuleName + '_' + FormatDateTime('YYYYMMDD', now) + '_' + FormatDateTime('hhmmsszzz',now) + '.log';
EMPLogger := TLogger.Create(sLogFile);
EMPLogger.getLogLevel;
// INFO log message
EMPLogger.Info('[Log4Pascal] Logging commenced');
except
Result := False;
end;
end;
Of course, if anyone has an answer to the question: Is there an OSX equivalent to:
GetModuleName(hInstance)
That would be excellent.
Upvotes: 0