본문 바로가기
Delphi, RadStudio

[개발/delphi] Vista, Windows 7 UAC (User Access Control) 를 델파이에서 설정하기

by SB리치퍼슨 2012. 7. 24.

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;



반응형

댓글