'As Administrator' folder - Lister shows images only as text
Moderators: Hacker, petermad, Stefan2, white
'As Administrator' folder - Lister shows images only as text
Lister is unable to display multimedia content of the image/animation file, that is located in a directory that requires administrator rights.
Steps to reproduce:
1) create directory c:\test,
2) copy any image or animation file to c:\test, that TC is able to display with F3 - some BMP, PNG, AVI, etc.
3) select image/animation file and press F3 - multimedia content will be shown,
4) now go to c:\, open properties of c:\test and, in the Security tab:
- Windows 7: remove access rights for all groups - leave only Administrators group,
- Windows XP: remove all access rights, and then add access rights only for some user, that you are currently not logged in as,
5) go into c:\test again - select "As Administrator" option when prompted,
6) select image/animation file and press F3 - image or animation will NOT be shown, text contents will be shown instead; selecting Options -> Image/Multimedia will not help.
Launching TC in administrator mode solves the problem, but even in the normal mode (after using "As Administrator" option) the image/animation file contents are accessible for Lister (Lister displays contents as text), so Image/Multimedia mode should also work properly.
Additional note: also comparing (Files -> Compare By Contents) contents of the file located in c:\test with some other file fails - "Access denied on file" message is shown.
Regards
Steps to reproduce:
1) create directory c:\test,
2) copy any image or animation file to c:\test, that TC is able to display with F3 - some BMP, PNG, AVI, etc.
3) select image/animation file and press F3 - multimedia content will be shown,
4) now go to c:\, open properties of c:\test and, in the Security tab:
- Windows 7: remove access rights for all groups - leave only Administrators group,
- Windows XP: remove all access rights, and then add access rights only for some user, that you are currently not logged in as,
5) go into c:\test again - select "As Administrator" option when prompted,
6) select image/animation file and press F3 - image or animation will NOT be shown, text contents will be shown instead; selecting Options -> Image/Multimedia will not help.
Launching TC in administrator mode solves the problem, but even in the normal mode (after using "As Administrator" option) the image/animation file contents are accessible for Lister (Lister displays contents as text), so Image/Multimedia mode should also work properly.
Additional note: also comparing (Files -> Compare By Contents) contents of the file located in c:\test with some other file fails - "Access denied on file" message is shown.
Regards
- ghisler(Author)
- Site Admin
- Posts: 50549
- Joined: 2003-02-04, 09:46 UTC
- Location: Switzerland
- Contact:
Sorry, this is unfortunately impossible. Neither TC plugins nor the internal media player control can access files which require admin rights for reading. The reading has to be done via tcmadmin.exe tool, but the functions require a file handle or even a file name.
Author of Total Commander
https://www.ghisler.com
https://www.ghisler.com
I don't know exactly how it works, so I have two questions:
- what is the difference between Lister and media player in Lister - isn't this the same process with same file access rights?
- what about "Compare By Contents" tool?
However, I can see some potential general solutions:
- opening a file in tcmadmin.exe and passing the file handle to media player/CBC tool,
- as above, but with a file mapping handle instead of the file handle (could be useful for CreateDIBSection function - it can get a file mapping handle as a parameter).
Regards
- what is the difference between Lister and media player in Lister - isn't this the same process with same file access rights?
- what about "Compare By Contents" tool?
However, I can see some potential general solutions:
- opening a file in tcmadmin.exe and passing the file handle to media player/CBC tool,
- as above, but with a file mapping handle instead of the file handle (could be useful for CreateDIBSection function - it can get a file mapping handle as a parameter).
Regards
- ghisler(Author)
- Site Admin
- Posts: 50549
- Joined: 2003-02-04, 09:46 UTC
- Location: Switzerland
- Contact:
Lister can request data from tcmadmin.exe through a Windows Pipe - MediaPlayer requires physical access to the media file itself.what is the difference between Lister and media player in Lister - isn't this the same process with same file access rights?
Currently there is no admin support in the compare tool.what about "Compare By Contents" tool?
This will not work (Windows access restrictions)opening a file in tcmadmin.exe and passing the file handle to media player/CBC tool,
File mappings are process-specific, the file is only mapped into a specific process (tcmadmin.exe or totalcmd.exe, not both).as above, but with a file mapping handle instead of the file handle (could be useful for CreateDIBSection function - it can get a file mapping handle as a parameter).
Author of Total Commander
https://www.ghisler.com
https://www.ghisler.com
- ghisler(Author)
- Site Admin
- Posts: 50549
- Joined: 2003-02-04, 09:46 UTC
- Location: Switzerland
- Contact:
Honestly I don't know whether DuplicateHandle works with UAC or not, there is no indication in the MSDN article:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms724251%28v=vs.85%29.aspx
http://msdn.microsoft.com/en-us/library/windows/desktop/ms724251%28v=vs.85%29.aspx
Author of Total Commander
https://www.ghisler.com
https://www.ghisler.com
DuplicateHandle works - below is some test code. This was tested with Windows Vista and should also work with more recent Windows versions.
For Windows NT4/2000/XP there is no UAC and "requireAdministrator" in manifest is ignored - so CreateProcessAsUser (or similar) should be used instead of ShellExecuteEx.
The best approach seems to make a call to ShellExecuteEx first, and - when it fails - to CreateProcessAsUser (after asking for user name and password).
Usage: Test.exe SomeFile
where SomeFile is a file accessible only in Administrator mode (see steps to reproduce in the first post)
Test.dpr:
TestAdmin.dpr:
TestAdmin.exe.manifest (place in the same place as TestAdmin.exe):
For Windows NT4/2000/XP there is no UAC and "requireAdministrator" in manifest is ignored - so CreateProcessAsUser (or similar) should be used instead of ShellExecuteEx.
The best approach seems to make a call to ShellExecuteEx first, and - when it fails - to CreateProcessAsUser (after asking for user name and password).
Usage: Test.exe SomeFile
where SomeFile is a file accessible only in Administrator mode (see steps to reproduce in the first post)
Test.dpr:
Code: Select all
program Test;
uses
Windows, SysUtils, ShellAPI;
{$IFDEF VER90} {Delphi 2}
{WARNING: ROUGH IMPLEMENTATION - FOR TESTING PURPOSES ONLY}
function AnsiQuotedStr(const S : string; Quote : Char) : string;
begin
Result:=Quote+S+Quote;
end;
{$ENDIF}
const
TESTADMINEXE = 'testadmin.exe';
var
Caption : string;
FileName : string;
FileHandle : THandle;
ShellExecuteInfo : TShellExecuteInfo;
ShellExecuteFile : string;
ShellExecuteParameters : string;
RemoteExitCode : {$IFDEF VER90}Integer{$ELSE}Cardinal{$ENDIF};
Buffer : packed array[0..100-1] of Byte;
BytesRead : {$IFDEF VER90}Integer{$ELSE}Cardinal{$ENDIF};
begin
Caption:=ExtractFileName(ParamStr(0));
FileName:=ParamStr(1);
if FileName = '' then
begin
MessageBox(0,'Enter file name as a parameter!',PChar(Caption),MB_ICONSTOP);
Exit;
end;
FileHandle:=CreateFile(PChar(FileName),GENERIC_READ,FILE_SHARE_READ,nil,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
if FileHandle <> INVALID_HANDLE_VALUE then
begin
CloseHandle(FileHandle);
MessageBox(0,'File could be accessed in a normal way, exiting.',PChar(Caption),MB_ICONSTOP);
Exit;
end;
FillChar(ShellExecuteInfo,SizeOf(ShellExecuteInfo),0);
ShellExecuteFile:=ExtractFilePath(ParamStr(0))+TESTADMINEXE;
ShellExecuteParameters:=IntToStr(GetCurrentProcessId)+' '+AnsiQuotedStr(FileName,'"');
with ShellExecuteInfo do
begin
cbSize:=SizeOf(ShellExecuteInfo);
fMask:=SEE_MASK_NOCLOSEPROCESS;
lpFile:=PChar(ShellExecuteFile);
lpParameters:=PChar(ShellExecuteParameters);
nShow:=SW_SHOW;
end;
if not ShellExecuteEx(@ShellExecuteInfo) then
begin
MessageBox(0,PChar('ShellExecuteEx call failed with error code '+IntToStr(GetLastError)+'.'),PChar(Caption),MB_ICONSTOP);
Exit;
end;
try
WaitForSingleObject(ShellExecuteInfo.hProcess,INFINITE);
FileHandle:=INVALID_HANDLE_VALUE;
if not GetExitCodeProcess(ShellExecuteInfo.hProcess,RemoteExitCode) then
begin
MessageBox(0,PChar('GetExitCodeProcess call failed with error code '+IntToStr(GetLastError)+'.'),PChar(Caption),MB_ICONSTOP);
Exit;
end;
try
FileHandle:=Integer(RemoteExitCode); {x64: typecasting to Integer forces sign-extending from 32-bit value to 64-bit value}
if (FileHandle = INVALID_HANDLE_VALUE) or (FileHandle = 0) then
begin
MessageBox(0,'Could not open file with '+TESTADMINEXE+'.',PChar(Caption),MB_ICONSTOP);
Exit;
end;
if not ReadFile(FileHandle,Buffer[0],SizeOf(Buffer),BytesRead,nil) then
begin
MessageBox(0,PChar('ReadFile call failed with error code '+IntToStr(GetLastError)+'.'),PChar(Caption),MB_ICONSTOP);
Exit;
end;
MessageBox(0,PChar('Successfully read '+IntToStr(BytesRead)+' bytes:'#13#10+string(PAnsiChar(@Buffer[0]))),PChar(Caption),MB_OK);
finally
CloseHandle(FileHandle);
end;
finally
CloseHandle(ShellExecuteInfo.hProcess);
end;
end.
Code: Select all
program TestAdmin;
uses
Windows, SysUtils;
{$IFDEF VER90} {Delphi 2}
const
PROCESS_DUP_HANDLE = $00000040;
DUPLICATE_SAME_ACCESS = $00000002;
{$ENDIF}
var
Caption : string;
Code : Integer;
ParentPID : Cardinal;
FileName : string;
ParentProcessHandle : THandle;
FileHandle : THandle;
DuplicatedFileHandle : THandle;
begin
ExitCode:=Integer(INVALID_HANDLE_VALUE);
Caption:=ExtractFileName(ParamStr(0));
Val(ParamStr(1),ParentPID,Code);
if Code <> 0 then
begin
MessageBox(0,'Enter parent process ID as a parameter!',PChar(Caption),MB_ICONSTOP);
Exit;
end;
FileName:=ParamStr(2);
if FileName = '' then
begin
MessageBox(0,'Enter file name as a parameter!',PChar(Caption),MB_ICONSTOP);
Exit;
end;
ParentProcessHandle:=OpenProcess(PROCESS_DUP_HANDLE,False,ParentPID);
if ParentProcessHandle = 0 then
begin
MessageBox(0,PChar('OpenProcess call failed with error code '+IntToStr(GetLastError)+'.'),PChar(Caption),MB_ICONSTOP);
Exit;
end;
try
FileHandle:=CreateFile(PChar(FileName),GENERIC_READ,FILE_SHARE_READ,nil,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
if FileHandle = INVALID_HANDLE_VALUE then
begin
MessageBox(0,PChar('CreateFile call failed with error code '+IntToStr(GetLastError)+'.'),PChar(Caption),MB_ICONSTOP);
Exit;
end;
try
if not DuplicateHandle(GetCurrentProcess,FileHandle,ParentProcessHandle,@DuplicatedFileHandle,0,True,DUPLICATE_SAME_ACCESS) then
begin
MessageBox(0,PChar('DuplicateHandle call failed with error code '+IntToStr(GetLastError)+'.'),PChar(Caption),MB_ICONSTOP);
Exit;
end;
{ExitCode is always 32-bit, file handle may be 64-bit, but:
"64-bit versions of Windows use 32-bit handles for interoperability.
When sharing a handle between 32-bit and 64-bit applications, only
the lower 32 bits are significant, so it is safe to truncate the handle
(when passing it from 64-bit to 32-bit) or sign-extend the handle
(when passing it from 32-bit to 64-bit)."}
ExitCode:=DuplicatedFileHandle;
finally
CloseHandle(FileHandle);
end;
finally
CloseHandle(ParentProcessHandle);
end;
{$IFDEF VER90} {Delphi 2}
{Delphi 2 overwrites ExitCode value with 0 without this call}
Halt(ExitCode);
{$ENDIF}
end.
Code: Select all
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity
type="win32"
name="DelphiApplication"
version="1.0.0.0"
processorArchitecture="*"/>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges>
<requestedExecutionLevel
level="requireAdministrator"/>
</requestedPrivileges>
</security>
</trustInfo>
</assembly>
- ghisler(Author)
- Site Admin
- Posts: 50549
- Joined: 2003-02-04, 09:46 UTC
- Location: Switzerland
- Contact: