BCL easyPDF SDK
easyPDF SDK Usermanual
PDF Creator Programming API  |  Download Free Trial  |  Contact Us to Purchase

Native C Printer API

Getting Help

The C API is inherently very large and obscure. However, the objects and the methods are all similar to the C# and COM APIs.

If you are just starting with easyPDF SDK, consider using C#, VB, PHP or Python for your initial testing and prototyping. You will be up to speed much quicker.

If you are ready to dive into C/C++, we recommend that you study the header file located at c:\Program Files\Common Files\BCL Technologies\easyPDF 8\include\easyPDFPrinter.h.

If you have any questions, please don't hesitate to submit a support ticket.

Usage

The native C API is very similar to the COM API, with a few distinct differences.

Objects are implemented as C structures, and member functions and properties are achieved via function pointers inside each structure. This allows for a syntax that is very close to C++ classes.

According to our naming convention, all easyPDF macros and enumerations begin with BCL_, and all global functions and types begin with Bcl. Therefore the Printer class is really called BclPrinter.

easyPDFPrinter.dll exports only a single function called BclNewPrinter, which is responsible for creating a new BclPrinter object. All other functions and properties are called via the BclPrinter object.

The BclNewPrinter function has the following prototype:

struct BclPrinter* BclNewPrinter(const BclLoaderSettings* init);

The input argument is a pointer to the Loader settings. Feel free to pass a NULL pointer for the default settings, unless your application is a server or a service, which we will discuss separately.

The pointer returned by BclNewPrinter must be explicitly deleted using the Dispose method:

BclPrinter* pPrinter = BclNewPrinter(NULL);
if(!pPrinter)
   goto Error;
...
pPrinter->Dispose(pPrinter);

You may call a method just like in C++, except the first argument is always the pPrinter pointer itself. pPrinter->Dispose is a function pointer to the method, and the first parameter in nearly every method is the BclPrinter pointer. This is similar to self in Python, and this in PHP, C# and C++. Even in C++, you must explicitly pass this parameter. In other words, a method that has no parameters still has a single argument, the pPrinter pointer.

Properties are accessed via getter and setter functions. For example, here is how to get the LibraryVersionMajor property:

int versionMajor;
BclPrnResult error = pPrinter->GetLibraryVersionMajor(pPrinter, &versionMajor);
if(error)
   goto Error;

Almost every method returns an error result type called BclPrnResult. The actual return value of the function is retrieved via a pointer, just like in COM.

Error handling must be implemented for each individual method call. If there is no error, the return value is BCL_PRN_R_SUCCESS, which has a value of 0. All errors have a negative value.

Note that a few properties are implemented as member variables, as opposed to member functions. Most importantly, all the PrintJob pointers are plain old pointers, so are BclPrinter::PrinterSetting, BclPrintJob::PDFSetting and BclPrinter::PrintJobMonitor.

For example, here is how to obtain the PrintJob from Printer:

BclPrintJob* pPrintJob = pPrinter->PrintJob;

In other words, these member classes are always available, because they are automatically allocated by BclNewPrinter.

Now that we have a PrintJob pointer, we can set the FileConversionTimeout property:

error = pPrintJob->SetFileConversionTimeout(pPrinter, 60000); // 60 seconds
if(error)
   goto Error;

Note how we are passing the pPrinter even to PrintJob methods.

And finally, we are ready to perform the actual printing:

error = pPrintJob->PrintOut(pPrinter, L"c:\\test\\input.doc", L"c:\\test\\output.pdf");
if(error)
   goto Error;

If you are programming in C++, feel free to translate errors into your own exceptions:

if(error)
   throw std::runtime_error(pPrinter->PrnResultToAscii(error));

PrnResultToAscii and PrnResultToString are two of the few functions that don't follow the regular method calling convention. They take a single BclPrnResult input, and return a human-readable error message. PrnResultToAscii returns const char*, while PrnResultToString returns const wchar_t*. Never deallocate these strings, because they are static constants!

Memory Management

With the exception of the BclPrinter pointer returned by BclNewPrinter, memory management is completely automatic. You are not required to manually deallocate any pointer returned by the SDK, with the exception of pPrinter itself, whose Dispose method must be called explicitly. Failure to properly dispose Printer will cause the SDK to stay in memory indefinitely, until your application quits. This can be a huge burden, especially when BclNewPrinter is called repeatedly without properly disposing of the pointer.

The good news is that easyPDF internally keeps track of all pointers that it allocates, and Dispose automatically takes care of all the deallocations. Most people will never have to worry about deallocating individual pointers other than pPrinter.

There are two notable exceptions:

  1. If you are calling a very large number of functions that return strings or memory buffers, without calling Dispose in between.
  2. If you are calling PrintOut2 or PrintOut3, which return potentially very large memory buffers, without calling Dispose shortly thereafter.

