Recent

Author Topic: A button require administrator level  (Read 2077 times)

badmintonfan

  • New Member
  • *
  • Posts: 49
A button require administrator level
« on: March 28, 2024, 05:35:38 am »
Is there any way that a button require administrator level to run some codes which is assigned instead of the main program
the attached picture as a sample

Fibonacci

  • Sr. Member
  • ****
  • Posts: 453
  • Internal Error Hunter
Re: A button require administrator level
« Reply #1 on: March 28, 2024, 05:57:21 am »
To add a shield icon to the button

Code: Pascal  [Select][+][-]
  1. SendMessage(Button1.Handle, $160C{BCM_SETSHIELD}, 0, 1{1 add shield, 0 remove});

Then spawn a new process using ShellExecuteEx. Pass SHELLEXECUTEINFO struct with lpVerb set to "runas". Only new process can be elevated.

furious programming

  • Hero Member
  • *****
  • Posts: 863
Re: A button require administrator level
« Reply #2 on: April 01, 2024, 12:55:25 pm »
This is quite simple to do, but as @Fibonacci wrote, you cannot raise privileges for a current process — you have to start a new one with administrator rights. You can run another program, that is, another executable file, prepared specifically to perform this special task, but you can also launch a second instance of the same application and provide it with arguments that will allow it to perform this special task, return operation code (process exit code) and exit immediately.



In my editors, I added the ability to edit the contents of the registry. The editor itself does not require elevated privileges to run, but modifying the HKEY_LOCAL_MACHINE branch in the registry does. So when the user chooses, for example, the option to register file extensions so that files with these extensions are run by default in my editor, the editor starts itself (with appropriate arguments), detects these arguments, modifies the registry, sets the exit code and closes — skips form creation and normal Application handling. The main instance reads the exit code and thus knows whether the operation was successful, and if not, it displays an appropriate error message based on this code.

The code that opens a new instance with elevated privileges and waits for the task to be executed looks like this (shortened):

Code: Pascal  [Select][+][-]
  1. uses
  2.   Windows,
  3.   ShellAPI;
  4.  
  5. function TEditorUtilsInstances.OpenRegister(const AParameters: String): Integer;
  6. var
  7.   ShellInfo: SHELLEXECUTEINFO;
  8.   Filename:  String;
  9. begin
  10.   // Prepare path for the application to run (in this case, the second instance of the editor).
  11.   Filename := FontEditor.Utils.Instances.Location;
  12.   Filename += ExtractFileName(Application.ExeName);
  13.  
  14.   ShellInfo              := Default(SHELLEXECUTEINFO);
  15.   ShellInfo.cbSize       := SizeOf(ShellInfo);
  16.   ShellInfo.lpVerb       := 'runas'; // Force displays a UAC dialog for confirmation.
  17.   ShellInfo.lpFile       := PChar(Filename); // Application path to run.
  18.   ShellInfo.lpParameters := PChar(AParameters); // Arguments that allow the application to detect that it has been launched only to perform a special task.
  19.   ShellInfo.fMask        := SEE_MASK_NOCLOSEPROCESS; // Wait until the process finishes.
  20.   ShellInfo.nShow        := SW_SHOW;
  21.  
  22.   // Display UAC window and wait for confirmation.
  23.   if ShellExecuteExA(@ShellInfo) then
  24.   begin
  25.     // The user has accepted the UAC dialog, so wait for the second instance to complete.
  26.     WaitForSingleObject(ShellInfo.hProcess, INFINITE);
  27.  
  28.     // Read the process exit code containing the result of the task execution (should never fail).
  29.     if not GetExitCodeProcess(ShellInfo.hProcess, LongWord(Result)) then
  30.       Result := EDITOR_ERROR_REGISTER_SUCCESS;
  31.  
  32.     // Close the process handle.
  33.     CloseHandle(ShellInfo.hProcess);
  34.   end
  35.   else
  36.     // The user cancelled the UAC dialog (pressed "no" or close button), so do nothing.
  37.     Result := EDITOR_ERROR_REGISTER_CANCELLED;
  38. end;

The code of the main editor module looks like this:

Code: Pascal  [Select][+][-]
  1. begin
  2.   case Editor.FontEditor.Utils.Instances.OpenedReason() of
  3.     EDITOR_OPEN_REASON_LOCATION_REGISTER:      ExitCode := Editor.FontEditor.Utils.Register.LocationRegister();
  4.     EDITOR_OPEN_REASON_LOCATION_UNREGISTER:    ExitCode := Editor.FontEditor.Utils.Register.LocationUnregister();
  5.     EDITOR_OPEN_REASON_ASSOCIATION_REGISTER:   ExitCode := Editor.FontEditor.Utils.Register.AssociationRegister();
  6.     EDITOR_OPEN_REASON_ASSOCIATION_UNREGISTER: ExitCode := Editor.FontEditor.Utils.Register.AssociationUnegister();
  7.   otherwise
  8.     Editor.FontEditor.Utils.Instances.Open();
  9.   end
  10. end.

