2

我需要将一个 DLL 注入到 Adob​​e Reader X 中,该 DLL 读取发送到滚动条的事件(即使它是隐藏的)。我需要这样做才能找出我在文档的哪一页。

我尝试使用 win32 钩子 API 钩子一个 dll,我给桌面上的所有进程一个 CBT 钩子并监听 Adob​​e Reader X 窗口的创建,然后用我的滚动条钩子钩子这个窗口。

问题是我从来没有在 Adob​​e Reader X 上放置滚动条挂钩,在创建这些窗口时我没有收到这些窗口的创建窗口或窗口激活消息。我如何获取这些消息以及如何连接到 Adob​​e Reader X?

#define WIN32_LEAN_AND_MEAN  
#include <windows.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "pdfviewlib.h"
#include <sstream>

#pragma data_seg(".PDFVIEWLIB")
PDFVIEWOBJ pdfviewobj[MAX_PDFOBJS] = {NULL};
HHOOK globalhook = NULL;
BOOL debug = TRUE;
INT sSlide = 0;

#pragma data_seg()
#pragma comment(linker, "/SECTION:.PDFVIEWLIB,RWS")

#define DEBUG(...)  if(debug) printf(__VA_ARGS__)

HINSTANCE hInstance = NULL;

static int tAttach = 0;
static int tDetach = 0;

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    hInstance = (HINSTANCE)hModule;
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
        DEBUG("PROCESS_ATTACH\n");
        break;
    case DLL_THREAD_ATTACH:
        DEBUG("THREAD_ATTACH %i\n",tAttach++);
        break;
    case DLL_THREAD_DETACH:
        DEBUG("THREAD_DETACH %i\n", tDetach++);
        break;
    case DLL_PROCESS_DETACH:
        // Clean up... hopefully there is only the one process attached? 
        DEBUG("PROCESS_DETACH\n");
        for(int i = 0; i<MAX_PDFOBJS; i++)
            ClosePDF(i);
        break;
    }
    return TRUE;
}
DllExport void SetDebug(BOOL onoff)
{
    printf("SetDebug\n");
    debug = onoff;
    DEBUG("enabled\n");
}


//Check if Acrobat Reader is installed
DllExport BOOL CheckInstalled()
{
    DEBUG("CheckInstalled\n");
    char cmdline[MAX_PATH * 2];
    return GetPDFViewerPath(cmdline, sizeof(cmdline));
}

