Function FormatMessageID(Module: HModule; MsgID: Integer;
MsgData: Array Of Const): String;
Var
Buffer: PChar;
Begin
If FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER or
FORMAT_MESSAGE_FROM_HMODULE, Pointer(Module),
MsgID, 0, @Buffer, 0, Nil) = 0 then
Raise Exception.Create(SysErrorMessage(GetLastError));
Try
Buffer[Lstrlen(Buffer) - 2] := #0;
Result := Buffer;
Finally
LocalFree(Cardinal(Buffer));
End;
End;
The calling code:
Module := LoadLibraryEx(PChar(ModuleName), 0,
LOAD_LIBRARY_AS_DATAFILE);
ShowMessage(FormatMessageID(Module, 1, []));
FreeLibrary(Module);
Where ModuleName is a constant that contains the path and name of my
DLL. My DLL is a simple DPR defined as:
Library BM_Msg;
{$R Messages.res}
Begin
End.
Finally, I used the free XN Resource Editor to create the Message
Table.
Any idea? Anyone?
Chris
---
chrisatkrohndotorg
Cayman Islands
--------------------------------------------------------------
// Given a DLL/EXE with a message table, a message ID, and an array of strings
// to substitute for place holders in the message, return a formatted message.
Function FormatMessageID(Module: HModule; MsgID: Integer;
MsgData: Array Of Const): String;
Var
I: Integer; // Loop index variable
T: String; // Temp string to hold value from MsgData
Buffer: PChar; // Buffer with returned message
S: Array Of PChar; // Array of args passed to FormatMessage
Begin
// Convert the passed variable array of variants to an array of PChars
SetLength(S, High(MsgData) + 1); // Set the number of PChar strings
For I := 0 To High(MsgData) Do
Begin
// Limitation of code requires only strings be passed. Could expand the
// case statement below to handle all types of variants, but this is not
// needed for our purposes.
If Not (MsgData[I].VType In [vtString, vtAnsiString, vtWideString]) Then
Raise Exception.Create('Only string values allowed for message data.');
// Convert variants to standard strings.
Case MsgData[I].VType Of
vtString: T := MsgData[I].VString^;
vtAnsiString: T := String(MsgData[I].VAnsiString);
vtWideString: T := String(MsgData[I].VWideString);
End;
// Allocate PChar memory for string and copy string to it.
GetMem(S[I], Length(T) + 1);
StrPCopy(S[I], T);
End;
Try
// Call the Win API FormatMessage function. Parameters tell FormatMessage
// to: allocate memory to Buffer for resultant message, get the message
// template from a DLL or EXE specified by Module, and treat the arguments
// array as a standard array of 32 bit pointers. Also pass the module
// handle (typecasted as a Pointer) retrieved by a LoadLibraryEx call, the
// MsgID of the message in the message table, a 0 for the language id which
// causes FormatMessage to search automatically for the best language, the
// address of the buffer which FormatMessage will allocate memory for and
// then return the completed message, the minimum amount of memory that
// FormatMessage should allocate in Buffer (in this case 0), and finally
// the PChar array of argument strings. If successfull, it should return
// the size of the message. If it fails, it returns a size of 0.
If FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER Or
FORMAT_MESSAGE_FROM_HMODULE Or
FORMAT_MESSAGE_ARGUMENT_ARRAY, Pointer(Module),
MsgID, 0, @Buffer, 0, S) = 0 then
Raise Exception.Create(SysErrorMessage(GetLastError)); // Failed, get reason
Try // and raise except.
Buffer[Lstrlen(Buffer) - 2] := #0; // Trim off CR/LF.
Result := Buffer; // Return the results.
Finally
LocalFree(Cardinal(Buffer)); // Free the memory FormatMessage alloc.
End;
Finally
For I := 0 To High(S) Do // Free memory allocated in PChar array.
FreeMem(S[I]);
End;
End;
Chris
---
chrisatkrohndotorg
Cayman Islands
Take a look here:
<http://tinyurl.com/8m5nw>
which links to
<http://delphi.wikicities.com/wiki/Delphi_Newsgroups>