Generate Output in Memory
TFormer_PrintToStream sends generated output to a TFN_StreamWriteCallback. The callback can receive open, data, and close events, and a data event can occur more than once.
For PDF output, the callback receives one stream. This C++ example uses the native C API to append each data block to an application-owned std::vector<BYTE> and ignores the open and close events. Other output types can produce several streams and require separate stream handling, which is not part of this PDF example.
Setup: Windows build. For a supplied project and layout, see the Quick Start.
Using TFormer_PrintToStream
The following excerpt assumes that form already has its form layout and data configured, and that pdfData and WriteToMemory are defined as in the complete example below:
CHECK(TFormer_SetPrinterType(form, ePrinterType_PDFFile));
CHECK(TFormer_PrintToStream(
form, WriteToMemory, reinterpret_cast<LPARAM>(&pdfData)));
// Use pdfData.data() and pdfData.size() here.
std::printf("PDF size: %zu bytes\n", pdfData.size());
Use pdfData.data() and pdfData.size() only after TFormer_PrintToStream returns ErrOk. The vector owns the captured bytes and releases them automatically when it leaves scope. No output filename or fixed capacity is required.
Complete Example
The following standalone C++ program includes the layout and data setup. Place both code blocks, in this order, in the same source file. Replace the layout filename and data-field name before running it. Include the public TFormer.h header and link the TFormer import library that matches the Windows application architecture and installed SDK release.
#include <cstdio>
#include <new>
#include <vector>
#define TECIT_DLLIMPORT
#include "TFormer.h"
#undef TECIT_DLLIMPORT
static ERRCODE __stdcall WriteToMemory(
BYTE *data, INT size, DWORD event, LPARAM userData) noexcept
{
if (event != eWriteCallBack_Data)
return ErrOk;
if (userData == 0 || size < 0 || (data == nullptr && size != 0))
return E_INVALIDARG;
if (size == 0)
return ErrOk;
auto *buffer = reinterpret_cast<std::vector<BYTE> *>(userData);
try {
buffer->insert(buffer->end(), data, data + static_cast<size_t>(size));
return ErrOk;
} catch (const std::bad_alloc &) {
return E_OUTOFMEMORY;
} catch (...) {
return E_FAIL;
}
}
#define CHECK(call) \
do { \
result = (call); \
if (result != ErrOk) { \
LPCSTR message = TFormer_GetLastErrorDescription(form); \
std::fprintf( \
stderr, "%s failed: %s\n", #call, \
message != nullptr ? message : "no error description"); \
goto cleanup; \
} \
} while (0)
int main()
{
ERRCODE result = ErrOk;
HTFORM form = TFormer_Init(nullptr);
std::vector<BYTE> pdfData;
if (form == nullptr)
return 1;
CHECK(TFormer_SetRepositoryName(
form, "FILENAME_OF_YOUR_FORMLAYOUT.tff"));
CHECK(TFormer_NewRecord(form));
CHECK(TFormer_SetVarValue(
form, "NAME_OF_YOUR_DATAFIELD", "Value of the data field"));
CHECK(TFormer_SetPrinterType(form, ePrinterType_PDFFile));
CHECK(TFormer_PrintToStream(
form, WriteToMemory, reinterpret_cast<LPARAM>(&pdfData)));
// Use pdfData.data() and pdfData.size() here.
std::printf("PDF size: %zu bytes\n", pdfData.size());
cleanup:
if (form != nullptr) {
ERRCODE exitResult = TFormer_Exit(form);
if (result == ErrOk)
result = exitResult;
}
return result == ErrOk ? 0 : 1;
}
The callback contains C++ exceptions and converts allocation failure to E_OUTOFMEMORY. Other callback exceptions become E_FAIL; none cross the native C callback boundary. The program reports the captured PDF byte count and does not write a PDF file.