如何使用Java获取当前正在运行的应用程序的名称(与任务管理器中的相同)? (Windows)

问题描述 投票:0回答:1

这是我的代码,应该打印当前使用的应用程序的名称:

import com.sun.jna.Native;
import com.sun.jna.platform.win32.*;
import com.sun.jna.ptr.IntByReference;

public class AppList {

    public static void main(String[] args) {

        // PRINT TITLE OF ACTIVE WINDOW (NOT WANTED)
        User32 user32 = User32.INSTANCE;
        WinDef.HWND hwnd = user32.GetForegroundWindow();
        char[] title = new char[1024];
        user32.GetWindowText(hwnd, title, title.length);
        System.out.println("Active window: " + String.valueOf(title));
        // "Active window: Project4 - AppList.java"

        // PRINT PATH OF ACTIVE APP AND FORMAT IT (BETTER BUT STILL NOT WANTED)
        IntByReference processId = new IntByReference();
        int id = user32.GetWindowThreadProcessId(hwnd, processId);
        WinNT.HANDLE processHandle = Kernel32.INSTANCE.OpenProcess(
                WinNT.PROCESS_QUERY_INFORMATION | WinNT.PROCESS_VM_READ, false, processId.getValue());
        char[] exePath = new char[1024];
        Psapi.INSTANCE.GetModuleFileNameExW(processHandle, null, exePath, exePath.length);
        String exePathStr = Native.toString(exePath);
        System.out.println(exePathStr);
        // "C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2023.3.2\bin\idea64.exe"

        // FORMAT IT
        String activeAppName = exePathStr.substring(exePathStr.lastIndexOf("\\") + 1)
                .replace(".exe", "").toLowerCase();
        char firstChar = Character.toUpperCase(activeAppName.charAt(0));
        activeAppName = firstChar + activeAppName.substring(1);

        System.out.println(activeAppName);
        Kernel32.INSTANCE.CloseHandle(processHandle);
        // "Idea64" instead of "InteliJ IDEA"
        // "Chrome" instead of "Google Chrome"
        // "Applicationframehost" instead of "Settings"
        // Task manager doesn't work at all
    }
}

如您所见,它无法正常工作。我想获取任务管理器中的应用程序名称(InteliJ IDEA、Google Chrome)

-使用第一个选项给我窗口标题。在某些情况下效果很好,但通常很糟糕。

-使用第二个选项为我提供当前应用程序的路径并对其进行格式化。在某些情况下也能很好地工作(例如 Spotify),但在大多数情况下,它会给我一些奇怪的名称,或者根本不起作用。

我花了几个小时在谷歌上搜索并询问人工智能,但我找不到任何东西。这些是我找到的唯一选择。

java jna
1个回答
0
投票

经过一番努力尝试找出如何使用 JNA 并使用 Win32 API 正确指定和操作参数后,我得到了一个工作示例,但最终与我给出的链接完全不同 - 这太手动了:

import com.sun.jna.platform.win32.*;

import com.sun.jna.Memory;
import com.sun.jna.Pointer;
import com.sun.jna.ptr.IntByReference;
import com.sun.jna.ptr.PointerByReference;

public class AppList {
    public static void main(String[] args) {
        // Just my luck, Eclipse doesn't have version info in it. This one does... 
        String testAppFilespec = "D:\\Programming\\Android\\Android Studio\\bin\\studio64.exe"; 
        String appDescription = "<Unable to retrieve>"; 
        
        // Find out how big the VERSIONINFO structure in the file is. 
        IntByReference hVerHandle = new IntByReference(); 
        int verSize = Version.INSTANCE.GetFileVersionInfoSize(testAppFilespec, hVerHandle); 
        
        // Create a memory buffer and try to grab the version info into it. 
        if (verSize > 0) { 
            Memory pInfoStruct = new Memory(verSize); 
            boolean gotInfo = Version.INSTANCE.GetFileVersionInfo(testAppFilespec, 
                                                                    0, verSize, 
                                                                    pInfoStruct); 
            if (gotInfo) { 
                // Grab the list of language / codepage pairs. 
                PointerByReference pLangCodePageList = new PointerByReference(null); 
                IntByReference pCPSize = new IntByReference(); 
                if (Version.INSTANCE.VerQueryValue(pInfoStruct, 
                                                    "\\VarFileInfo\\Translation", 
                                                    pLangCodePageList, pCPSize) 
                        && pCPSize.getValue() > 0) { 

                    // We'll use the description from the first entry only: 
                    
                    // pCPSize.getValue() has the number of bytes in ONE 
                    // language / codepage entry. 

                    // Don't use getPointer() here!!! Had me scratching my head 
                    // for hours... 
                    Pointer pEntry = pLangCodePageList.getValue();                  
                    byte[] langCodePageBytes 
                        = pEntry.getByteArray(0,  pCPSize.getValue() ); 
                    
                    // Format the name of the sub-block containing the 
                    // description of this app (watch byte order here): 
                    String subBlockName 
                        = "\\StringFileInfo\\" 
                        + String.format("%02x", langCodePageBytes[1] ) 
                        + String.format("%02x", langCodePageBytes[0] ) 
                        + String.format("%02x", langCodePageBytes[3] ) 
                        + String.format("%02x", langCodePageBytes[2] ) 
                        + "\\FileDescription"; 
                    
                    // Now ask for this value out of the full info struct: 
                    PointerByReference pDesc = new PointerByReference(); 
                    if (Version.INSTANCE.VerQueryValue(pInfoStruct, 
                                                        subBlockName, 
                                                        pDesc, pCPSize) 
                            && pCPSize.getValue() > 0) { 

                        // Strings are all wide from this info struct: 
                        appDescription = pDesc.getValue().getWideString(0); 
                        
                    }
                    
                }

            }        

        }

        System.out.println("App description: " + appDescription); 
        
    }
    
}

享受吧!

(注意:您可能必须在顶部包含一个包声明 - 我在 Eclipse 中这样做,但我已将其排除在这段代码之外。)

© www.soinside.com 2019 - 2024. All rights reserved.