Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SynTaskDialog hyperlinks support; native implementation for non-themed Windows/applications #456

Open
the-Arioch opened this issue Oct 2, 2024 · 1 comment

Comments

@the-Arioch
Copy link

clipboard-202410012027-ujqag

made a "quick dirty change" to add native (not emulation) support for hyperlink and help events

works fine in delphi 2007 / windows 10 and i think should work with other Delphi verions too, the changes are simple

SynTaskDialog-2f92598c.zip


Also, made a funny function to use native TD when visual themes are turned off in the application or in Windows. By default windows only exposes CommCtl 5.8 then and your "normal" code does not find the implementation (that IS present in process memory)

Here is a code sample using two small pieces from JCL that make native implementation found and used even when UI theming tries ot prevent it. If anyone would care implanting it into the "mainline" STD should be straight-forward (back port to stock TStringList and copy/redo the function listing the loaded DLLs into TStrings).

uses JclSysInfo, JclStringLists, StrUtils;

{$EXTERNALSYM GetModuleHandleEx}
{$EXTERNALSYM GET_MODULE_HANDLE_EX_FLAG_PIN}
{$EXTERNALSYM GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT}
{$EXTERNALSYM GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS}
function GetModuleHandleEx(dwFlags: DWORD; lpModuleName: LPCTSTR; var phModule: HMODULE): BOOL; stdcall;
  external kernel32 name 'GetModuleHandleExA';
const
  GET_MODULE_HANDLE_EX_FLAG_PIN                = $00000001;
  GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT = $00000002;
  GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS       = $00000004;

procedure SynTaskDlgFindGhostComCtl6;
var
  libs: iJclStringList;
  i: integer;
  h: HMODULE;
  f: TFileName;
begin
// <legacy app name> only works with XP Themes off, otherwise it crashes
// This makes Delphi stock TaskDialog be turned off
// This also makes GetModuleHandle(comctl32) return DLL v. 5.80 that has no TaskDlg API
// However the close look at the process memory shows there are TWO DLLs loaded at time!!!

  if Assigned(SynTaskDialog.TaskDialogIndirect) then
     Exit; // Themes were enabled and we're already provided with ComCtl 6.x

  libs := JclStringList();  // Jedi CodeLib
  LoadedModulesList(libs.GetStringsRef, GetCurrentProcessId);  // Jedi CodeLib

  // observed in Win10 that comctl 6.1 is loaded later than conctl 5.8, getting 
  // a higher base address, hence we're scanning memory backwards
  i := libs.Count - 1;
  while i >= 0 do begin
    if Assigned(SynTaskDialog.TaskDialogIndirect) then
       Exit;
    f := libs[i];
    if EndsText(comctl32, f) then begin
       h := NativeUInt(Pointer(libs.Objects[i]));
       SynTaskDialog.TaskDialogIndirect := GetProcAddress(h,'TaskDialogIndirect');

       // now we should create a warranty this DLL never gets unloaded
       if Assigned(SynTaskDialog.TaskDialogIndirect) then
          Win32Check(  GetModuleHandleEx(
              GET_MODULE_HANDLE_EX_FLAG_PIN or GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
              pointer(h), h));
          // LoadLibrary(f); pre-XP way, https://stackoverflow.com/questions/14302483/winapi-getmodulehandle-and-increment-refcount
    end;

    Dec(i);
  end;
end;
@the-Arioch
Copy link
Author

Updated flags, added new Microsoft options which your custom options erroneously overlapped with.

tdfNoSetForeground, tdfSizeToContent,
SynTaskDialog.zip

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant