Hi,

I attach some code that can open PDFs using DDE, which is the API interface. It also allows you to go to a specific page, and so on. It has been tested with a range of different Acrobat versions on all windows versions. It would be simple to extend this with other methods, such as close, print and so on.

See

http://partners.adobe.com/public/developer/en/acrobat/sdk/pdf/iac/IACOverview.pdf

for the full API Adobe provides.

Regards,
Asger
#if 
!defined(AFX_ACROBATREADER_H__A7867A8B_6E2C_42AF_90E6_4A9E81C44473__INCLUDED_)
#define AFX_ACROBATREADER_H__A7867A8B_6E2C_42AF_90E6_4A9E81C44473__INCLUDED_

#include <Ddeml.h>
#include <string>

class AcrobatReader {
public:
        AcrobatReader( std::string const & appName );
        ~AcrobatReader();
        void openDoc( std::string const & filename );
        void gotoPage( int page );
        void gotoName( std::string const & name );
private:
        // Fires up a viewer and returns true if successful
        bool startReader();
        bool acrobatReaderIsRunning();

        // Return true when successful
        bool sendDdeMsg( std::string const & msg );

        // DDE transaction
        bool setUpDde();
        void shutDownDde();
        void reportDdeError( std::string const & msg );

        // The process info is used to shut the viewer down again
        PROCESS_INFORMATION processInfo;

        // The file being viewed
        std::string file;

        // The application name, used for reporting errors
        std::string appName;

        std::string acrobatReaderExecutable;

        bool firstTime;

        // The DDE communication handles
        DWORD ddeId;
        HSZ serverName;
        HSZ topicName;
        HCONV conversation;
};

#endif // 
!defined(AFX_ACROBATREADER_H__A7867A8B_6E2C_42AF_90E6_4A9E81C44473__INCLUDED_)
#include <windows.h>
#include "AcrobatReader.h"

// Ignore DDE messages from pdf viewer
// This also seems to interact with COM.  For example, DDEMessageProc also 
receives 
// messages when an event sink is attached to IE.
HDDEDATA CALLBACK 
DDEMessageProc(
        UINT uType,
        UINT uFmt,
        HCONV hconv,
        HSZ hsz1,
        HSZ hsz2,
        HDDEDATA hdata,
        DWORD dwData1,
        DWORD dwData2 )
{
#       if defined( _DEBUG )
        UTIL_TRACE( _T("DDE callback type %d: \n"), uType );
#       endif
        return NULL;
}

void
AcrobatReader::reportDdeError( std::string const & msg )
{
        UINT errCode = DdeGetLastError( ddeId );
        std::cout << msg << " (DDE error code " << errCode << ")" << std::endl;
}

bool
AcrobatReader::startReader()
{
        CWaitCursor wc;

        // Close Acrobat Reader process and thread handles, if any
        if ( processInfo.hProcess != 0) {
                CloseHandle( processInfo.hProcess );
        }
        if ( processInfo.hThread != 0) {
                CloseHandle( processInfo.hThread );
        }
        ZeroMemory( & processInfo, sizeof( PROCESS_INFORMATION ) );

        // Tell Acrobat Reader how to start up
        STARTUPINFO startupInfo;
        ZeroMemory( & startupInfo, sizeof( STARTUPINFO ) );
        startupInfo.cb = sizeof( STARTUPINFO );
        startupInfo.wShowWindow = SW_SHOW;
        startupInfo.dwFlags = STARTF_USESHOWWINDOW;
        
        // Launch Acrobat.
        if ( ! CreateProcess( acrobatReaderExecutable.c_str(), NULL, NULL, 
NULL, 
                                                  false, NORMAL_PRIORITY_CLASS, 
NULL, NULL, & startupInfo, & processInfo ) ) {
                std::string message = 
                        "Problem starting Acrobat Reader '" + 
acrobatReaderExecutable + "': " 
                        + getFormatErrorMessage( GetLastError() );
                MessageBox(
                        ::AfxGetMainWnd()->GetSafeHwnd(),
                        message.c_str(),
                        appName.c_str(),
                        MB_OK | MB_ICONINFORMATION
                );
                return false;
        } else {
                return true;
        }
}

