$theTitle=wp_title(" - ", false); if($theTitle != "") { ?>
About Virtualization, VDI, SBC, Application Compatibility and anything else I feel like
A few days ago I wrote about Using Windows Dialogs in your own programs, wouldn’t it be nice to be able to use Windows Resource Strings for the same reasons?
Loading a resource string is not difficult, let’s look at some examples:
1 2 3 4 5 6 7 8 9 10 11 12 | function LoadResourceString(const DllName: String; ResourceId: Integer): String; var hDLL: THandle; Buffer: array[0..MAX_PATH] of Char; begin hDLL := LoadLibrary(PChar(DllName)); if hDLL = 0 then Exit; if LoadString(hDll, ResourceId, Buffer, Length(Buffer)) > 0 then Result := Buffer; end; |
This uses the LoadString api to load a Resource String from an Executable or Dll by it’s resource Id. An Example might call might be:
1 | LoadResourceString('dsadmin.dll', 226) |
This loads the string with ResourceId 226 from dsadmin.dll(.mui):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | STRINGTABLE LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US { 224, "Windows cannot complete the password change for %2 because:\n%1" 225, "Windows cannot access object %2 because:\n%1The object may have been deleted by another administrator in this enterprise." 226, "The New and Confirm passwords must match. Please re-type them." 228, "Object %2 has been disabled." 229, "Windows cannot disable object %2 because:\n%1" 231, "Object %2 has been enabled." 232, "Windows cannot enable object %2 because:\n%1" 233, "Create a new object..." 237, "Mo&ve...\nMoves the selected object" 238, "The password for %2 cannot be set due to insufficient privileges. Windows will attempt to disable this account. If this attempt fails, the account will become a security risk. Contact an administrator as soon as possible to repair this. Before this user can log on, the password should be set, and the account must be enabled." } |
As you can see in this example, some resource strings have identifiers such as %1 and %2 which are used in the FormatMessage Api. How can we use that from Delphi?
I wrote a very simple wrapper for it:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | function FormatMsg(const Source: String; const Args: array of const): String; var i: Integer; ArgArray: array of Pointer; Buffer: PChar; begin for i := Low(Args) to High(Args) do begin SetLength(ArgArray, i+1); case Args[i].VType of vtExtended:; // not supported, should raise Exception else ArgArray[i] := Args[i].VPointer; end; end; if FormatMessage(FORMAT_MESSAGE_FROM_STRING or FORMAT_MESSAGE_ALLOCATE_BUFFER or FORMAT_MESSAGE_ARGUMENT_ARRAY, PChar(Source), 0, 0, @Buffer, 0, @ArgArray[0]) > 0 then begin Result := Buffer; // replace \n (linefeed) with #13#10 Result := StringReplace(Result, '\n', #13#10, [rfReplaceAll]); LocalFree(DWORD(Buffer)); end else begin SetLength(Result, 0); end; end; |
And here is a usage example:
1 2 3 | Memo1.Lines.Add (FormatMsg( 'Windows cannot complete the password change for %2 because:\n%1', ['the password doesn''t meet complexity requirements', 'John Doe'])); |
The Result of this is:
Windows cannot complete the password change for John Doe because:
the password doesn’t meet complexity requirements
Leave a reply