More languages
Some test text!
More languages
Sample C++ code for using PDFTron SDK's PDF viewer control in a basic project. This sample uses a number of built-in features from PDFViewCtrl to open PDF files, implement document navigation, text highlighting, markup, and editing. If you are looking for a sample showing how to further customize the viewer (e.g. by implementing custom tools or custom GUI elements), please take a look at the PDFView sample code. Learn more about our C++ PDF Library and PDF Viewer SDK.
Get Started Samples DownloadTo run this sample, get started with a free trial of Apryse SDK.
//---------------------------------------------------------------------------------------
// Copyright (c) 2001-2021 by PDFTron Systems Inc. All Rights Reserved.
// Consult legal.txt regarding legal and license information.
//---------------------------------------------------------------------------------------
// This sample shows how to add PDF viewer control in a basic Win32 project.
// The sample uses a number of built-in features from PDFViewCtrl to implement
// document navigation, text highlighting, markup, and editing.
//
// PDFViewCtrl offers built-in support for a number of PDF tools (including markup,
// link creation, forms, text selection, etc) and user interface elements (such as
// navigation panel, find text, etc). PDFViewCtrl is highly configurable allowing
// users to implement custom tools or to modify behavior of built-in tools.
// Default user interface elements such as the navigation panel can be replaced
// with a custom implementation and users can override window events and various
// document actions. For example, by default, PDFViewCtrl will launch URL links
// in a web browser and will jump to a destination for 'GoTo' actions. The default
// behavior can be overridden using a custom callback function (as shown in the
// following sample).
//
// Besides PDFViewCtrl, the C++ version of PDFNet SDK also includes a low-level class
// called PDFView. Because PDFView does not process any window messages and does not
// implement built-in tools it is only suitable for very low-level control development
// (e.g. if you would like to implement a control similar to PDFViewCtrl from scratch).
// The basic use of PDFView is illustrated in PDFView sample project.
//---------------------------------------------------------------------------------------
#include "stdafx.h"
#include "resource.h"
#include <Common/Exception.h>
#include <commdlg.h>
#include <cassert>
#include <PDF/PDFViewCtrl.h>
#include <PDF/PDFDraw.h>
#include <PDF/PDFNet.h>
#include <stdlib.h>
#include <iostream>
#include <utility>
#include <algorithm>
#include <memory>
#include "../../LicenseKey/CPP/LicenseKey.h"
using namespace pdftron;
using namespace PDF;
#define MAX_LOADSTRING 100
// Global Variables:
HINSTANCE hInst; // current instance
TCHAR szTitle[MAX_LOADSTRING]; // The title bar text
TCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name
UString m_doc_name;
std::auto_ptr<PDF::PDFDoc> mp_doc;
std::auto_ptr<PDF::PDFViewCtrl> m_view;
// Forward declarations of functions included in this code module:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
int APIENTRY _tWinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
// TODO: Place code here.
MSG msg;
HACCEL hAccelTable;
// Initialize global strings
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_PDFVIEWSIMPLE, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
// Perform application initialization:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_PDFVIEWSIMPLE));
// Main message loop:
while (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int) msg.wParam;
}
//
// FUNCTION: MyRegisterClass()
//
// PURPOSE: Registers the window class.
//
// COMMENTS:
//
// This function and its usage are only necessary if you want this code
// to be compatible with Win32 systems prior to the 'RegisterClassEx'
// function that was added to Windows 95. It is important to call this function
// so that the application will get 'well formed' small icons associated
// with it.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_PDFVIEWSIMPLE));
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = MAKEINTRESOURCE(IDC_PDFVIEWSIMPLE);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
return RegisterClassEx(&wcex);
}
typedef std::pair< int, PDF::PDFViewCtrl::ToolMode > ToolModeMapType;
const ToolModeMapType toolModeMap[] = {
ToolModeMapType( IDM_TOOL_PAN , PDF::PDFViewCtrl::e_pan ),
ToolModeMapType( IDM_TOOL_STRUCTURALSELECTION , PDF::PDFViewCtrl::e_text_struct_select ),
ToolModeMapType( IDM_TOOL_RECTANGLESELECTION , PDF::PDFViewCtrl::e_text_rect_select ),
ToolModeMapType( IDM_TOOL_RECTANGLEZOOMIN , PDF::PDFViewCtrl::e_zoom_in ),
ToolModeMapType( IDM_TOOL_RECTANGLEZOOMOUT , PDF::PDFViewCtrl::e_zoom_out ),
ToolModeMapType( IDM_TOOL_ANNOTATIONEDITING , PDF::PDFViewCtrl::e_annot_edit ),
ToolModeMapType( IDM_TOOL_TEXTANNOTCREATION , PDF::PDFViewCtrl::e_text_annot_create ),
ToolModeMapType( IDM_TOOL_LINECREATION , PDF::PDFViewCtrl::e_line_create ),
ToolModeMapType( IDM_TOOL_ARROWCREATION , PDF::PDFViewCtrl::e_arrow_create ),
ToolModeMapType( IDM_TOOL_RECTANGLECREATION , PDF::PDFViewCtrl::e_rect_create ),
ToolModeMapType( IDM_TOOL_OVALCREATION , PDF::PDFViewCtrl::e_oval_create ),
ToolModeMapType( IDM_TOOL_FREEHANDTOOL , PDF::PDFViewCtrl::e_ink_create ),
ToolModeMapType( IDM_TOOL_STAMPCREATIONTOOL , PDF::PDFViewCtrl::e_stamp_create ),
ToolModeMapType( ID_TOOL_HIGHLIGHTTOOL , PDF::PDFViewCtrl::e_highlight_create ),
ToolModeMapType( ID_TOOL_UNDERLINETOOL , PDF::PDFViewCtrl::e_underline_create ),
ToolModeMapType( ID_TOOL_STRIKEOUTTOOL , PDF::PDFViewCtrl::e_strikeout_create ),
ToolModeMapType( ID_TOOL_SQUIGGLYUNDERLINETOOL , PDF::PDFViewCtrl::e_squiggly_create ),
ToolModeMapType( ID_TOOL_CALLOUTTEXTBOXTOOL , PDF::PDFViewCtrl::e_calloutbox_create ),
ToolModeMapType( ID_TOOL_SIMPLETEXTBOXTOOL , PDF::PDFViewCtrl::e_text_box_create ),
ToolModeMapType( ID_TOOL_POLYGONTOOL , PDF::PDFViewCtrl::e_polygon_create ),
ToolModeMapType( ID_TOOL_POLYLINETOOL , PDF::PDFViewCtrl::e_polyline_create ),
ToolModeMapType( ID_TOOL_FILEATTACHMENTTOOL , PDF::PDFViewCtrl::e_file_attachment ),
ToolModeMapType( ID_TOOL_SOUNDATTACHMENTTOOL , PDF::PDFViewCtrl::e_sound_attachment ),
ToolModeMapType( ID_TOOL_MOVIEINSERTIONTOOL , PDF::PDFViewCtrl::e_movie_attachment ),
ToolModeMapType( ID_TOOL_CARETPLACEMENTTOOL , PDF::PDFViewCtrl::e_caret_create ),
ToolModeMapType( ID_TOOL_REDACTIONTOOL , PDF::PDFViewCtrl::e_redaction_create ),
ToolModeMapType( ID_TOOL_TEXTFIELDCREATION , PDF::PDFViewCtrl::e_text_field_create ),
ToolModeMapType( ID_TOOL_CHECKBOXCREATIONTOOL , PDF::PDFViewCtrl::e_check_box_create ),
ToolModeMapType( ID_TOOL_RADIOBUTTON , PDF::PDFViewCtrl::e_radio_button_create ),
ToolModeMapType( ID_TOOL_LISTBOX , PDF::PDFViewCtrl::e_list_box_create ),
ToolModeMapType( ID_TOOL_COMBOBOX , PDF::PDFViewCtrl::e_combo_box_create ),
ToolModeMapType( ID_TOOL_BUTTONCREATIONTOOL , PDF::PDFViewCtrl::e_button_create )
};
const ToolModeMapType* const toolModeMapEnd = toolModeMap + sizeof(toolModeMap)/sizeof(ToolModeMapType);
struct ToolModePred {
int m_code;
ToolModePred( int c ) : m_code(c) {}
bool operator()( ToolModeMapType tp ) { return tp.first == m_code; }
};
// FUNCTION: InitInstance(HINSTANCE, int)
//
// PURPOSE: Saves instance handle and creates main window
//
// COMMENTS:
//
// In this function, we save the instance handle in a global variable and
// create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
PDFNet::Initialize(LicenseKey);
// PDFNet::SetColorManagement();
HWND hWnd;
hInst = hInstance; // Store instance handle in our global variable
hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
if (!hWnd)
{
return FALSE;
}
ShowWindow(hWnd, nCmdShow);
// Optional: PDFViewCtrl can save its UI state across different sessions.
// In this case the config file is save in the current working folder.
//m_view->LoadCurrentConfiguration( "my.cfg" );
UpdateWindow(hWnd);
return TRUE;
}
void ErrorCallback(const char* message, void* custom_data)
{
static bool reported_once = false;
if (!reported_once) {
reported_once = true;
HWND hwnd = (HWND) custom_data; // Case custom data to the expected argument.
::MessageBoxA(hwnd, message, "Error", MB_OK);
}
}
void DownloadCallback(DownloadedType type, PDFDoc* doc, int page_num, int obj_num, const char* message, void* custom_data)
{
switch(type)
{
case PDF::e_downloadedtype_opened :
// e_opened indicates that we have a valid, but incomplete PDFDoc.
// the PDF should be treated as read only, and only simple functions
// should be called on the doc, until e_finished has been called.
break;
case PDF::e_downloadedtype_page :
// this indicates the entire page is downloaded and it is safe to modify
// for example add a new annotation
break;
case PDF::e_downloadedtype_finished :
{
// we now have the full PDF file and it can be treated like any other
HWND hwnd = (HWND) custom_data; // Case custom data to the expected argument.
if(::MessageBoxA(hwnd, "Download complete, would you like to save the PDF locally?",
"PDF Downloaded", MB_YESNO)==IDYES)
{
::PostMessage(hwnd, WM_COMMAND, MAKELONG(IDM_FILE_SAVEAS,0), 0);
}
}
break;
case PDF::e_downloadedtype_failed :
{
// downloading has stopped if this occurs
HWND hwnd = (HWND) custom_data; // Case custom data to the expected argument.
::MessageBoxA(hwnd, message, "Error", MB_OK);
}
break;
}
}
TRN_Bool MyActionHandler( TRN_Action act, void* custom_data )
{
Action action(act);
if (!action.IsValid()) return 1;
HWND hwnd = (HWND) custom_data; // Case custom data to the expected argument.
Action::Type type = action.GetType();
if (type == Action::e_GoTo)
{
Destination dest = action.GetDest();
if (!dest.IsValid()) {
MessageBoxA(hwnd, "Destination is not valid", "MyURLActionHandler", MB_OK | MB_ICONEXCLAMATION);
}
else {
int page_num = dest.GetPage().GetIndex();
char buf[256];
sprintf(buf, " Links to: page number %d in this document", page_num);
MessageBoxA(hwnd, buf, "MyURLActionHandler", MB_OK | MB_ICONEXCLAMATION);
return 0; // -> execute the default action handler.
}
}
else if (type == Action::e_URI)
{
UString uri;
action.GetSDFObj().Get("URI").Value().GetAsPDFText(uri);
char buf[256];
sprintf(buf, " Links to: %s", uri.ConvertToAscii().c_str());
MessageBoxA(hwnd, buf, "MyURLActionHandler", MB_OK);
}
else
{
MessageBoxA(hwnd, "Other Action Type -> Handled by PDFViewCtrl", "MyURLActionHandler", MB_OK);
return 0; // -> execute the default action handler.
}
// If this function returns true, PDFViewCtrl will not execute the default
// action internally (in case of URL the default action is to open the URL
// link in a web browser).
return 1;
}
TRN_Bool MyMouseDoubleClickEvent( PDFViewCtrl::MouseEvent* evt, void* custom_data)
{
if (!evt->m_pdfviewctrl_processed) // Display the message box before the message is processed by PDFNet?
{
HWND hwnd = (HWND) custom_data; // Case custom data to the expected argument.
MessageBoxA(hwnd, "Example of a custom event", "MyMouseDoubleClickEvent", MB_OK);
return false; // execute built-in event. To skip event processing in PDFViewCtrl return true.
}
return false;
}
BOOL OpenURLProc(HWND hDlg, UINT iMessage, WPARAM wParam, LPARAM lParam)
{
switch( iMessage ){
case WM_COMMAND:
switch( LOWORD( wParam ) ){
case IDOK :
{
char url[MAX_PATH];
char pass[MAX_PATH];
GetDlgItemTextA(hDlg, IDC_OPENURL_URL, url, MAX_PATH);
GetDlgItemTextA(hDlg, IDC_OPENURL_PASSWORD, pass, MAX_PATH);
m_view->CloseDoc();
mp_doc.reset();
// Open a PDF file at the given url. This works best with PDF's that
// are linearized, as pages can be downloaded and viewed in random access order,
// without the need to download the entire document. A viewing session can also be
// persisted across multiple viewing/application sessions to remove redundant downloads
// and improve overall performance by using the optional cache_file parameter.
m_view->OpenURLAsync(&url[0], "", &pass[0]);
// IMPORTANT: PDFViewCtrl 'owns' downloaded documents, so don't take
// ownership of the document (mp_doc == null)
}
// fall through
case IDCANCEL:
EndDialog(hDlg, wParam);
return TRUE;
}
break;
}
return FALSE;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
static HMENU hMenu ;
switch (message)
{
case WM_CREATE:
{
m_view = std::auto_ptr<pdftron::PDF::PDFViewCtrl>(new pdftron::PDF::PDFViewCtrl(hWnd, hInst));
hMenu = LoadMenu (hInst, MAKEINTRESOURCE(IDC_PDFVIEWSIMPLE));
hMenu = GetSubMenu (hMenu, 0);
// m_view->SetProgressiveRendering(false);
// m_view->SetPageBorderVisibility(false);
// m_view->SetPageSpacing(0, 0, 0, 0);
// m_view->SetDefaultPageColor(255, 255, 255);
// m_view->ShowNavPanel(true);
// m_view->ShowNavToolbar(true);
// m_view->SetAntiAliasing( true );
// m_view->SetGamma(0.01);
m_view->SetErrorReportHandler(ErrorCallback, hWnd);
m_view->SetActionHandler(MyActionHandler, hWnd);
m_view->SetDownloadReportHandler(DownloadCallback, hWnd);
PDFViewCtrl::EventHandlers my_handlers;
my_handlers.mouse_left_dclick = MyMouseDoubleClickEvent;
my_handlers.custom_data = hWnd;
m_view->SetCustomEventHandlers( &my_handlers );
}
break;
case WM_COMMAND:
{
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
const ToolModeMapType* const wmId_it = std::find_if( toolModeMap, toolModeMapEnd, ToolModePred(wmId) );
if( wmId_it != toolModeMapEnd )
m_view->SetToolMode( wmId_it->second );
else {
switch (wmId)
{
case IDM_ABOUT:
// DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
case IDM_FILE_PRINT:
{
if(m_view->GetDoc())
m_view->Print();
}
break;
case IDM_FILE_SAVEAS:
{
if(m_view->GetDoc())
{
TCHAR szFile[256] = { 0 };
TCHAR *szFilter =TEXT("PDF Files (*.pdf)\0")
TEXT("*.pdf\0")
TEXT("All Files\0")
TEXT("*.*\0");
OPENFILENAME ofn;
ZeroMemory(&ofn, sizeof(OPENFILENAME));
ofn.lStructSize=sizeof(OPENFILENAME);
ofn.lpstrFilter=szFilter;
ofn.nFilterIndex=1;
ofn.lpstrFile=szFile;
ofn.nMaxFile=sizeof(szFile);
ofn.lpstrTitle=_T("Save PDF File");
ofn.nMaxFileTitle=sizeof(ofn.lpstrFile);
//===Start the File Dialog
if(GetSaveFileName(&ofn))
{
m_view->GetDoc()->Save(UString(ofn.lpstrFile), SDF::SDFDoc::e_linearized, 0);
}
}
}
break;
case IDM_FILE_SAVE:
{
if(m_view->GetDoc())
{
if(m_view->GetDoc())
{
m_view->GetDoc()->Save(m_doc_name, SDF::SDFDoc::e_remove_unused, 0);
}
}
}
break;
case IDM_FILE_OPEN:
{
//===File path
TCHAR szFile[256] = { 0 };
//===Filter
TCHAR *szFilter =TEXT("PDF Files (*.pdf)\0")
TEXT("*.pdf\0")
TEXT("All Files\0")
TEXT("*.*\0");
OPENFILENAME ofn;
ZeroMemory(&ofn, sizeof(OPENFILENAME));
ofn.lStructSize=sizeof(OPENFILENAME);
ofn.lpstrFilter=szFilter;
ofn.nFilterIndex=1;
ofn.lpstrFile=szFile;
ofn.nMaxFile=sizeof(szFile);
ofn.lpstrTitle=_T("Open PDF File");
ofn.nMaxFileTitle=sizeof(ofn.lpstrFile);
//===Start the File Dialog
if(GetOpenFileName(&ofn))
{
m_doc_name=UString(ofn.lpstrFile);
try{
std::auto_ptr<PDF::PDFDoc> doc(new PDF::PDFDoc(m_doc_name));
if(m_view->SetDoc(*doc))
{
mp_doc=doc;
// m_view->ShowNavPanel(true);
// m_view->ShowNavToolbar(true);
}
}
catch(...)
{
::MessageBoxA(hWnd,"An error occurred while opening a file","PDFViewSimple Error",MB_OK);
}
}
}
break;
case IDM_FILE_OPENURL:
{
::DialogBox(hInst, MAKEINTRESOURCE(IDD_OPENURL), hWnd, DLGPROC(OpenURLProc));
}
break;
case IDM_PAGELAYOUT_SINGLEPAGE:
{
m_view->SetPagePresentationMode(PDF::PDFViewCtrl::e_single_page);
}
break;
case IDM_PAGELAYOUT_SINGLECONTINUOUS:
{
if(m_view->GetDoc())
{
m_view->SetPagePresentationMode(PDF::PDFViewCtrl::e_single_continuous);
}
}
break;
case IDM_PAGELAYOUT_FACING:
{
m_view->SetPagePresentationMode(PDF::PDFViewCtrl::e_facing);
}
break;
case IDM_PAGELAYOUT_FACINGCONTINUOUS:
{
if(m_view->GetDoc())
{
m_view->SetPagePresentationMode(PDF::PDFViewCtrl::e_facing_continuous);
}
}
break;
case IDM_PAGELAYOUT_FACING_COVER:
{
if(m_view->GetDoc())
{
m_view->SetPagePresentationMode(PDF::PDFViewCtrl::e_facing_cover);
}
}
break;
case IDM_PAGELAYOUT_FACINGCONTINUOUS_COVER:
{
if(m_view->GetDoc())
{
m_view->SetPagePresentationMode(PDF::PDFViewCtrl::e_facing_continuous_cover);
}
}
break;
case IDM_PAGEVIEWMODE_FITPAGE:
{
m_view->SetPageViewMode(PDF::PDFViewCtrl::e_fit_page);
}
break;
case IDM_PAGEVIEWMODE_FITWIDTH:
{
m_view->SetPageViewMode(PDF::PDFViewCtrl::e_fit_width);
}
break;
case IDM_VIEW_ZOOMIN:
{
if(m_view->GetDoc())
{
m_view->SetZoom(m_view->GetZoom()*2);
}
}
break;
case IDM_VIEW_ZOOMOUT:
{
if(m_view->GetDoc())
{
m_view->SetZoom(m_view->GetZoom()/2);
}
}
break;
case IDM_PAGENAVIGATION_GOTONEXTPAGE:
{
if(m_view->GetDoc())
{
m_view->GotoNextPage();
}
}
break;
case IDM_PAGENAVIGATION_GOTOPREVIOUSPAGE:
{
if(m_view->GetDoc())
{
m_view->GotoPreviousPage();
}
}
break;
case IDM_PAGENAVIGATION_GOT:
{
if(m_view->GetDoc())
{
m_view->GotoLastPage();
}
}
break;
case IDM_PAGENAVIGATION_GOTOFIRSTPAGE:
{
if(m_view->GetDoc())
{
m_view->GotoFirstPage();
}
}
break;
case IDM_EDIT_COPY:
{
if(m_view->GetDoc())
{
m_view->Copy();
}
}
break;
case IDM_EDIT_FIND:
{
if(m_view->GetDoc())
{
m_view->Find();
}
}
break;
case IDM_EDIT_SELECTALL:
{
if(m_view->GetDoc())
{
m_view->SelectAll();
}
}
break;
case ID_TOGGLE_NAV_PANEL:
m_view->ShowNavPanel(!m_view->IsNavPanelVisible());
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
}
break;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code here...
EndPaint(hWnd, &ps);
break;
case WM_CLOSE:
//m_view->SaveCurrentConfiguration("my.cfg");
m_view.reset();
DestroyWindow(hWnd);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_SIZE:
// this is never getting called, wxWidgets handles these events internally
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
// Message handler for about box.
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
switch (message)
{
case WM_INITDIALOG:
return (INT_PTR)TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, LOWORD(wParam));
return (INT_PTR)TRUE;
}
break;
}
return (INT_PTR)FALSE;
}