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.
These functions (which all have the prefix PBORCA_) use a callback function:
ORCA function call (prefix PBORCA_) |
Purpose of callback |
---|---|
BuildProjectEx BuildProject |
Called once for each deployment error |
CompileEntryImport CompileEntryImportList CompileEntryRegenerate |
Called once for each compile error |
ExecutableCreate |
Called once for each link error |
LibraryDirectory |
Called once for each library entry name |
ObjectQueryHierarchy |
Called once for every ancestor name |
ObjectQueryReference |
Called once for every object referenced in the entry |
SccSetTarget |
Called once for each library in the library list |
ORCA calls a callback function like this:
-
The calling program allocates a buffer to hold data (the UserData buffer).
-
The calling program calls an ORCA function, passing it pointers to the callback function and the UserData buffer.
-
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.
-
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.
-
The ORCA function completes and returns control to the calling program, which reads the information in the UserData buffer.
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 } ORCA_USERDATAINFO, FAR *PORCA_USERDATAINFO;
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:
ORCA_USERDATAINFO UserDataBuffer; PORCA_USERDATAINFO lpUserDataBuffer; lpUserDataBuffer = &UserDataBuffer; lpUserDataBuffer->dwCallCount = 0; lpUserDataBuffer->dwBufferOffset = 0; lpUserDataBuffer->dwBufferSize = 60000; lpUserDataBuffer->lpszBuffer = (LPTSTR)malloc((size_t)lpUserDataBuffer-> dwBufferSize); memset(lpUserDataBuffer->lpszBuffer, 0x00,(size_t)lpUserDataBuffer->dwBufferSize);
Define function pointer
The calling program defines a function pointer to the callback function that it passes to the ORCA function:
PBORCA_LINKPROC fpLinkProc; fpLinkProc = (PBORCA_LINKPROC)LinkErrors;
Call ORCA
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) { PORCA_USERDATAINFO lpData; LPBYTE lpCurrByte; LPTSTR lpCurrentPtr; int iNeededSize; lpData = (PORCA_USERDATAINFO) lpUserData; // Keep track of number of link errors lpData->dwCallCount++; // Is buffer already full? if (lpData->dwBufferOffset==lpData->dwBufferSize) return; // How long is the new message? // Message length plus carriage rtn and newline iNeededSize = (_tcslen(lpLinkError->lpszMessageText) + 2)* sizeof(TCHAR); // Reallocate buffer if necessary if ((lpData->dwBufferOffset + iNeededSize) > lpData->dwBufferSize) { LPVOID lpNewBlock; DWORD dwNewSize; dwNewSize = lpData->dwBufferSize * 2; lpNewBlock = realloc(lpData->lpszBuffer, (size_t)dwNewSize); if (lpNewBlock) { lpData->lpszBuffer = (LPTSTR) lpNewBlock; lpData->dwBufferSize = dwNewSize; } else return; } // 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; return; }