Search code examples
c#winapifreepascallazarus

Windows 7 Welcome screen (translating c# to pascal)


The code provided by Jon in the following thread seems to illustrate exactly what I want to do

Running a process at the Windows 7 Welcome Screen

Unfortunately it's in C#, a language I don't know at all. I'm trying to translate the code to Pascal (a recent version of Lazarus on Windows 7). From reading between the lines, I think I may have got a lot of it - however, I'll only know if I've got it wrong when it fails to do its job. At the moment it is failing to compile at the following point.

if (!DuplicateTokenEx(userToken, 0x10000000, ref tokenAttributes,   
SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation, TOKEN_TYPE.TokenImpersonation,
out newToken)) {
log("ERROR: DuplicateTokenEx returned false - "

My Pascal version:

If Not DuplicateTokenEx(UserToken, MAXIMUM_ALLOWED, tokenAttributes,
SecurityImpersonation, TokenPrimary, newToken) then
  Writeln(DLog, 'Failed to duplicate security token'); 

Lazarus throws an error on the fifth of the six parameters.

dmain.pas(189,110) Error: Incompatible type for arg no. 5: Got "TOKEN_TYPE", expected "_TOKEN_TYPE" - which indicates I haven't understood what the parameters are doing. (Changing parameter 5 to TokenImpersonation throws the same error.)

Further down, I get even more lost:

tokPrivs.Privileges = new LUID_AND_ATTRIBUTES[1];
tokPrivs.Privileges[0].Luid = seDebugNameValue;
tokPrivs.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

I can see that the structure type LUID_AND_ATTRIBUTES is in the Windows API but it seems it's not recognised by Lazarus.

In short, I'm groping around in the dark. I've tried Googling for "C# for Pascal programmers" but didn't find anything helpful. Learning C# isn't a trivial undertaking, so I be would really grateful for any hints on the differences between it and Object Pascal, and how to translate this code.

Edit: Unfinished code as requested.

function RunOurProcess(ProgramName: String): Boolean;
var
StartInfo: TStartupInfo;
ProcInfo: TProcessInformation;
NewToken, Token, UserToken: THandle;
WPID: DWord;
ThreadAttributes, TokenAttributes: TSecurityAttributes;
TOKPrivs: TTokenPrivileges;
begin
    FillChar(StartInfo, SizeOf(TStartupInfo), #0);
    FillChar(ProcInfo, SizeOf(TProcessInformation), #0);
    StartInfo.cb:= SizeOf(TStartupInfo);
    { Insert handle of current desktop - without this, GUI app is not visible!
      To appear before logon, lpDesktop value should be 'winsta0\WinLogon' }
    StartInfo.lpDesktop:= PChar('winsta0\WinLogon');
    // Save the process ID of the WinLogon process
    WPID:= FindInProcesses('Winlogon.exe');
    // Get the handle of this
    Token:= OpenProcess(TOKEN_QUERY or TOKEN_IMPERSONATE or TOKEN_DUPLICATE, False, WPID);
    // Open a process token using the handle above
    If OpenProcessToken(Token, TOKEN_QUERY or TOKEN_IMPERSONATE or TOKEN_DUPLICATE, UserToken) then
    Writeln(DLog, 'Opened process token for WinLogon')
        else
    Writeln(DLog, 'Failed to open process token for WinLogon');
    // Create a new token
    NewToken:= 0;
    tokenAttributes.nLength:= SizeOf(tokenAttributes);
    threadAttributes.nLength:= SizeOf(threadAttributes);
    If Not DuplicateTokenEx(UserToken, MAXIMUM_ALLOWED, tokenAttributes, SecurityImpersonation, TokenImpersonation, newToken) then
    Writeln(DLog, 'Failed to duplicate security token');
    // Elevate the privileges of the token
    AdjustTokenPrivileges(NewToken, False, {NewState, BufferLength, PreviousState, ReturnLength});
    // LogOnUser
    // If successful, CreateProcessAsUser
    // In progress - code below needs to go before 'CreateProcessAsUser'
    StartInfo.cb:= SizeOf(TStartupInfo);
    // Insert handle of current desktop - without this, GUI app is not visible!
    StartInfo.lpDesktop:= PChar('winsta0\WinLogon');
end; // RunOurProcess            

I notice now that I get the following error if I try to find the declaration for "DuplicateTokenEx"

C:\lazarus\fpc\2.6.1\source\packages\winunits-jedi\src\jwawindows.pas(366,5) Error: include file not found "JwaLmErr.pp"


Solution

  • Here's how to solve the compilation problems.

    The call to DuplicateTokenEx actually fails on the third parameter. Looking at the declaration, it is LPSECURITY_ATTRIBUTES which is ^TSecurityAttributes. Now, tokenAttributes is of type TSecurityAttributes so you need to pass its address:

    If Not DuplicateTokenEx(..., @tokenAttributes, ...) then
    

    And similarly in the call to AdjustTokenPrivileges. The C# code is:

    AdjustTokenPrivileges(newToken, false, ref tokPrivs, 0, IntPtr.Zero, IntPtr.Zero)
    

    Translated to Pascal that would be:

    AdjustTokenPrivileges(NewToken, False, @TOKPrivs, 0, nil, nil)
    

    I've no idea whether or not the code will solve your problem. I think that's beyond the remit of this question – at least that's my excuse and I'm sticking to it!