First, the reason for launching the application is checked based on run arguments:

Code: Pascal  [Select][+][-]
  1. function TEditorUtilsInstances.OpenedReason(): Integer;
  2. begin
  3.   Result := EDITOR_OPEN_REASON_NORMAL;
  4.  
  5.   case Application.ParamCount of
  6.     1: case Application.Params[1] of
  7.          EDITOR_PARAMETER_LOCATION_REGISTER:      Result := EDITOR_OPEN_REASON_LOCATION_REGISTER;
  8.          EDITOR_PARAMETER_LOCATION_UNREGISTER:    Result := EDITOR_OPEN_REASON_LOCATION_UNREGISTER;
  9.          EDITOR_PARAMETER_ASSOCIATION_REGISTER:   Result := EDITOR_OPEN_REASON_ASSOCIATION_REGISTER;
  10.          EDITOR_PARAMETER_ASSOCIATION_UNREGISTER: Result := EDITOR_OPEN_REASON_ASSOCIATION_UNREGISTER;
  11.        otherwise
  12.          Result := EDITOR_OPEN_REASON_EDIT;
  13.        end;
  14.  
  15.     2: case Application.Params[1] of
  16.          EDITOR_PARAMETER_OPEN_CLONED: Result := EDITOR_OPEN_REASON_CLONE;
  17.        end;
  18.   end;
  19. end;

If the argument is one of those specifying a special task (e.g. EDITOR_OPEN_REASON_ASSOCIATION_REGISTER, i.e. registering file extensions in the registry), the editor performs its task, sets the exit code and closes. However, if it was started normally, it creates a form and runs normally:

Code: Pascal  [Select][+][-]
  1. procedure TEditorUtilsInstances.Open();
  2. begin
  3.   RequireDerivedFormResource := True;
  4.  
  5.   Application.Title  := 'Project: Kids — Font Editor';
  6.   Application.Scaled := True;
  7.  
  8.   Application.Initialize();
  9.   Application.CreateForm(TFormMain, FormMain);
  10.   Application.Run();
  11. end;
« Last Edit: April 01, 2024, 12:59:53 pm by furious programming »
Lazarus 3.2 with FPC 3.2.2, Windows 10 — all 64-bit

Working solo on an acrade, action/adventure game in retro style (pixelart), programming the engine and shell from scratch, using Free Pascal and SDL. Release planned in 2026.

badmintonfan

  • New Member
  • *
  • Posts: 49
Re: A button require administrator level
« Reply #3 on: May 15, 2024, 07:16:14 am »
thanks every one

KodeZwerg

  • Hero Member
  • *****
  • Posts: 2269
  • Fifty shades of code.
    • Delphi & FreePascal
Re: A button require administrator level
« Reply #4 on: May 15, 2024, 10:44:47 am »
Thats how I do if neeeded.
Code: Pascal  [Select][+][-]
  1. procedure RunUnelevated(const FileName: string);
  2. var
  3.   ProcessInfo: TProcessInformation;
  4.   StartupInfo: TStartupInfo;
  5. begin
  6.   FillChar(StartupInfo, SizeOf(TStartupInfo), 0);
  7.   StartupInfo.cb := SizeOf(TStartupInfo);
  8.   if CreateProcess(nil, PChar('explorer.exe "' + FileName + '"'), nil, nil, False, 0, nil, nil, StartupInfo, ProcessInfo) then
  9.   begin
  10.     CloseHandle(ProcessInfo.hProcess);
  11.     CloseHandle(ProcessInfo.hThread);
  12.   end;
  13. end;
  14.  
  15. function RunElevated(const FileName: WideString; const Params: WideString): Boolean;
  16. var
  17.   ShellExecuteInfo: TShellExecuteInfoW;
  18. begin
  19.   Result := False;
  20.   FillChar(ShellExecuteInfo, SizeOf(ShellExecuteInfo), 0);
  21.   ShellExecuteInfo.cbSize := SizeOf(ShellExecuteInfo);
  22.   ShellExecuteInfo.fMask := SEE_MASK_NOCLOSEPROCESS;
  23.   ShellExecuteInfo.Wnd := GetActiveWindow; // or 0 if you don't have a window handle
  24.   ShellExecuteInfo.lpVerb := 'runas'; // Request UAC elevation
  25.   ShellExecuteInfo.lpFile := PWideChar(FileName);
  26.   ShellExecuteInfo.lpParameters := PWideChar(Params);
  27.   ShellExecuteInfo.nShow := SW_NORMAL;
  28.  
  29.   if ShellExecuteExW(@ShellExecuteInfo) then
  30.   begin
  31.     WaitForSingleObject(ShellExecuteInfo.hProcess, INFINITE);
  32.     Result := True;
  33.   end;
  34. end;
« Last Edit: Tomorrow at 31:76:97 xm by KodeZwerg »

 

TinyPortal © 2005-2018