About ORCA callback functions

Several ORCA functions require you to code a callback function. A callback function provides a way for the called program (the ORCA DLL or the Library Manager) to execute code in the calling program (the ORCA program executable).

How ORCA uses callbacks

ORCA uses callback functions when an unknown number of items needs to be processed. The purpose of the callback function is to process each of the returned items, and in most cases return the information to the user.

Optional or required

Some callbacks handle errors that occur when the main work is being done -- for example, when compiling objects or building executables. For handling errors, the callback function is optional. Other callbacks handle the information you wanted when you called the function -- such as each item in a directory listing. Callbacks for information functions are required.

Language requirement

ORCA functions that require the use of callback functions can be used only by programs written in languages that use pointers, such as C and C++.

When you create a new ORCA callback function, use the CALLBACK macro to specify the calling convention of the function. On the Windows platform, CALLBACK is defined as __stdcall.

ORCA functions that use callbacks

These functions (which all have the prefix PBORCA_) use a callback function:

ORCA function call (prefix PBORCA_)

   Purpose of callback



Called once for each deployment error




Called once for each compile error


Called once for each link error


Called once for each library entry name


Called once for every ancestor name


Called once for every object referenced in the entry


Called once for each library in the library list

How a callback works

ORCA calls a callback function like this:

  1. The calling program allocates a buffer to hold data (the UserData buffer).

  2. The calling program calls an ORCA function, passing it pointers to the callback function and the UserData buffer.

  3. When the ORCA function needs to report information, it calls the callback function. It passes pointers to the structure holding the information and the UserData buffer.

  4. The callback function reads the information in the structure and formats it in the UserData buffer.

    Steps 3 and 4 repeat for each piece of information ORCA needs to report. An ORCA function might call the callback once, several times, or not at all, depending on whether errors occur or information needs to be reported.

  5. The ORCA function completes and returns control to the calling program, which reads the information in the UserData buffer.

Content of a callback function

The processing that occurs in the callback function is entirely up to you. This section illustrates a simple way of handling it.

UserData buffer

In this example, the UserData buffer is a structure with a field whose value points to the actual message buffer. Other fields keep track of the message buffer's contents as it is filled:

typedef struct ORCA_UserDataInfo {
   LPBYTE lpszBuffer;     // Buffer to store data
   DWORD dwCallCount;    // # of messages in buffer 
   DWORD dwBufferSize;   // size of buffer 
   DWORD dwBufferOffset; // current offset in buffer 

Calling program

In the calling program, the UserDataInfo structure is initialized.

The calling program does not know how much room will be required for messages, so it allocates 60000 bytes (an arbitrary size). If you are gathering link errors, it's probably enough. It might not be enough if you wanted directory information for a large library:

lpUserDataBuffer = &UserDataBuffer;
lpUserDataBuffer->dwCallCount = 0;
lpUserDataBuffer->dwBufferOffset = 0;
lpUserDataBuffer->dwBufferSize = 60000;
lpUserDataBuffer->lpszBuffer = 

Define function pointer

The calling program defines a function pointer to the callback function that it passes to the ORCA function:

fpLinkProc = (PBORCA_LINKPROC)LinkErrors;


The calling program calls the ORCA function, passing the callback function pointer and the UserData buffer pointer. This example calls PBORCA_ExecutableCreate, whose callback type is PBORCA_LNKPROC:

rtn = PBORCA_ExecutableCreate(..., (PBORCA_LNKPROC) 
fpLinkProc, lpUserDataBuffer);

Process results

Finally, the calling program can process or display information that the callback function stored in the UserData buffer.

Free allocated memory

If your UserData structure allocates memory, free the allocated memory:

free( lpUserDataBuffer->lpszBuffer )

Callback program

The callback program receives a structure with the current error or information and stores the information in the message buffer pointed to by lpszBuffer in the UserData buffer. It also manages the pointers stored in the UserData buffer.

Simple callback

A simple callback might do the following:

  • Keep count of the number of times it is called

  • Store messages and reallocate buffer if it overflows

This code implements a callback called LinkErrors for PBORCA_ExecutableCreate:

void CALLBACK LinkErrors(PPBORCA_LINKERR lpLinkError, 
      LPVOID lpUserData) 
   LPBYTE lpCurrByte;
   LPTSTR lpCurrentPtr;
   int iNeededSize;
   lpData = (PORCA_USERDATAINFO) lpUserData;
   // Keep track of number of link errors
   // Is buffer already full?
   if (lpData->dwBufferOffset==lpData->dwBufferSize)
   // How long is the new message? 
   // Message length plus carriage rtn and newline
   iNeededSize = 
      (_tcslen(lpLinkError->lpszMessageText) + 2)* 
    // Reallocate buffer if necessary
   if ((lpData->dwBufferOffset + iNeededSize) > 
      LPVOID lpNewBlock;
      DWORD  dwNewSize;
      dwNewSize = lpData->dwBufferSize * 2; 
      lpNewBlock = realloc(lpData->lpszBuffer,
      if (lpNewBlock)
         lpData->lpszBuffer = (LPTSTR) lpNewBlock;
         lpData->dwBufferSize = dwNewSize;
   // Set pointer for copying message to buffer
     lpCurrentPtr = lpData->lpszBuffer 
        + lpData->dwBufferOffset;   
      lpCurrString = (LPTSTR) lpCurrByte;
  // Copy link error message, CR, and LF to buffer. 
  _tcscpy(lpCurrentPtr, lpLinkError->lpszMessageText);
  _tcscat(lpCurrentPtr, _TEXT("\r\n"));
  lpData->dwBufferOffset += iNeededSize;