Strings and memory streams allocated by the SDK may be explicitly deallocated using the BclPrinter::ReleasePtr method, which has the following prototype:

void ReleasePtr(struct BclPrinter* pPrinter, void* p);

The first parameter is the pPrinter that was used to allocate the string or buffer. The second parameter is the pointer to be deallocated. If you have multiple pPrinter pointers alive, it is essential to pass the one which did the allocation, because each BclPrinter object has a completely independent memory manager. Whatever memory was not deallocated via ReleasePtr will be deallocated by Dispose. Obviously, after the Dispose method is called, all related SDK pointers become invalid and unusable.

Never call ReleasePtr on pPrinter itself! pPrinter must be deallocated using Dispose, all other strings and buffer must be deallocated using ReleasePtr, or not deallocated at all. Never call free(), delete, VirtualFree or other operating system functions on SDK pointers!

Also note that all pointers returned by the SDK point to constant memory and must not be modified. For example, strings returned are constant. If you need to modify them, make your own copy, and apply the modifications there.

Notification Events

Notification callbacks are implemented via function pointers:

typedef BclPrnMonitorResponse (*BclPrintJobMonitor_OnPrinterInitPtr)(void* CallbackUser, int uID, PrintJobInfo* info);
typedef BclPrnMonitorResponse (*BclPrintJobMonitor_OnPrinterUpdatePtr)(void* CallbackUser, int uID, PrintJobInfo* info);
typedef BclPrnMonitorResponse (*BclPrintJobMonitor_OnPrinterStartPtr)(void* CallbackUser, int uID);
typedef BclPrnMonitorResponse (*BclPrintJobMonitor_OnPageStartPtr)(void* CallbackUser, int uID, int pageNumber);
typedef BclPrnMonitorResponse (*BclPrintJobMonitor_OnPrinterEndPtr)(void* CallbackUser, int uID, BclPrnResult result);

The first parameter is always a void* pointer, where you can pass your own data to the callback.

Here is how you would set up printing with callback:

pPrinter->PrintJobMonitor->CallbackUser = CallbackUser;
pPrinter->PrintJobMonitor->OnPageStart = UserPageStart;
pPrinter->PrintJob->PrintOut(pPrinter, L"c:\\test\\input.doc", L"c:\\test\\output.pdf");

Then you would create a global function to handle the callback:

// Per-page printer callback
BclPrnMonitorResponse UserPageStart(void* CallbackUser, int uID, int pageNumber)
{
        printf("Starting page %d...\n", pageNumber + 1);
        return BCL_PRN_MON_CONTINUE_CONVERSION;
}

CallbackUser is usually a pointer to the customer's own object. This is the only way for the callback function to reference the main application object in a thread-safe way. In extremely simple cases, like the example above, CallbackUser can be NULL.

Launch Timeout

Launching the worker process and connecting the named pipe should happen very fast, in milliseconds. However, under an abnormally heavy load, the computer may not have enough cycles to perform this task in a timely fashion.

The Native C API has an internal timeout built-in. The default value is 1 minute. This is because a server may momentarily slow down so much that it is not responding for seconds, but it usually recovers after a while.

The default timeout value can be changed via BclLoaderSettings::LaunchTimeout (in milliseconds). This can be done by passing BclLoaderSettings to BclNewPrinter:

BclLoaderSettings loaderSettings = { 0 };
loaderSettings.LaunchTimeout = 60000; // 1 minute
BclPrinter* printer = BclNewPrinter(&loaderSettings);

loaderSettings cannot be changed after pPrinter is created.

Upon timeout, BclNewPrinter returns a NULL pointer, and the SDK cannot be used. Another attempt may be made later.

Server-Side Operation

Printing from the server side has always required easyPDF Loader, a special service that helps execute functions under a different user account.

The Native C SDK offers two possible solutions for server-side printing. One is called the Loader Service, and the other one is called Impersonation.

Customers who are printing from a web server or a system service should study both alternatives, and decide which one they prefer.

By default, the Loader Service is used automatically when easyPDF Printer deems necessary. However, the customer is still responsible for setting up and configuring the Loader Service properly.

To use Impersonation, create a BclLoaderSettings object, set UserName and Password, then pass it to BclNewPrinter:

BclLoaderSettings loaderSettings = { 0 };
loaderSettings.UserName = L"easyPDF8User";
loaderSettings.Password = L"your actual password here";
BclPrinter* pPrinter = BclNewPrinter(&loaderSettings);

PrinterMonitor

PrinterMonitor does not exist in the native C API at this moment.

Note that most customers do not need PrinterMonitor. Its sole purpose is to enable File > Print in a desktop environment. It was not designed for server-side operation anyway.

If you just want to get notification events while printing, please use PrintJobMonitor, which is part of the native C API.

If you really need PrinterMonitor, it is still available in the COM API.