سؤال

I need to inject a DLL into Adobe Reader X that reads the events sent to the scrollbar (even if it is hidden). I need to do this to be able to find out what page of the document i am on.

I have tried hooking a dll using the win32 hooking API, i give a CBT hook to all processes on the desktop and listen for the creation of the Adobe Reader X window, then hooking this window with my scrollbar hook.

The problem is that i never get the scrollbar hook placed on Adobe Reader X, i dont get the create window or window activate messages for these windows when they are created. How do i get these messages and how do i hook into Adobe 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); 
}

heres the header if you need it

#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;
};
هل كانت مفيدة؟

المحلول

Adobe Reader typically runs in protected mode. (See Edit/Preferences/Security (Enhanced). Un-check the "Enable Protected Mode at startup" checkbox.

Relaunch reader and see if you get your messages. You should. The issue is that the User Interface Privilege Isolation (UIPI) disallows many windows messages from crossing process boundaries between processes running at a different integrity level (low/medium/high). You are supposed to be able to change the windows message filter via ChangeWindowMessageFilterEx().

I am currently experiencing issues with Adobe Reader Xi where the ChangeWindowsMessageFilter and ChangeWindowMessageFilterEx do not seem to change the behavior of Adobe reader sending messages to the global hook receiver in the hooking process. I have copied noteapad.exe to notepad2.exe and lowered its integrity level to low via: icacls notepad2.exe /setintegritylevel low (run from an elevated cmd prompt (i.e. run as admin)). When I do this my hooking works fine (using ChangeWindowMessageFilterEx()) but still does not get hooked messages from Adobe.

Also, Reader is 32-bit so make sure you are hooking it from a 32-bit hooking process otherwise you won't see messages either).

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