// Open the PDF
DllExport int OpenPDF(char *filename, HWND hParentWnd, int startSlide)
{
    STARTUPINFO * si = (STARTUPINFO *) malloc(sizeof(STARTUPINFO));
    PROCESS_INFORMATION * pi = (PROCESS_INFORMATION*) malloc(sizeof(PROCESS_INFORMATION));
    char cmdline[MAX_PATH * 2];
    int id;
    sSlide = startSlide;


    DEBUG("OpenPDF start: %u", hParentWnd);
    //First check if Acrobat Reader is installed before continuing
    if(GetPDFViewerPath(cmdline, sizeof(cmdline))==FALSE)
    {
        DEBUG("OpenPDF: GetPDFTViewerPath failed\n");
        return -1;
    }
    id = -1;
    for(int i = 0; i<MAX_PDFOBJS; i++)
    {
        if(pdfviewobj[i].state==PDF_CLOSED)
        {
            id=i;
            break;
        }
    }
    if(id<0)
    {
        DEBUG("OpenPDF: Too many PDFs\n");
        return -1;
    }
    if (pdfviewobj[id].state == PDF_STARTED) 
    {
        DEBUG("RERUN WHEN PDF_STARTED\n");
        return -1;
    }
    memset(&pdfviewobj[id], 0, sizeof(PDFVIEWOBJ));
    strcpy_s(pdfviewobj[id].filename, MAX_PATH, filename);

    pdfviewobj[id].state = PDF_CLOSED;
    pdfviewobj[id].currentSlide = 0;
    pdfviewobj[id].hParentWnd = hParentWnd;
    pdfviewobj[id].hWnd = NULL;
    pdfviewobj[id].hWnd2 = NULL;

    strcat_s(cmdline, MAX_PATH * 2, "\\AcroRd32.exe /n /s /o");
    strcat_s(cmdline, MAX_PATH * 2, " \"");
    strcat_s(cmdline, MAX_PATH * 2, filename);
    strcat_s(cmdline, MAX_PATH * 2, "\"");
    si = (STARTUPINFO *)memset(si, 0, sizeof(STARTUPINFO));
    pi = (PROCESS_INFORMATION *)memset(pi, 0, sizeof(PROCESS_INFORMATION)); 
    if(globalhook!=NULL){
        UnhookWindowsHookEx(globalhook);
        DEBUG("Global unhooked\n");
        globalhook = NULL;
    }
    //Set the global hook listening for Window Create/Window Activate messages
    globalhook = SetWindowsHookEx(WH_CBT,CbtProc,hInstance,NULL);
    if(globalhook==NULL)
    {
        DEBUG("OpenPDF: Global SetWindowsHookEx failed\n");
        DEBUG("ERROR: %X\n", GetLastError());
        globalhook = NULL;
        ClosePDF(id);
        return -1;
    }
    else DEBUG("GLOBAL HOOKED %X\n", globalhook);
    pdfviewobj[id].state = PDF_STARTED;
    Sleep(10); 
    DEBUG(cmdline);
    //Run Acrobat Reader, PDF STATE SET TO STARTED
    if(!CreateProcess(NULL, cmdline, NULL, NULL, FALSE, 0, 0, NULL, si, pi))
    {
        DEBUG("OpenPDF: CreateProcess failed\n");
        ClosePDF(id);
        return -1;
    }
    pdfviewobj[id].dwProcessId = pi->dwProcessId;
    pdfviewobj[id].dwThreadId = pi->dwThreadId;
    pdfviewobj[id].hThread = pi->hThread;
    pdfviewobj[id].hProcess = pi->hProcess;
    //WAIT FOR GLOBAL HOOK TO DETECT Acrobat Windows and set PDF STATE TO PDF_OPENED
    //For some reason the loops exits and PDFSTATE is PDF_CLOSED...  
    while(pdfviewobj[id].state==PDF_STARTED)
        Sleep(50);
    DEBUG("PDFSTATE == CLOSED = %i \n", pdfviewobj[id].state==PDF_CLOSED);
    DEBUG("PDFSTATE == STARTED = %i \n", pdfviewobj[id].state==PDF_STARTED);
    DEBUG("PDFSTATE == OPENED = %i \n", pdfviewobj[id].state==PDF_OPENED);
    DEBUG("PDFSTATE == LOADED = %i \n", pdfviewobj[id].state==PDF_LOADED);
    if (sSlide > 0){
        GotoSlide(id, sSlide+1);
    }
    pdfviewobj[id].state = PDF_LOADED;
    DEBUG("OpenPDF Done: id=%i\n", id);
    return id;
}

// Get the path of Acrobat Reader X from the registry 
BOOL GetPDFViewerPath(char *pdfviewerpath, int strsize)
{
    HKEY hkey;
    DWORD dwtype, dwsize;
    LRESULT lresult;

    DEBUG("GetPDFViewerPath: start\n");
        if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Adobe\\Acrobat Reader\\9.0\\InstallPath", 0, KEY_READ, &hkey)!=ERROR_SUCCESS)            
            return FALSE;   
    dwtype = REG_SZ;
    dwsize = (DWORD)strsize;
    lresult = RegQueryValueEx(hkey, NULL, NULL, &dwtype, (LPBYTE)pdfviewerpath, &dwsize );
    RegCloseKey(hkey);
    if(lresult!=ERROR_SUCCESS)
        return FALSE;
    DEBUG("GetPDFViewerPath: exit ok \n");
    return TRUE;
}

// Unhook the Windows hook 
void Unhook(int id)
{
    DEBUG("Unhook: start %i\n", id);
    if(pdfviewobj[id].hook!=NULL)   
        UnhookWindowsHookEx(pdfviewobj[id].hook);
    pdfviewobj[id].hook = NULL;
    DEBUG("Unhook: exit ok\n");
}

