Introduction
This article is a simple how-to article on using the Adobe Acrobat 7 ActiveX control within a C++ application using MFC. The sample project included uses a minimal MDI MFC application to show that you can use multiple instances of the control within the same application. The code was kept simple and slim so that it focused more on the actual content. The source code and project file was written using Microsoft Visual C++ .NET 2003, but the code can easily be integrated into any version of Visual C++.
Background
Previous versions of Adobe Acrobat did not allow the ActiveX control to be used within an external application. According to the Acrobat Developer FAQ, the ActiveX control was only developed for use in the Microsoft Internet Explorer Web Browser and was not supported or licensed for use in any other application. With the release of Adobe Acrobat 7, the Acrobat Reader ActiveX control is now fully supported and documented, this gives application writers much more flexibility when distributing PDF files to customers. The PDFs that are opened with this control can also take advantage of the Acrobat JavaScript to communicate with each other just as they would if they were opened within a web page.
Using the code
The code is very simple and straightforward to use, it is mainly intended to show you how to import the control into your own application and not just for copying and pasting the code from the demo source. I chose to use a CWnd
as the view instead of a CFormView
for the demo project, this will help you understand how to create the control programmatically instead of just plopping it on a dialog from a toolbox.
The first step to using the Acrobat Reader 7 control is to create an MFC class from an ActiveX control using the Class Wizard. While in the Class View tab, right click on your project and select "Add->Add Class..." and choose the option "MFC Class From ActiveX".
Now click "Open" and a new dialog will appear. Under the section labeled "Available ActiveX Controls", find and select the "Adobe Acrobat 7.0 Browser Document <1.0>" control from the combo box. The interface "IAcroAXDocShim
" will appear in the list of interfaces. Select the interface and click the ">" arrow to add a class for it. The wizard will then create the class CAcroAXDocShim
and add it to your project.
You are almost finished, now you just need to use this generated class in your own window. Add a member variable in your window view class that is of type "CAcroAXDocShim
":
#include "CAcroAXDocShim.h"
class CAcroViewer : public CWnd
{
public:
...
private:
CAcroAXDocShim m_ctrl;
};
Now that you have added the variable, you just need to create it and use it to open PDF Files. To create it, first create a control ID, which is just an integer that is not currently being used by another control in your application. Now, at the end of your window's OnCreate
handler, you call the control's Create
function. The first parameter needed is a string for the window name, you can use anything for this value, I chose "AdobeWnd
". The next parameter is the window style, you need WS_CHILD
to make it a child and WS_VISIBLE
to make it visible. Next is a RECT
for the window position, I used all 0's because I made a WM_SIZE
handler to resize the control when the window is resized. The next parameters are the window parent (this
), and the control ID that was created.
const int CTRL_ID = 280;
int CAcroViewer::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CWnd::OnCreate(lpCreateStruct) == -1)
return -1;
if (!m_ctrl.Create("AdobeWnd", WS_CHILD | WS_VISIBLE,
CRect(0, 0, 0, 0), this, CTRL_ID))
{
AfxMessageBox("Failed to create adobe wnd");
return -1;
}
return 0;
}
The ActiveX control is now created and visible in your application. The only problem now is that its size is 0. To fix this we add a WM_SIZE
handler to the window and resize the control to match the window's client rect. We must make sure that the window is valid first by calling IsWindow(m_hWnd)
. After this call we just simply call GetClientRect()
and pass that rect to MoveWindow()
for our control.
void CAcroViewer::OnSize(UINT nType, int cx, int cy)
{
CWnd::OnSize(nType, cx, cy);
if (IsWindow(m_hWnd))
{
CRect rc;
GetClientRect(rc);
m_ctrl.MoveWindow(rc);
}
}
The only thing left now is to open a PDF file. This can be done with one simple call to LoadFile
on the control. The file
parameter can be either a file on the local file system or a URL to a file on an HTTP server.
void CAcroViewer::Open(const char *file)
{
m_ctrl.LoadFile(file);
}
Points of interest
Unfortunately, even though this control is now outside of the Microsoft Internet Explorer Browser, it still seems to suffer from the bugs that it has had in all other versions of the Acrobat Reader. Occasionally it seems necessary to open up Task Manager and "End Task" the "AcroRd32.exe" application to get things work properly again. It's not a problem related to this application, it's a problem with the control itself. When opening and closing several PDF files from within Internet Explorer, you occasionally run into a problem where the PDF viewer just freezes. I was hoping that Adobe would have fixed this bug with the release of Acrobat Reader 7, but it appears to be still there.
Conclusion
I hope that this article has helped those of you who want to use PDF files within your own applications and only have the Acrobat Reader. If you have the full version of Adobe Acrobat, there are many other options open to you for using PDF files within your own applications, such as OLE automation. I have worked pretty extensively with OLE automation of Acrobat within C++ and C# applications and it is a much better approach in most cases but is limited to Acrobat Professional and not supported on systems that only have the Acrobat Reader installed.