Vista, Windows 7 UAC (User Access Control) 를 델파이에서 설정하기
델파이나 그 외 개발툴로 작성되는 윈도우즈 어플리케이션에는
UAC라는 사용자 권한 제어를 적용해야한다.
델파이에서 실행에 요구되는 Level
일반 유저나 adminstrator 권한으로 실행한다면 실행 level을 설정해야 한다.
XPMan Unit에 대한 모든 참조를 제거해야한다.
어플리케이션에 manifest로 리소스를 추가한다.
program TestAsInvoker;
{$R 'ExecutionLevelAsInVokerManifest.res' 'ExecutionLevelAsInvokeManifest.rc'}
uses
Forms,
MainForm in 'MainForm.pas' {Form1};
{$R *.res}
begin
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;
End;
델파이에서 실행에 요구되는 Level를 지원하기 위해서 우리는 manifest 리소스 파일을
직접 만들어서 포함시킬 것이다.
rc 파일은 컴파일되어 res 파일로 생성된다. Manifests는 리소스 타입 24 이며 파일명을 포함시킨다.
Manifest 파일
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<dependency>
<dependencyAssembly>
<assemblyIdentity
type="win32"
name="Microsoft.Windows.Common-Controls"
version="6.0.0.0"
publickKeyToken="6595b64144ccf1df"
language="*"
processorArchitecture="X86"
/>
</dependency>
</dependencyAssembly>
<description>elevate execution level</description>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>
<requestedExecutionLevel level="requireAdministrator" />
</requestedPrivileges>
</security>
</trustInfo>
</assembly>
trust정보는 아래의 값으로 할 수 있다.
- level = "asInvoker"
: 프로세스 생성과 동일한 token으로 실행하려는 프로세스를 시작한다.
- level = "highestAvailable"
: 사용자가 관리 권한을 갖는다면 권한상승을 허락하기 위해 administrators 를 요청하지만 일반유저 권한으로 시작한다.
- level = "requireAdministrator"
: administrators 권한 상승을 요청한다. 일반 유저는 login dialog 를 받게 된다. 결국, 관리자 권한으로 시작하게 된다.
Windows XP 경고
Manifest 포맷이 잘못되면 Windows XP 에서는 blue screen을 유발한다. MS 사이트에서 KB921337 을 봐라.
SHGetFolderPath
일반유저에게는 여러 시스템 폴더 경로가 읽기 모드가 된다.
확실한 경로를 사용하는 것이 중요하다.
SHGetFolderPath 함수를 사용해서 아래의 위치들을 구할 수 있다.
CSIDL_PERSONAL { My Documents }
CSIDL_APPDATA { Application Data, new for NT4 }
CSIDL_LOCAL_APPDATA { non roaming, user\Local Settings\Application Data }
CSIDL_COMMON_APPDATA { All Users\Application Data }
CSIDL_MYPICTURES { My Pictures, new for Win2K }
CSIDL_COMMON_DOCUMENTS { All Users\Documents }
...
implementation
{$R *.dfm}
uses
SHFolder;
Function GetFolder(csidl: Integer; ForceFolder: Boolean = False): string;
var
i: Integer;
begin
SetLength(Result, MAX_PATH);
if ForceFolder then
SHGetFolderPath(0, csidl or CSIDL_FLAG_CREATE, 0, 0 PChar(Result))
else
SHGetFolderPath(0, csidl, 0, 0, PChar(Result));
i := pos(#0, Result);
if i > 0 Then
SetLength(Result, Pred(i));
End;
function GetLocalAppDataFolder(ForceFodler: Boolean = False) : String;
begin
Result := GetFolder(CSIDL_LOCAL_APPDATA, ForceFolder);
end;
RunAsAdmin
ShelllExecute 를 사용해서 administrator 권한으로 프로세스를 실행할 수 있다.
Application이 유저가 어떤 작업을 하려할 때 수락 다이얼로그를 노출해서 바탕화면 보안을 막는 것을 최소화한다면 Application.Handle은 권한 상승을 지연한다.
Application.Handle을 사용하자. (or MainForm.Handle)
핸들을 사용하지 않는다면 직접 전면 권한상승을 줄것이다.
// Vista Utilties
procdure RunAsAdmin (hWnd: HWND; aFile: String; aParameters: String);
Var
sei: TShellExecuteInfoA;
begin
FillChar(sei, SizeOf(sei), 0);
sei.cbSize := sizeof (sei);
sei.wnd := hWnd;
sei.fMask := SEE_MASK_FLAG_DDEWAIT or SEE_MASK_FLAG_NO_UI;
sei.lpVerb := "runas";
sei.lpFile := PChar(aFile);
sei.lpParameters := PChar(aParameters);
sei.nShow := SW_SHOWNORMAL;
if not ShellExecuteEx(@sei) then
RaiseLastOSError;
end;
Using COM class for Admin tasks
admin 작업을 수행하기 위해 다른 어플리케이션을 실행하는 대신에 일반 유저로 실행하는 프로세스로부터
권한상승된 실행하는 COM 어브젝트를 호출하는 것이 가능하다.
COM 서버는 EXE 이어야 하며 EXE COM 어브젝트를 설치하기 위하여 requireAdministrator 를 필요로 한다.
등록을 위해서 아래 두가지를 해야한다.
1. LocalizedString값을 추가한다.
2. Elevation키의 값으로 Enabled=1을 추가한다.
Creating the elevated COM object
admin token의 프로세스에서 권한상승된 CoClass를 생성하기 위해 사용자 프로세스로부터 Moniker를 사용하자.
function NewCoGetObject(pazName: PWideChar; pBindOptions: PBindOpts3; const iid: TIID; out ppv): HRESULT; stdcall; external 'ole32.dll' name 'CoGetObject';
function CoCreateInstanceAdmin(WndHandle: HWND; clsid: TCLSID; iid: TIID; out ppv): HRESULT;
var
Bo: TBindOpts3;
Moniker: PWideChar;
Begin
Moniker := PWIdeChar(WideString('Elevation:Administrator!new:' + GuidToString(clsid)));
FillChar(Bo, SizeOf(Bo), #0);
Bo.hWnd := WndHandle;
Bo.cbStruct := SizeOf(Bo);
Bo.dwClassContext := CLSCTX_LOCAL_SERVER;
Result := NewCoGetObject(Moniker, @Bo, iid, ppv);
End;
Adding the Shield to your buttons- SetElevationRequiredState
admin 권한으로 클릭하는 표시로 버튼, 링크 메뉴 아이템의 Shield icon을 얻는 단순한 방법.
쉽게 수락 다이얼로그를 나타낸다.
const
BCM_FIRST = $1600; // Button control message
BCM_SETSHIELD = BCM_FIRST + $000C;
procedure SetElevationRequireState(aControl: TWinControl; Required: Boolean);
var
lRequired: Integer;
begin
lRequired := Integer(Required);
SendMessage(aControl.Handle, BCM_SETSHIELD, 0, lRequired);
end;
'Delphi, RadStudio' 카테고리의 다른 글
[개발/delphi] Windows 7에서 델파이 도움말 사용하기 (0) | 2012.08.12 |
---|---|
[개발/delphi] 컴포넌트 델파이 6, 7으로 업그레이드 시 dsgnintf 에러 해결하기 (0) | 2012.08.11 |
[개발/Delphi] 델파이에서 메모리 릭 체크하는 방법 (0) | 2012.07.09 |
[개발/delphi] 리소스 형태로 외부 파일을 자신의 프로그램에 쉽게 붙여 사용하는 방법 (0) | 2012.07.09 |
[IT/개발] delphi32.$$$ 파일 delphi32.dro 파일명으로 변경 에러 (0) | 2012.06.19 |
댓글