CreateProcessAsUser 函数 运行 来自服务的 GUI 程序

CreateProcessAsUser function to run a GUI program from a service

下面是我用于 运行 来自服务应用程序的 GUI 应用程序的代码。我正在传递命令字符串“C:\Windows\notepad.exe”。

它没有打开记事本,甚至没有给出任何错误。即使在使用 WTSQueryUserToken 之后,hToken 仍为空。 这是以用户身份创建过程的文档 link:https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessasusera

private void cpasUser(String cmd) {
        HANDLE h = null; 
        final HANDLEByReference childStdInRead = new HANDLEByReference();
        final HANDLEByReference childStdInWrite = new HANDLEByReference();
        final HANDLEByReference childStdOutRead = new HANDLEByReference();
        final HANDLEByReference childStdOutWrite = new HANDLEByReference();
        
        final int HANDLE_FLAG_INHERIT = 0x00000001;
        final int HANDLE_FLAG_PROTECT_FROM_CLOSE = 0x00000002;
        
        final int BUFSIZE = 4096;
        final int GENERIC_READ = 0x80000000;
        final int FILE_ATTRIBUTE_READONLY = 1;
        final int OPEN_EXISTING = 3;
        final DWORD STD_OUTPUT_HANDLE = new DWORD(-11);
        final int STARTF_USESTDHANDLES = 0x00000100;
        
        String szCmdline = cmd;

        PROCESS_INFORMATION processInformation = new PROCESS_INFORMATION();
        STARTUPINFO startupInfo = new STARTUPINFO();
        startupInfo.cb = new DWORD(processInformation.size());
        startupInfo.hStdError = childStdOutWrite.getValue();
        startupInfo.hStdOutput = childStdOutWrite.getValue();
        startupInfo.hStdInput = childStdInRead.getValue();
        startupInfo.dwFlags |= STARTF_USESTDHANDLES;
 
        // Create the child process. 
        HANDLE hToken = null;
        MyWtsapi32 mw = MyWtsapi32.INSTANCE;
        mw.WTSQueryUserToken(Kernel32Ext.INSTANCE.WTSGetActiveConsoleSessionId(), hToken) ;

      //be sure that the handle is correct ! (can be the issue)
      if (hToken == null) logger.info("Token error.");
        if (!Advapi32.INSTANCE.CreateProcessAsUser(
                hToken, 
                szCmdline, 
                null, 
                null, 
                null,
                true, 
                32, 
                null, 
                null, 
                startupInfo, 
                processInformation)){
           // System.err.println(Advapi32.INSTANCE.GetLastError());
            logger.error("Cannot create process as User ");
            logger.error("error code "+Native.getLastError());
        }

MyWtsApi32.java

public interface MyWtsapi32 extends Wtsapi32 {
      // Your own instance to access your functions
     MyWtsapi32 INSTANCE =  Native.load("Wtsapi32", MyWtsapi32.class, W32APIOptions.DEFAULT_OPTIONS);
    
    // From https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-messagebox
    int MB_OK = 0; 

    // The function to send the message
      boolean WTSSendMessageW(HANDLE hServer, int SessionId,
        LPWSTR pTitle, int TitleLength,
        LPWSTR pMessage, int MessageLength,
        int Style, int Timeout, IntByReference pResponse, boolean bWait);
      
      boolean WTSQueryUserToken(long SessionId,HANDLE hServer);
}

Kernel32Ext.java

public interface Kernel32Ext extends Kernel32{
    Kernel32Ext INSTANCE = Native.load("Kernel32",Kernel32Ext.class,W32APIOptions.DEFAULT_OPTIONS);
    
    int WTSGetActiveConsoleSessionId();
}

当您的 JNA 函数映射不起作用时,第一个调试步骤应该是检查您的函数映射。

WTSQueryUserToken 定义为:

BOOL WTSQueryUserToken(
    ULONG SessionId,
    PHANDLE phToken
);

Windows类型ULONGan unsigned 32-bit integer;它应该映射为 int,而不是 long

PHANDLE 是指向 HANDLE 的指针,而不是句柄本身。正确的 JNA 映射是 HANDLEByReference.

所以你的接口函数映射应该是:

boolean WTSQueryUserToken(int SessionId, HANDLEByReference hServer);

调用它的代码应该是:

HANDLEByReference phToken = new HANDLEByReference();
MyWtsapi32 mw = MyWtsapi32.INSTANCE;
// you should probably check the return value here
// on failure throw LastErrorException
mw.WTSQueryUserToken(Kernel32Ext.INSTANCE.WTSGetActiveConsoleSessionId(), phToken);

// Extract the HANDLE for use in later code
HANDLE hToken = phToken.getValue();