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

Native C PDFConverter 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\easyPDFConverter.h.

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


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 PDFConverter class is really called BclPDFConverter.

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

The BclNewPDFConverter function has the following prototype:

struct BclPDFConverter* BclNewPDFConverter(const BclLoaderSettings* init);

The input argument is a pointer to the Loader settings. Feel free to pass a NULL pointer for the default settings.

The pointer returned by BclNewPDFConverter must be explicitly deleted using the Dispose method.

We prefer to wrap BclNewPDFConverter into CreatePDFConverter, like this:

// Create a new BclPDFConverter object
// hDll: [in] handle returned by LoadEasyPDFConverterDLL
// returns a new BclPDFConverter pointer. Result must be deleted using pPDFConverter->Dispose(pPDFConverter);
static BclPDFConverter* CreatePDFConverter(HMODULE hDll)
      typedef BclPDFConverter* (*BclNewPDFConverterPtr)(const BclLoaderSettings*);
      BclNewPDFConverterPtr ptrBclNewPDFConverter = (BclNewPDFConverterPtr)GetProcAddress(hDll, "BclNewPDFConverter");
      return ptrBclNewPDFConverter(NULL);
      return NULL;

It is now very easy to use the PDFConverter SDK:

BclPDFConverter* pConverter = CreatePDFConverter(hConverterDll);
   goto Error;

You may call a method just like in C++, except the first argument is always the pConverter pointer itself. pConverter->Dispose is a function pointer to the method, and the first parameter in nearly every method is the BclPDFConverter 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 pConverter pointer.

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

int versionMajor;
BclCnvResult error = pConverter->GetLibraryVersionMajor(pConverter, &versionMajor);
   goto Error;

Almost every method returns an error result type called BclCnvResult. 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_CNV_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, PDF2Image is a plain old pointer.

For example, here is how to obtain the PDF2Image from pConverter:

BclPDF2Image* pPDF2Image = pConverter->PDF2Image;

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

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

error = pPDF2Image->SetFileConversionTimeout(pConverter, 60000); // 60 seconds
   goto Error;

Note how we are passing the pConverter even to PDF2Image methods.

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

error = pPDF2Image->Convert(pConverter, L"c:\\test\\input.pdf", L"c:\\test\\output.tif", L"", -1, -1);
   goto Error;

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

   throw std::runtime_error(pConverter->CnvResultToAscii(error));

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

Memory Management

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

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 pConverter.

There is one notable exception: If you are calling a very large number of functions that return strings or memory buffers, without calling Dispose in between.

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

void ReleasePtr(struct BclPDFConverter* pConverter, void* p);

The first parameter is the pConverter that was used to allocate the string or buffer. The second parameter is the pointer to be deallocated. If you have multiple pConverter pointers alive, it is essential to pass the one which did the allocation, because each BclPDFConverter 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 pConverter itself! pConverter 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.

C++ Exception Safety

If you are using the C API from C++, it is wise to wrap BclPDFConverter pointers into your own C++ smart pointer class. We recommend the following implementation:

class SafePDFConverter
   explicit SafePDFConverter(BclPDFConverter* a_pPDFConverter) : pPDFConverter(a_pPDFConverter) { }
   ~SafePDFConverter() { if(pPDFConverter) pPDFConverter->Dispose(pPDFConverter); }
   operator BclPDFConverter*() const { return pPDFConverter; }
   BclPDFConverter* operator->() const { return pPDFConverter; }
   BclPDFConverter* pPDFConverter;
   SafePDFConverter(const SafePDFConverter&); // copy disabled!
   SafePDFConverter& operator=(const SafePDFConverter&); // copy disabled!

Here is how you would use this:

SafePDFConverter pConverter(CreatePDFConverter(hConverterDll));
if(pConverter == NULL)
   throw std::runtime_error("Could not create easyPDF PDFConverter");
BclCnvResult error = pConverter>PDF2Image->Convert(pConverter, L"c:\\test\\input.pdf", L"c:\\test\\output.tif", L"", -1, -1);

Using SafePDFConverter means you are not calling Dispose manually. It will be called automatically when your local variable goes out of scope, even if an exception occurs.

This implementation has no reference counting, therefore it can only be used in a local scope. Do not use standard smart pointers, such as std::auto_ptr or std::shared_ptr, because they would attempt to call delete instead of Dispose on the pointer, which would cause an instant crash. Similarly, do not use standard smart pointers for any other easyPDF pointer.

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 BclNewPDFConverter:

BclLoaderSettings loaderSettings = { 0 };
loaderSettings.LaunchTimeout = 60000; // 1 minute
BclPDFConverter* pConverter = BclNewPDFConverter(&loaderSettings);

loaderSettings cannot be changed after pConverter is created.

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