Handles are the mechanism for using the MQe items. The handle points to an area of memory used to store the specific information for that instance of an item. Type information is held for each item so care needs to be taken to correctly initialise the handle.
In order to use a handle it must be initialized. This is achieved by calling the new function of the associated item to be used. For instance, if we wish to create an MQeString, we first of all need to call the mqeString_new() function, passing to that function a pointer to an MQeStringHndl. The mqeString_new() function will then allocate memory for the internal structure and set any default values required by the MQeString. Once this has been completed successfully the function returns the handle which can now be used on subsequent calls to MQeString functions.
Once an item has been finished with, it is important to call the free() function of the item with which the handle is associated. The free() functions release all the system resources used by that item. If the handle is merely set to null, a memory leak will be introduced to the application and the system may run out of resources. However it can be useful programming practice to set the handle to null after it has been freed.
Attempts to free a handle twice can cause unpredictable results - similar to the situation of freeing dynamically allocated memory twice.
Handles must only be used with their associated items, and they must be properly initialised and freed. The only instances where it is not the responsibility of the application to initialise a handle is in the cases where a pointer to a handle is passed as an input parameter to a Websphere MQ Everyplace API. In such instances, a fully initialised handle is returned to the application without the user having to invoke the relevant new() function. An example of such an occurrence is mqeQueueManager_browseMessages() which has a pointer to an MQeVectorHndl as an input parameter.
MQeVectorHndl hMsgs; ... rc = mqeQueueManager_browseMessages(hQMgr, &exceptBlock, &hMsgs, hQMgrName,hQName, hFilter, hAttribute, justUID );
Although the user does not invoke the mqeVector_new() function to initialise hMsgs, it is still essential that the user uses mqeVector_free(hMsgs,&exceptBlock) in order to free the resources used by hMsgs at the appropriate point in the application.
In this case the vector contains fields, and the vector will free any fields items it still contains. If the vector contains strings, freeing the vector will free all the strings that it contains. It is possible, however, that the vector may be filled with your own data structures. In this case, freeing the vector will not free its contents - as it is impossible for the vector to know the precise way to free your structures. Freeing such a non-empty vector will generate an error condition.
It is always the responsibility of the user to free any handles.
Handles and their associated items are:
MQeFields MQeFieldsHndl MQeString MQeStringHndl MQeVector MQeVectorHndl MQeQueueManager MQeQueueManagerHndl MQeAdministrator MQeAdministratorHndl MQeAuthenticator MQeAuthenticatorHndl MQeCompressor MQeCompressorHndl MQeRLECompressor MQeRleCompressorHndl MQeCryptor MQeCryptorHndl MQeRC4Cryptor MQeRC4CryptorHndl MQeLocalSecure MQeLocalSecureHndl MQeFieldsAttribute MQeFieldsAttrHndl Plugin comms adapter MQeMasterCommsAdapterHndl MQeKey MQeKeyHndl MQeLocalKey MQeLocalKeyHndl MQeSharedKey MQeSharedKeyHndl
Of all these items, the first five are the most commonly used.
The order of the parameters in the API calls follows a strict pattern.
Most functions take a handle and an exception block, together with any other possible parameters. The 1st parameter will be the handle, and the 2nd parameter will be the exception block.
The handle indicates the item that the function is operating on. The exception block provides the ability to communicate errors back to the caller. Some functions do not take a handle as the 1st parameter. These are Static functions that do not operate on an object. Examples are the Session terminate and initialize functions and functions that create new object handles. The latter do, however, take a handle as an output parameter, returning a new handle.
For the construction of new objects
MQERETURN mqeObjectName_new(MQeExceptBlock *pErrStruct, MQeObjectHndl *phNewObjectHndl, .... <parameter>);
All other functions
MQERETURN mqeObjectName_functionName(MQeObjectHndl hObjectHndl, MQeExceptBlock *pErrStruct, ... <parameters>);
The direction in which parameters are passed is indicated as follows:
For situations where a buffer is required a double call approach is adopted. On the first call the parameter requiring the buffer is set to NULL - in this instance, the size of the item is returned in the parameter indicating the length of the buffer. The user can then allocate the required memory for the buffer, and the API call is then made a second time, this time passing in the buffer.
In many cases, an MQeStringHndl is passed into a function, for example as the name of an item. Unless otherwise stated, the MQeStringHndl will be duplicated internally, and the handle held by the application can be freed.