William23668 8 Posted February 6 (edited) 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 February 6 by William23668 Share this post Link to post
William23668 8 Posted February 6 Just now, FPiette said: Just run the IDE as administrator. Tried that but I got invalid handle Share this post Link to post
Remy Lebeau 1394 Posted February 6 (edited) 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 February 6 by Remy Lebeau 1 Share this post Link to post
William23668 8 Posted February 6 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 ? Share this post Link to post
Remy Lebeau 1394 Posted February 6 (edited) 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 February 6 by Remy Lebeau 1 Share this post Link to post
William23668 8 Posted February 6 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
Remy Lebeau 1394 Posted February 6 (edited) 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 February 6 by Remy Lebeau 1 Share this post Link to post
William23668 8 Posted February 6 3 minutes ago, Remy Lebeau said: Try adding FILE_SHARE_WRITE Thanks alot this solved the problem. Share this post Link to post