10

C# 2.0 アプリケーションの外部にあるウィンドウの実行可能ファイルの名前を取得しようとしています。私のアプリは現在、「user32.dll」から GetForegroundWindow() 呼び出しを使用してウィンドウ ハンドル (hWnd) を取得しています。

掘り下げた結果、(PSAPI の) GetModuleFileNameEx() 関数を使用して名前を取得したいと思いますが、GetModuleFileNameEx() にはウィンドウではなくプロセスへのハンドルが必要です。

ウィンドウ ハンドルからプロセス ハンドルを取得することは可能ですか? (最初にウィンドウのスレッド ハンドルを取得する必要がありますか?)

私がやろうとしていることをより明確にするために、最初の文を編集しました。

アップデート!これが私のために働いていることがわかったC#コードです。唯一の注意点は、ドライブ文字が「?」であるファイル/パスを返す場合があることです実際のドライブ文字 (「C」など) の代わりに。-- 理由はまだわかりません。

[DllImport("user32.dll")]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);

[DllImport("kernel32.dll")]
static extern IntPtr OpenProcess(UInt32 dwDesiredAccess, Int32 bInheritHandle, UInt32 dwProcessId);

[DllImport("psapi.dll")]
static extern uint GetModuleFileNameEx(IntPtr hProcess, IntPtr hModule, [Out] StringBuilder lpBaseName, [In] [MarshalAs(UnmanagedType.U4)] int nSize);

[DllImport("kernel32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool CloseHandle(IntPtr hObject);

private string GetWindowModuleFileName(IntPtr hWnd)
{
    uint processId = 0;
    const int nChars = 1024;
    StringBuilder filename = new StringBuilder(nChars);
    GetWindowThreadProcessId(hWnd, out processId);
    IntPtr hProcess = OpenProcess(1040, 0, processId);
    GetModuleFileNameEx(hProcess,IntPtr.Zero,filename,nChars);
    CloseHandle(hProcess);
    return (filename.ToString());
}
4

5 に答える 5

8

同じ問題に1時間苦労しており、最初の文字が?に置き換えられました。GetModuleFileNameEx を使用して。最後に、 System.Diagnostics.Processクラスを使用してこのソリューションを考え出しました。

[DllImport("user32.dll")]
public static extern IntPtr GetWindowThreadProcessId(IntPtr hWnd, IntPtr ProcessId);

void GetProcessPathFromWindowHandle(IntPtr hwnd)
{
   uint pid = 0;
   Win32.GetWindowThreadProcessId(hwnd, out pid);
   Process p = Process.GetProcessById((int)pid);
   return p.MainModule.FileName;
}
于 2008-11-26T16:36:08.730 に答える
6

GetWindowThreadProcessIdを呼び出すと、ウィンドウに関連付けられたプロセスが返されます。

そこから、OpenProcessを呼び出してプロセスを開き、プロセスへのハンドルを取得できます。

于 2008-11-10T05:09:37.350 に答える
2

Windows 64ビットプラットフォームで実行している場合は、代わりにQueryFullProcessImageNameを使用する必要がある場合があります。これは、NtQuerySymbolicLinkObjectまたはZwQuerySymbolicLinkObjectを使用して変換する必要があるシステムスタイルパスを返すGetProcessImageFileNameとは異なり、ユーザースタイルパスを返します。

巨大な関数の例の1つ-再利用可能なビットに分割することをお勧めします。

typedef DWORD (__stdcall *PfnQueryFullProcessImageName)(HANDLE hProcess, DWORD dwFlags, LPTSTR lpImageFileName, PDWORD nSize);
typedef DWORD (__stdcall *PfnGetModuleFileNameEx)(HANDLE hProcess, HMODULE hModule, LPTSTR lpImageFileName, DWORD nSize);

std::wstring GetExeName( HWND hWnd ){
// Convert from Window to Process ID
DWORD dwProcessID = 0;
::GetWindowThreadProcessId(hWnd, &dwProcessID);

// Get a handle to the process from the Process ID
HANDLE hProcess = ::OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, dwProcessID);

// Get the process name
if (NULL != hProcess) {
    TCHAR szEXEName[MAX_PATH*2] = {L'\0'};
    DWORD nExeName = sizeof(szEXEName)/sizeof(TCHAR);

    //  the QueryFullProcessImageNameW does not exist on W2K
    HINSTANCE hKernal32dll = LoadLibrary(L"kernel32.dll");
    PfnQueryFullProcessImageName pfnQueryFullProcessImageName = NULL;
    if(hKernal32dll != NULL) {
        pfnQueryFullProcessImageName = (PfnQueryFullProcessImageName)GetProcAddress(hKernal32dll, "QueryFullProcessImageNameW");
        if (pfnQueryFullProcessImageName != NULL) 
            pfnQueryFullProcessImageName(hProcess, 0, szEXEName, &nExeName);
        ::FreeLibrary(hKernal32dll);
    } 

    // The following was not working from 32 querying of 64 bit processes
    // Use as backup for when function above is not available 
    if( pfnQueryFullProcessImageName == NULL ){ 
        HINSTANCE hPsapidll = LoadLibrary(L"Psapi.dll");
        PfnGetModuleFileNameEx pfnGetModuleFileNameEx = (PfnGetModuleFileNameEx)GetProcAddress(hPsapidll, "GetModuleFileNameExW");
        if( pfnGetModuleFileNameEx != NULL )    
            pfnGetModuleFileNameEx(hProcess, NULL, szEXEName, sizeof(szEXEName)/sizeof(TCHAR));
        ::FreeLibrary(hPsapidll);
    }

    ::CloseHandle(hProcess);

    return( szEXEName );
} 
return std::wstring();
}
于 2009-02-11T02:38:59.823 に答える
1

あなたがやろうとしていることは、正確には何ですか?GetWindowThreadProcessId()でウィンドウを作成したプロセスのプロセス ID を取得し、続いてOpenProcess()でプロセス ハンドルを取得できます。しかし、これは非常に厄介なように思えます。やりたいことを行うためのよりエレガントな方法があるように感じます。

于 2008-11-10T05:10:07.647 に答える
0

実行可能ファイルのファイル名を取得するには、これを試してください:

C#:

string file = System.Windows.Forms.Application.ExecutablePath;

製造

于 2010-05-31T07:52:31.613 に答える