bool
AcrobatReader::setUpDde()
{
        /// Set up DDE communication    

        // Allow some time in ms for DDE connection to be established
        int const MAX_TIMEOUT = 5000;
        // Sleep one-fifth of a second when the DDE connection cannot be 
obtained
        int const STEP_SIZE = 200; 
        
        /// Initialize DDE conversation with server
        serverName = DdeCreateStringHandle( ddeId, _T("acroview"), 0 );
        topicName  = DdeCreateStringHandle( ddeId, _T("control"), 0 );
        // Acrobat can take a while to launch. We repeatedly attempt to connect 
to the server until MAX_TIMEOUT expires
        DWORD sleep = 0;
        while ( true ) {
                conversation = DdeConnect( ddeId, serverName, topicName, NULL );
                if ( conversation || ( sleep > MAX_TIMEOUT ) ) break;
                // Give Acrobat some more time to launch
                ::Sleep( sleep += STEP_SIZE );
        }
        
        if ( ! conversation ) {
                reportDdeError( "Could not connect to server" );
                return false;
        } else {
                return true;
        }
}

void
AcrobatReader::shutDownDde()
{
        // Terminate the DDE conversation
        DdeDisconnect( conversation );
        // Release the resources we acquired
        DdeFreeStringHandle( ddeId, serverName );
        DdeFreeStringHandle( ddeId, topicName );
}

bool
AcrobatReader::sendDdeMsg( std::string const & msg )
{
        bool success = false;
        // Check whether a viewer is running.
        // First try Acrobat Reader
        HWND viewer = FindWindow( NULL, _T("Adobe Reader") );
        if ( viewer == NULL ) {
                // Then try Acrobat Reader
                viewer = FindWindow( NULL, _T("Acrobat Reader") );
        }
        if ( viewer == NULL ) {
                // Then try Acrobat
                viewer = FindWindow( NULL, _T("Acrobat") );
        }
        if ( viewer == NULL ) {
                // Make sure it is started
                if ( startReader() ) {
                        // Nothing
                } else {
                        return false;
                }
        } else {
                // Make sure it is shown
                ::ShowWindow( viewer, SW_SHOW );
        }

        // Set up the DDE connection
        if ( setUpDde() ) {
                // Send the message
                if (
                        DdeClientTransaction(
                                (unsigned char *) msg.c_str(),
                                (DWORD) msg.length(),
                                conversation,
                                NULL,
                                0,
                                (UINT) XTYP_EXECUTE,
                                TIMEOUT_ASYNC,
                                NULL ) )
                {
                        success = true;
                }
                shutDownDde();
        }
        
        return success;
}

AcrobatReader::AcrobatReader( gstring const & an ) : 
        appName( an ),
        ddeId( 0 )
{
        // Make sure the process info is null
        ZeroMemory( & processInfo, sizeof( PROCESS_INFORMATION ) );

        /// Determine through the Registry whether Acrobat Reader is installed.

        // TODO: Is Acrobat (Reader) always named like this?
        TCHAR const * REG_INSTALL_KEY = 
_T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\AcroRd32.exe");
        TCHAR const * REG_INSTALL_KEY_ALT = 
_T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\Acrobat.exe");
        LONG retCode = ERROR_SUCCESS;
        HKEY hkey;
        // Try to find Acrobat Reader
        retCode = ::RegOpenKeyEx( HKEY_LOCAL_MACHINE, REG_INSTALL_KEY, 0, 
KEY_READ, & hkey );
        // If no Acrobat Reader, try to find First Acrobat
        if ( retCode != ERROR_SUCCESS ) {
                retCode = ::RegOpenKeyEx( HKEY_LOCAL_MACHINE, 
REG_INSTALL_KEY_ALT, 0, KEY_READ, & hkey );
        }
        if ( retCode == ERROR_SUCCESS ) {

                // Get the path to the Acrobat Reader executable.
                TCHAR buffer[ MAX_PATH ];
                DWORD size = MAX_PATH;

                retCode = RegQueryValueEx( hkey, _T(""), 0, 0, (LPBYTE) buffer, 
& size );
                if ( retCode == ERROR_SUCCESS ) {
                        RegCloseKey( hkey );
                        acrobatReaderExecutable = 
GString::multiByteFrom_t_str(buffer);
                }
        }

        // Catch all errors
        if ( retCode != ERROR_SUCCESS ) {
                std::cout << "Could not find Acrobat using registry key '" << 
                        REG_INSTALL_KEY << "', or '" << REG_INSTALL_KEY_ALT << 
"' : " << 
                        retCode << std::endl;
        }

        // Prepare for DDE communication
        if ( DdeInitialize( & ddeId, (PFNCALLBACK) & DDEMessageProc, 
APPCMD_CLIENTONLY, 0 ) != DMLERR_NO_ERROR ) {
                reportDdeError( "Failed to initialize DDE" );
        }
}

