Jump to content
William23668

How to debug an app that need to run as administrator from the IDE ?

Recommended Posts

Hi

 

I searched for solution and found in stack overflow two methods but still not getting what I need. The code I use that need admin level :

 

Handle := CreateFile(pchar('\\.\PhysicalDrive' + IntToStr(DiskNumber)), GENERIC_READ, FILE_SHARE_READ  , nil, OPEN_EXISTING, 0, 0);

 

It return invalid handle. So I created this manifest to debug run the app as admin and include it in my app source folder:

 

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
    <assemblyIdentity
        version="1.0.0.0"
        processorArchitecture="*"
        name="myapp"
        type="win32"
    />
    <description>My Delphi Application</description>
    <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
        <security>
            <requestedPrivileges>
                <requestedExecutionLevel
                    level="requireAdministrator"
                    uiAccess="false"
                />
            </requestedPrivileges>
        </security>
    </trustInfo>
</assembly>

included this line in my dpr source:

{$R *.res}
{$R 'myapp.manifest'}

but I get this error:

Quote

RLINK32: Unsupported 16bit resource in file "H:\myapp\myapp.manifest"

I saved the file as text utf-8 

 

I tried another method to include this "SetEnvironmentVariable" line in the dpr source

begin
  Application.Initialize;
  SetEnvironmentVariable('__COMPAT_LAYER', 'RunAsAdmin');
  Application.MainFormOnTaskbar := True;
  Application.CreateForm(TForm2, Form2);
  Application.Run;
end.

But I still get invalid handle so I think SetEnvironmentVariable did not work, any ideas ?

 

When I run the exe as admin from explorer I dont get this invalid handle error.

 

Delphi 12 and Windows 11 Pro

 

Thanks

 

Edited by William23668

Share this post


Link to post
2 hours ago, William23668 said:

{$R 'myapp.manifest'}

 

You can't use {$R} to link a .manifest file directly like that, it can only link a precompiled .res file.  But, what you can do is create an .rc file that references the .manifest file, and then tell {$R} to compile that .rc file into a .res file and link it, eg:

// mymanifest.rc
#define CREATEPROCESS_MANIFEST_RESOURCE_ID 1
#define RT_MANIFEST 24
CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "myapp.manifest"
 {$R 'mymanifest.res' 'mymanifest.rc'}

However, you do not need to resort to using {$R} in this manner at all, as the Project Options dialog has an option to let you specify a custom .manifest file:

 

Customizing the Windows Application Manifest File

 

And there is also a configurable option to specify an ExecutionLevel in a compiler-generated manifest:

 

Application Options: Manifest File (Windows Only)

 

2 hours ago, William23668 said:

I tried another method to include this "SetEnvironmentVariable" line in the dpr source

That approach will not work, as your application's process is already running when you call SetEnvironmentVariable(), but elevation needs to occur BEFORE the process is created.  To use __COMPAT_LAYER properly, you would have to create a separate .bat script that sets the __COMPAT_LAYER first and then runs your application so it inherits the updated environment.

 

See: What does '__COMPAT_LAYER' actually do?

2 hours ago, William23668 said:

When I run the exe as admin from explorer I dont get this invalid handle error.

Makes sense, as access to a physical drive requires admin rights (or, at least the SE_BACKUP_NAME privilege).  But, that does not mean you have to run your entire application as an admin (unless you really need to).  A better solution would be to isolate the disk access code into a separate process or COM object, and then run just that process/object elevated.

Edited by Remy Lebeau
  • Like 1

Share this post


Link to post
18 minutes ago, Remy Lebeau said:

And there is also a configurable option to specify an ExecutionLevel in a compiler-generated manifest:

Thanks I tried now to use the auto generate but I still can not get the drive handle, why ?

 

image.thumb.png.6a3399e2ee332be559de1b07a7742710.png

Share this post


Link to post
33 minutes ago, William23668 said:

Thanks I tried now to use the auto generate but I still can not get the drive handle, why ?

What does GetLastError() return when CreateFile() fails?  Does it return ERROR_ACCESS_DENIED (5, ie you don't have rights to open the drive), ERROR_SHARING_VIOLATION (32, ie someone else has the drive open for non-read access, but you are sharing only read access), or something else?

Handle := CreateFile(...);
if Handle = INVALID_HANDLE_VALUE then
begin
  ErrCode := GetLastError; // <-- what does this return?
  ...
end

 

Edited by Remy Lebeau
  • Like 1

Share this post


Link to post
46 minutes ago, Remy Lebeau said:

What does GetLastError() return when CreateFile() fails?  Does it return ERROR_ACCESS_DENIED (5, ie you don't have rights to open the drive), ERROR_SHARING_VIOLATION (32, ie someone else has the drive open for non-read access, but you are sharing only read access), or something else?

Yes I get code 32 but all drives are local

Share this post


Link to post
1 hour ago, William23668 said:

Yes I get code 32 but all drives are local

Locality has nothing to do with it.

 

You are opening the drive with just FILE_SHARE_READ specified by itself.  You are telling the OS that you are willing to share access to the drive with other open handles only if they open the drive for read-only access.  If anybody else already has the drive open for writing, then you won't be able to open it since you are not willing to share write access.  And clearly someone does have the drive open for writing (you can verify this with a tool like SysInternals' Handle or Process Monitor utilities), which is why you are getting the "sharing violation" error.

 

Try adding FILE_SHARE_WRITE for your sharing rights:

Handle := CreateFile(..., FILE_SHARE_READ or FILE_SHARE_WRITE, ...);

But be aware that this will allow other open handles to potentially write to the drive while you are reading from it.  If that is not what you want, then omit FILE_SHARE_WRITE and simply warn your user that you can't gain read-only access to the drive.

Edited by Remy Lebeau
  • Thanks 1

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×