كيف يمكنني الحصول على GetModuleFileName() إذا كان لدي مقبض نافذة فقط (hWnd)؟

StackOverflow https://stackoverflow.com/questions/277085

  •  07-07-2019
  •  | 
  •  

سؤال

أحاول الحصول على اسم الملف القابل للتنفيذ للنافذة الموجودة خارج تطبيق C# 2.0.يحصل تطبيقي حاليًا على مقبض نافذة (hWnd) باستخدام استدعاء GetForegroundWindow() من "user32.dll".

من الحفر الذي تمكنت من القيام به، أعتقد أنني أريد استخدام وظيفة GetModuleFileNameEx() (من PSAPI) للحصول على الاسم، ولكن 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());
}
هل كانت مفيدة؟

المحلول

تستطيع الاتصال GetWindowThreadProcessId وهذا سيعيد لك العملية المرتبطة بالنافذة.

من ذلك يمكنك الاتصال عملية مفتوحة لفتح العملية والحصول على المقبض للعملية.

نصائح أخرى

كنت أعاني من نفس المشكلة لمدة ساعة الآن، كما تم استبدال الحرف الأول بـ a ? باستخدام 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;
}

إذا كنت تعمل على نظام التشغيل Windows 64 بت، فقد تحتاج إلى استخدام QueryFullProcessImageName بدلاً من ذلك.يؤدي هذا إلى إرجاع مسار نمط المستخدم، مقارنةً بـ GetProcessImageFileName الذي يُرجع مسار نمط النظام الذي قد يحتاج إلى تحويل باستخدام NtQuerySymbolicLinkObject أو ZwQuerySymbolicLinkObject.

أحد الأمثلة الضخمة على الوظائف - نوصي بتقسيمها إلى أجزاء قابلة لإعادة الاستخدام.

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();
}

ما هو بالضبط الذي تحاول القيام به؟يمكنك الحصول على معرف العملية للعملية التي أنشأت نافذة بها GetWindowThreadProcessId(), ، تليها عملية مفتوحة () للحصول على مقبض العملية.لكن هذا يبدو مبتذلًا جدًا، وأشعر أن هناك طريقة أكثر أناقة لفعل ما تريد القيام به.

جرب هذا للحصول على اسم الملف القابل للتنفيذ:

ج#:

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

مبدعين

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top