AcrobatReader::~AcrobatReader()
{
        // Close Acrobat Reader process and thread handles, if any
        if ( processInfo.hProcess != 0) {
                CloseHandle( processInfo.hProcess );
        }
        if ( processInfo.hThread != 0) {
                CloseHandle( processInfo.hThread );
        }
        // Release DDE handle
        if ( ddeId != 0) {
                DdeUninitialize( ddeId );
        }
}

namespace {
bool
getIsFile( std::string const & fileName )
{
    DWORD const attr = ::GetFileAttributes( fileName.c_str() );
        return 
                attr != INVALID_FILE_ATTRIBUTES && 
                ( attr & FILE_ATTRIBUTE_DIRECTORY ) != FILE_ATTRIBUTE_DIRECTORY;
}
}

void
AcrobatReader::openDoc( std::string const & filename )
{
        // Remember the file name
        file = filename;

        // Check whether the file exists
        if( !getIsFile( filename ) ) {
                std::string message = "File '" + filename + "' not found";
                MessageBox(
                        ::AfxGetMainWnd()->GetSafeHwnd(),
                        message.c_str(),
                        appName.c_str(),
                        MB_OK | MB_ICONINFORMATION
                );
                return;
        }
        
        // Make sure a file is not open already
        std::string cmd = "[DocClose(\"" + file + "\")]";
        sendDdeMsg( cmd );

        ::Sleep( 500 );
        
        // We have to Open a document before we can do anything with it
        cmd = "[DocOpen(\"" + file + "\")]";
        if ( ! sendDdeMsg( cmd ) ) {
                reportDdeError( "Cannot open " + file );
        } else {

        // If the pdf file is password protected then Adobe Reader might crash 
without this!
        // At least when the file is opened the second time
        // guess it resets some state or something....
                cmd = ( "[dummy(\"" + file + "\")]" );
                sendDdeMsg( cmd );
        }

}


namespace {
        
std::string
fromInt(int d, char const * spec) 
{
        enum { buffer_size = 50 };
        char buffer[ buffer_size ];
        _snprintf(buffer, buffer_size, spec, d );
        return buffer;
}

}

void
AcrobatReader::gotoPage( int page )
{
        // Construct the command to open the document
        std::string cmd ( "[DocGoTo(\"" + file + "\"," + fromInt( page, "%d" ) 
+ ")]" );
        if ( ! sendDdeMsg( cmd ) ) {
                reportDdeError( "Cannot goto page " + (fromInt( page, "%d" )) );
        }
}

void
AcrobatReader::gotoName( std::string const & name )
{
        // Construct the command to open the document
        std::string cmd ( "[DocGoToNameDest(\"" + file + "\"," + name + ")]" );
        if ( ! sendDdeMsg( cmd ) ) {
                reportDdeError( "Cannot goto destination " + name );
        }
}

Reply via email to