0

ここにあるコードを使用すると、代替ユーザーとしてアプリケーションを正常に起動できます。ただし、アプリケーションの起動後に Python がクラッシュし、Windows に「python.exe が動作を停止しました」と表示されます。関数の呼び出しが終了した後にのみ発生するようですが、関数内の何かが原因ではないようです。

import ctypes, sys
from ctypes import Structure, sizeof

NULL  = 0
TRUE  = 1
FALSE = 0

INVALID_HANDLE_VALUE = -1

WORD   = ctypes.c_ushort
DWORD  = ctypes.c_uint
LPSTR  = ctypes.c_char_p
LPBYTE = LPSTR
HANDLE = DWORD

# typedef struct _PROCESS_INFORMATION {
#     HANDLE hProcess;
#     HANDLE hThread;
#     DWORD dwProcessId;
#     DWORD dwThreadId;
# } PROCESS_INFORMATION, *PPROCESS_INFORMATION, *LPPROCESS_INFORMATION;
class PROCESS_INFORMATION(Structure):
   _pack_   = 1
   _fields_ = [
       ('hProcess',    HANDLE),
       ('hThread',     HANDLE),
       ('dwProcessId', DWORD),
       ('dwThreadId',  DWORD),
   ]

# typedef struct _STARTUPINFO {
#     DWORD   cb;
#     LPSTR   lpReserved;
#     LPSTR   lpDesktop;
#     LPSTR   lpTitle;
#     DWORD   dwX;
#     DWORD   dwY;
#     DWORD   dwXSize;
#     DWORD   dwYSize;
#     DWORD   dwXCountChars;
#     DWORD   dwYCountChars;
#     DWORD   dwFillAttribute;
#     DWORD   dwFlags;
#     WORD    wShowWindow;
#     WORD    cbReserved2;
#     LPBYTE  lpReserved2;
#     HANDLE  hStdInput;
#     HANDLE  hStdOutput;
#     HANDLE  hStdError;
# } STARTUPINFO, *LPSTARTUPINFO;
class STARTUPINFO(Structure):
   _pack_   = 1
   _fields_ = [
       ('cb',              DWORD),
       ('lpReserved',      DWORD),     # LPSTR
       ('lpDesktop',       LPSTR),
       ('lpTitle',         LPSTR),
       ('dwX',             DWORD),
       ('dwY',             DWORD),
       ('dwXSize',         DWORD),
       ('dwYSize',         DWORD),
       ('dwXCountChars',   DWORD),
       ('dwYCountChars',   DWORD),
       ('dwFillAttribute', DWORD),
       ('dwFlags',         DWORD),
       ('wShowWindow',     WORD),
       ('cbReserved2',     WORD),
       ('lpReserved2',     DWORD),     # LPBYTE
       ('hStdInput',       DWORD),
       ('hStdOutput',      DWORD),
       ('hStdError',       DWORD),
   ]

# BOOL WINAPI CreateProcessWithLogonW(
#   __in         LPCWSTR lpUsername,
#   __in_opt     LPCWSTR lpDomain,
#   __in         LPCWSTR lpPassword,
#   __in         DWORD dwLogonFlags,
#   __in_opt     LPCWSTR lpApplicationName,
#   __inout_opt  LPWSTR lpCommandLine,
#   __in         DWORD dwCreationFlags,
#   __in_opt     LPVOID lpEnvironment,
#   __in_opt     LPCWSTR lpCurrentDirectory,
#   __in         LPSTARTUPINFOW lpStartupInfo,
#   __out        LPPROCESS_INFORMATION lpProcessInfo
# );
def CreateProcessWithLogonW(lpUsername = None, lpDomain = None, lpPassword =
None, dwLogonFlags = 0, lpApplicationName = None, lpCommandLine = None,
dwCreationFlags = 0, lpEnvironment = None, lpCurrentDirectory = None,
lpStartupInfo = None):
   if not lpUsername:
       lpUsername          = NULL
   else:
       lpUsername          = ctypes.c_wchar_p(lpUsername)
   if not lpDomain:
       lpDomain            = NULL
   else:
       lpDomain            = ctypes.c_wchar_p(lpDomain)
   if not lpPassword:
       lpPassword          = NULL
   else:
       lpPassword          = ctypes.c_wchar_p(lpPassword)
   if not lpApplicationName:
       lpApplicationName   = NULL
   else:
       lpApplicationName   = ctypes.c_wchar_p(lpApplicationName)
   if not lpCommandLine:
       lpCommandLine       = NULL
   else:
       lpCommandLine       = ctypes.create_unicode_buffer(lpCommandLine)
   if not lpEnvironment:
       lpEnvironment       = NULL
   else:
       lpEnvironment       = ctypes.c_wchar_p(lpEnvironment)
   if not lpCurrentDirectory:
       lpCurrentDirectory  = NULL
   else:
       lpCurrentDirectory  = ctypes.c_wchar_p(lpCurrentDirectory)
   if not lpStartupInfo:
       lpStartupInfo              = STARTUPINFO()
       lpStartupInfo.cb           = sizeof(STARTUPINFO)
       lpStartupInfo.lpReserved   = 0
       lpStartupInfo.lpDesktop    = 0
       lpStartupInfo.lpTitle      = 0
       lpStartupInfo.dwFlags      = 0
       lpStartupInfo.cbReserved2  = 0
       lpStartupInfo.lpReserved2  = 0
   lpProcessInformation              = PROCESS_INFORMATION()
   lpProcessInformation.hProcess     = INVALID_HANDLE_VALUE
   lpProcessInformation.hThread      = INVALID_HANDLE_VALUE
   lpProcessInformation.dwProcessId  = 0
   lpProcessInformation.dwThreadId   = 0
   success = ctypes.windll.advapi32.CreateProcessWithLogonW(lpUsername,
lpDomain, lpPassword, dwLogonFlags, lpApplicationName,
ctypes.byref(lpCommandLine), dwCreationFlags, lpEnvironment,
lpCurrentDirectory, ctypes.byref(lpStartupInfo),
ctypes.byref(lpProcessInformation))
   if success == FALSE:
       raise ctypes.WinError()
   #A raw_input or other blocking function here will prevent python from crashing until continuing
   return lpProcessInformation #Happens whether or not this is returned

CreateProcessWithLogonW("User", "Domain", "Password", 0, None, "C:\\Windows\\notepad.exe")
print("Test") #This will never be reached

コードでコメントしたように、関数の最後に到達しないようにすると、クラッシュは発生しません。スコープが関数の外に戻った後は何も到達せず、python.exe がクラッシュします。

私が試した回避策は、関数の最後で taskkill を使用して、PID で python.exe プロセスを強制終了することです。これにより、エラー メッセージが期待どおりに表示されなくなりましたが、子プロセス (正常に起動したプロセスを含む) も強制終了するため、理想的とは言えません。関数呼び出しを完了すると Python がクラッシュする理由がわかりません。これは、Python 2.7 と 3.x の両方で発生します。どんな提案でも大歓迎です。

4

1 に答える 1