// Close the Acrobat Reader, release resources
DllExport void ClosePDF(int id)
{
    DEBUG("ClosePDF: start %i\n", id);
    if (globalhook != NULL) {
        DEBUG("GLOBAL UNHOOKED %X\n", globalhook);
        UnhookWindowsHookEx(globalhook);
        globalhook = NULL;

    }
    else DEBUG("GLOBAL NOT UNHOOKED\n");
    pdfviewobj[id].state = PDF_CLOSED;
    Unhook(id);
    if(pdfviewobj[id].hWnd==0)
        TerminateThread(pdfviewobj[id].hThread, 0);
    else
        PostMessage(pdfviewobj[id].hWnd, WM_CLOSE, 0, 0);
    CloseHandle(pdfviewobj[id].hThread);
    CloseHandle(pdfviewobj[id].hProcess);
    memset(&pdfviewobj[id], 0, sizeof(PDFVIEWOBJ)); 
    DEBUG("ClosePDF: exit ok\n");
    return;
}
// Return the number of the slide currently viewing
DllExport int GetCurrentSlide(int id)
{
    DEBUG("GetCurrentSlide:%d\n", id);
    if(pdfviewobj[id].state==0)
        return -1;
    else
        return pdfviewobj[id].currentSlide;
}

// Take a step forwards through the show 
DllExport void NextStep(int id)
{
    DEBUG("NextStep:%d\n", id);
    SetForegroundWindow(pdfviewobj[id].hWnd);
    SetFocus(pdfviewobj[id].hWnd);
    PostMessage(pdfviewobj[id].hWnd2, WM_MOUSEWHEEL, MAKEWPARAM(0, -WHEEL_DELTA), 0);
}

// Take a step backwards through the show 
DllExport void PrevStep(int id)
{
    DEBUG("PrevStep:%d\n", id);
    SetForegroundWindow(pdfviewobj[id].hWnd);
    SetFocus(pdfviewobj[id].hWnd);
    PostMessage(pdfviewobj[id].hWnd2, WM_MOUSEWHEEL, MAKEWPARAM(0, WHEEL_DELTA), 0);
}

// Go directly to a slide
DllExport void GotoSlide(int id, int slideno)
{   
    //TODO: USE SETSCROLLINFO 
}


// This hook is started with the AcroRd32.EXE process and waits for the WM_CREATEWND message. 
// Release the hook as soon as we're complete to free up resources
LRESULT CALLBACK CbtProc(int nCode, WPARAM wParam, LPARAM lParam)
{
    HHOOK hook = globalhook;
    DEBUG("HOOK: %X\n", hook);
    if (nCode < 0) {
        return CallNextHookEx(hook, nCode, wParam, lParam);
    }
    else if(nCode==HCBT_CREATEWND)
    {
        DEBUG("CREATE WINDOW \n");
        char csClassName[16];
        char csCaptionName[16];
        HWND hCurrWnd = (HWND)wParam;
        DWORD retProcId = NULL;
        GetClassName(hCurrWnd, csClassName, sizeof(csClassName));
        GetWindowText(hCurrWnd, csCaptionName, sizeof(csCaptionName));
        if((strcmp(csClassName, "AcrobatSDIWindow")==0)
          ||(strcmp(csClassName, "AVL_AVView")==0))
        {
            DEBUG("%s found \n", csClassName);
            int id=-1;
            DWORD windowthread = GetWindowThreadProcessId(hCurrWnd,NULL);
            for(int i=0; i<MAX_PDFOBJS; i++)
            {
                if(pdfviewobj[i].dwThreadId==windowthread)
                {
                    id=i;
                    break;
                }
            }
            if(id>=0)
            {
                DEBUG("Matched threadid!\n");
                if(strcmp(csClassName, "AVL_AVView")==0){
                    if (strcmp(csCaptionName, "AVPageView")==0){
                        pdfviewobj[id].hWnd2=hCurrWnd;
                    }
                }
                else        
                {
                    pdfviewobj[id].hWnd=hCurrWnd;
                    CBT_CREATEWND* cw = (CBT_CREATEWND*)lParam;
                    if(pdfviewobj[id].hParentWnd!=NULL) 
                        cw->lpcs->hwndParent = pdfviewobj[id].hParentWnd;
                }
                if((pdfviewobj[id].hWnd!=NULL)&&(pdfviewobj[id].hWnd2!=NULL))
                {
                    pdfviewobj[id].hook = SetWindowsHookEx(WH_CALLWNDPROC,CwpProc,hInstance,pdfviewobj[id].dwThreadId);
                    if (pdfviewobj[id].hook != NULL) {
                        DEBUG("Global UNHOOKED %X\n", globalhook);
                        UnhookWindowsHookEx(globalhook);
                        globalhook=NULL;                        
                        pdfviewobj[id].state = PDF_OPENED;
                    }                   
                    Sleep(10);                  
                }
            }
        }
    }
    return CallNextHookEx(hook,nCode,wParam,lParam); 
}


