如何用AutoHotkey获取激活的Foxit窗口PDF总页数
获取激活状态下Foxit PhantomPDF打开的PDF总页数(AutoHotkey实现)
问题背景
已实现Adobe Acrobat下获取当前打开PDF总页数的功能,但在Foxit PhantomPDF场景中,无法获取激活窗口对应的PDF文件路径,现有代码仅能在指定固定路径时获取页数,需补充路径获取逻辑以实现完整需求。
解决方案
通过以下步骤实现:
- 获取当前激活的Foxit PhantomPDF窗口句柄
- 从窗口标题或进程命令行中提取打开的PDF文件路径
- 将提取到的路径传入原有页数获取逻辑,计算总页数
完整AutoHotkey代码
F1:: ; 获取当前激活窗口的句柄 WinGet, activeWinID, ID, A WinGet, activeWinProcess, ProcessName, ahk_id %activeWinID% ; 验证是否为Foxit PhantomPDF进程 if (activeWinProcess != "FoxitPhantomPDF.exe") { MsgBox 当前激活窗口不是Foxit PhantomPDF return } ; 尝试从窗口标题提取文件路径 WinGetTitle, activeWinTitle, ahk_id %activeWinID% pdfPath := ExtractPathFromTitle(activeWinTitle) ; 如果标题提取失败,从进程命令行获取 if (!pdfPath) { pdfPath := ExtractPathFromProcess(activeWinID) } if (!pdfPath) { MsgBox 无法获取当前打开的PDF文件路径 return } ; 原有获取页数的逻辑 VarSetCapacity(GUID, 16) DllCall("ole32\CLSIDFromString", "wstr", IID_RandomAccessStream := "{905A0FE1-BC53-11DF-8C49-001E4FC686DA}", "ptr", &GUID) DllCall("ShCore\CreateRandomAccessStreamOnFile", "wstr", pdfPath, "uint", Read := 0, "ptr", &GUID, "ptr*", IRandomAccessStream) CreateClass("Windows.Data.Pdf.PdfDocument", IPdfDocumentStatics := "{433A0B5F-C007-4788-90F2-08143D922599}", PdfDocumentStatics) DllCall(NumGet(NumGet(PdfDocumentStatics+0)+8*A_PtrSize), "ptr", PdfDocumentStatics, "ptr", IRandomAccessStream, "ptr*", PdfDocument) ; LoadFromStreamAsync WaitForAsync(PdfDocument) DllCall(NumGet(NumGet(PdfDocument+0)+7*A_PtrSize), "ptr", PdfDocument, "uint*", PageCount) ; get_PageCount ObjReleaseClose(IRandomAccessStream) ObjReleaseClose(PdfDocumentStatics) ObjReleaseClose(PdfDocument) MsgBox 当前PDF总页数:%PageCount% return ; 从窗口标题提取路径(Foxit标题格式:"文件名 - Foxit PhantomPDF") ExtractPathFromTitle(title) { splitPos := InStr(title, " - Foxit PhantomPDF") if (splitPos = 0) return "" ; 处理可能的引号(如果文件名含空格,标题会带引号) filePath := SubStr(title, 1, splitPos-1) if (SubStr(filePath, 1, 1) = """" && SubStr(filePath, StrLen(filePath)) = """") { filePath := SubStr(filePath, 2, StrLen(filePath)-2) } ; 验证路径是否存在 if (FileExist(filePath)) return filePath return "" } ; 从进程命令行提取路径 ExtractPathFromProcess(winID) { WinGet, pid, PID, ahk_id %winID% hProcess := DllCall("OpenProcess", "UInt", 0x400 | 0x10, "Int", 0, "UInt", pid, "Ptr") if (!hProcess) return "" ; 获取命令行缓冲区大小 cmdLineSize := DllCall("Psapi\GetCommandLine", "Ptr", hProcess, "Ptr", 0, "UInt", 0, "UInt*", 0) + 1 VarSetCapacity(cmdLine, cmdLineSize * 2, 0) DllCall("Psapi\GetCommandLine", "Ptr", hProcess, "Ptr", &cmdLine, "UInt", cmdLineSize, "UInt*", 0) DllCall("CloseHandle", "Ptr", hProcess) ; 解析命令行,提取PDF路径(Foxit启动参数中会包含打开的文件路径) cmdLineStr := StrGet(&cmdLine, "UTF-16") ; 分割命令行中的参数 params := [] inQuotes := false currentParam := "" loop, Parse, cmdLineStr { char := A_LoopField if (char = """") { inQuotes := !inQuotes continue } if (!inQuotes && char = " ") { if (currentParam != "") { params.Push(currentParam) currentParam := "" } continue } currentParam .= char } if (currentParam != "") params.Push(currentParam) ; 遍历参数,找到存在的PDF文件路径 for index, param in params { if (SubStr(param, -3) = ".pdf" || SubStr(param, -4) = ".PDF") { if (FileExist(param)) return param } } return "" } CreateClass(string, interface := "", ByRef Class := "") { CreateHString(string, hString) if (interface = "") result := DllCall("Combase.dll\RoActivateInstance", "ptr", hString, "ptr*", Class, "uint") else { VarSetCapacity(GUID, 16) DllCall("ole32\CLSIDFromString", "wstr", interface, "ptr", &GUID) result := DllCall("Combase.dll\RoGetActivationFactory", "ptr", hString, "ptr", &GUID, "ptr*", Class, "uint") } if (result != 0) { if (result = 0x80004002) msgbox No such interface supported else if (result = 0x80040154) msgbox Class not registered else msgbox error: %result% ExitApp } DeleteHString(hString) } CreateHString(string, ByRef hString) { DllCall("Combase.dll\WindowsCreateString", "wstr", string, "uint", StrLen(string), "ptr*", hString) } DeleteHString(hString) { DllCall("Combase.dll\WindowsDeleteString", "ptr", hString) } WaitForAsync(ByRef Object) { AsyncInfo := ComObjQuery(Object, IAsyncInfo := "{00000036-0000-0000-C000-000000000046}") loop { DllCall(NumGet(NumGet(AsyncInfo+0)+7*A_PtrSize), "ptr", AsyncInfo, "uint*", status) ; IAsyncInfo.Status if (status != 0) { if (status != 1) { DllCall(NumGet(NumGet(AsyncInfo+0)+8*A_PtrSize), "ptr", AsyncInfo, "uint*", ErrorCode) ; IAsyncInfo.ErrorCode msgbox AsyncInfo status error: %ErrorCode% ExitApp } ObjRelease(AsyncInfo) break } sleep 10 } DllCall(NumGet(NumGet(Object+0)+8*A_PtrSize), "ptr", Object, "ptr*", ObjectResult) ; GetResults ObjReleaseClose(Object) Object := ObjectResult } ObjReleaseClose(ByRef Object) { if Object { if (Close := ComObjQuery(Object, IClosable := "{30D5A829-7FA4-4026-83BB-D75BAE4EA99E}")) { DllCall(NumGet(NumGet(Close+0)+6*A_PtrSize), "ptr", Close) ; Close ObjRelease(Close) } ObjRelease(Object) } Object := "" }
代码说明
- 路径提取逻辑:优先从窗口标题解析路径,若失败则读取进程命令行参数,覆盖文件名含空格、特殊字符等场景
- 页数计算:复用原有基于Windows.Data.Pdf.PdfDocument的COM接口实现,保证页数获取的准确性
- 兼容性处理:加入路径有效性验证,避免无效路径导致的报错
内容的提问来源于stack exchange,提问作者Shahin Kachooie
相关产品推荐
相关产品推荐