LRESULT CALLBACK CwpProc(int nCode, WPARAM wParam, LPARAM lParam){
    CWPSTRUCT *cwp;
    cwp = (CWPSTRUCT *)lParam;
    HHOOK hook = NULL;

    DWORD windowthread = GetWindowThreadProcessId(cwp->hwnd,NULL);
    int id=-1;
    for(int i=0; i<MAX_PDFOBJS; i++)
    {
        if(pdfviewobj[i].dwThreadId==windowthread)
        {
            id=i;
            hook = pdfviewobj[id].hook;
            break;
        }
    }
    if((id>=0)&&(nCode==HC_ACTION))
    {
        DEBUG("CBT HC_ACTION\n");
        if(cwp->message==SBM_SETSCROLLINFO)
        {
            DEBUG("CBT SBM_SETSCROLLINFO\n");
            SCROLLINFO *scrInf;
            scrInf = (SCROLLINFO *)cwp->lParam;
            pdfviewobj[id].currentSlide = scrInf->nPos;             
        }
        if((pdfviewobj[id].state != PDF_CLOSED)&&(cwp->message==WM_CLOSE||cwp->message==WM_QUIT)){
            pdfviewobj[id].state = PDF_CLOSING;
        }
    }
    return CallNextHookEx(hook,nCode,wParam,lParam); 
}

如果您需要,这是标题

#define DllExport extern "C"  __declspec( dllexport ) 

enum PDFVIEWSTATE { PDF_CLOSED, PDF_STARTED, PDF_OPENED, PDF_LOADED, PDF_CLOSING};

DllExport int OpenPDF(char *filename, HWND hParentWnd, int startSlide);
DllExport BOOL CheckInstalled();
DllExport void ClosePDF(int id);
DllExport int GetCurrentSlide(int id);
DllExport void NextStep(int id);
DllExport void PrevStep(int id);
DllExport void GotoSlide(int id, int slideno);

DllExport void SetDebug(BOOL onoff);

LRESULT CALLBACK CbtProc(int nCode, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK CwpProc(int nCode, WPARAM wParam, LPARAM lParam);
BOOL GetPDFViewerPath(char *pdfviewerpath, int strsize);

void Unhook(int id);

//MAXUMUM NUMBER OF PDF-PROCESSES CURRENTLY SET TO ONE
#define MAX_PDFOBJS 1

struct PDFVIEWOBJ 
{
    HHOOK hook;
    HWND hWnd;
    HWND hWnd2;
    HWND hParentWnd;
    HANDLE hProcess;
    HANDLE hThread;
    DWORD dwProcessId;
    DWORD dwThreadId;
    int currentSlide;
    char filename[MAX_PATH];
    PDFVIEWSTATE state;
};
4

1 回答 1

2

Adobe Reader 通常在受保护模式下运行。(请参阅编辑/首选项/安全(增强)。取消选中“启动时启用保护模式”复选框。

重新启动阅读器,看看您是否收到消息。你应该。问题是用户界面特权隔离 (UIPI) 不允许许多 Windows 消息跨越以不同完整性级别(低/中/高)运行的进程之间的进程边界。您应该能够通过 ChangeWindowMessageFilterEx() 更改 Windows 消息过滤器。

我目前遇到 Adob​​e Reader Xi 的问题,其中 ChangeWindowsMessageFilter 和 ChangeWindowMessageFilterEx 似乎没有改变 Adob​​e 阅读器在挂钩过程中向全局挂钩接收器发送消息的行为。我已将 noteapad.exe 复制到 notepad2.exe 并通过以下方式将其完整性级别降低到低:icacls notepad2.exe /setintegritylevel low(从提升的 cmd 提示符运行(即以管理员身份运行))。当我这样做时,我的挂钩工作正常(使用 ChangeWindowMessageFilterEx()),但仍然没有收到来自 Adob​​e 的挂钩消息。

此外,Reader 是 32 位的,因此请确保您从 32 位挂钩进程中挂钩它,否则您也不会看到消息)。

于 2015-09-18T15:48:38.240 回答