GroupWise XTD Tokenization
Articles and Tips: article
GroupWare Technical Writer
GroupWare Division
CAROL OERTLI
GroupWare Technical Editor
GroupWare Division
TIM STURDIVANT
GroupWare Technical Writer
GroupWare Division
RANDY WAKI
Software Engineer
GroupWise Client Development
01 May 1996
GroupWise XTD developer tools include the Object API (GWOAPI) for obtaining data from the GroupWise information store and C3POs for adding objects to the GroupWise object set. But what about commanding the client? Tokenization names low-level events. GroupWise uses tokens to operate as a program. You can use Visual Basic executables, DLLs using the 3rd-Party Handler, and DDE to command the GroupWise XTD 32-bit client. This article discusses using DDE to command the GroupWise XTD 32-Bit Client and using the 3rd-Party Handler.
Dynamic Data Exchange (DDE) lets Windows applications communicate. Applications can establish a DDE conversation and send messages to each other. A DDE conversation involves server and client applications. The server provides resources to the client. The client accepts processing or information from the server. The 3rd-Party Handler (formerly WOAPI) lets your DLLs monitor the GroupWise token stream. DLLs can process tokens before GroupWise, affect how GroupWise processes them, or process them instead of GroupWise.
- Introduction
- Using the 3rd-Party Handler
- Third-Party Handler DLL Entry Points
- Structures, Types, and Enumerations
- Token Handling
Introduction
GroupWise XTD developer tools include the Object API (GWOAPI) for obtaining data from the GroupWise information store and C3POs for adding objects to the GroupWise object set. But what about commanding the client? Tokenization names low-level events. GroupWise uses tokens to operate as a program. You can use Visual Basic executables, DLLs using the 3rd-Party Handler, and DDE to command the GroupWise XTD 32-bit client.
GroupWise 32-bit client menus at XTD release no longer include Macro, Play and Macro, Record. However, the client will let users play executables from the Toolbar, menus, and customized views. The Tokenization story includes DDE and the 3rd-Party Handler (formerly WOAPI). The Novell SDK CD Release 8 will include C++, DLL, DDE, and VB code samples and information about obsolete, added, and modified GroupWise XTD tokens.
This article discusses using DDE to command the GroupWise XTD 32-Bit Client and using the 3rd-Party Handler.
Using DDE To Command the GroupWise XTD 32-Bit Client
Dynamic Data Exchange (DDE) lets Windows applications communicate. Applications can establish a DDE conversation and send messages to each other. A DDE conversation involves server and client applications. The server provides resources to the client. The client accepts processing or information from the server.
DDE Management Library. Use DdeInitialize( ) to register an application with DDEML. The DDE Management Library (DDEML) simplifies DDE management by providing a high-level interface.
DDE Conversations. Use DdeConnect( ) to establish a conversation. A service parameter specifies an application to establish a conversation with. A topic parameter specifies the conversation topic.
Sending DDE Messages. Use DdeClientTransaction( ) to send service and information requests between conversing applications.
Terminating a DDE Conversation. Use DdeDisconnect( ) to end a conversation, then DdeUninitialize( ) to clear application registration.
DDE, GroupWise, and Your Solution
Your solution can:
Share GroupWise resources using DDE Execute.
Obtain GroupWise processing results using DDE Request.
A DDEML-registered application can establish a conversation with GroupWise using DdeConnect( ) including a service and topic name pair from the table below. The first pair is generally recommended:
Service Name
|
Topic Name
|
Comments
|
GroupWise |
Command |
Recommended.A conversation using this pair can send anysupported command to GroupWise. |
OFWin |
Command |
Operateslike GroupWise/Command but makes GroupWisecompatible with applications that launcha server based on the service name--in thiscase--OFWIN.EXE. |
WPOffice40 |
Command |
Includedfor backward compatibility with Office 4.x.Avoid using this pair because support mayend in future releases. |
WPOffice40 |
GetOfficeData |
Includedfor backward compatibility with Office 4.x.Support may end in future releases. |
WPOffice40 |
GetAddressBookData |
Includedfor backward compatibility with Office 4.x.Support may end in future releases. |
For example:
const char lpszService[ ] = OFWIN ; const char lpszTopic[ ] = COMMAND ; HDDEDATA FAR PASCAL __export DdeCallback( UINT, UINT, HCONV, HSZ, HSZ, HDDEDATA, DWORD, DWORD ); DWORD dwDDEInst; HSZ hszService; HSZ hszTopic; HCONV hConv; /** Register with DDEML **/ DdeInitialize(&dwDDEInst,(PFNCALLBACK)DdeCallback, APPCLASS_STANDARD | APPCMD_CLIENTONLY, 0L);& /** Create our String Handles **/ hszService = DdeCreateStringHandle(dwDDEInst, lpszService, 0); hszTopic = DdeCreateStringHandle(dwDDEInst, lpszTopic, 0); /** Attempt to establish connection **/ hConv = DdeConnect(dwDDEInst, hszService, hszTopic, NULL); /** Free the string handles **/ DdeFreeStringHandle(dwDDEInst, hszService); DdeFreeStringHandle(dwDDEInst, hszTopic);
Your solution can send GroupWise a product command (see the GroupWise Macros Manual) in a DDE Execute parameter. When GroupWise cannot process a command, it stores user-accessible error information (see DDE Error Messages below).
DDE Execute strings are null-terminated ANSI strings. Each string consists of supported macro commands. You can space-delimit multiple commands in a string.
For example:
"ViewOpenDlg( )"" "ViewOpen( Appointment!; Yes! )"" "ViewOpen( Appointment!; Yes!) FocusSet( Message! ) EditPaste( )"" "ViewOpen(Appointment!;Yes!) FocusSet(Message!)EditPaste()"" " ViewOpen(Appointment!;Yes!) FocusSet(Message!) EditPaste( ) ""
DDE ignores the remainder of a transaction containing an invalid command or syntax. See the GroupWise Macros Reference online manual for command syntax. Send GroupWise a command string as the DDE data block in a DDE Execute transaction. This is the Windows DDEClientTransaction( ), lpvData parameter.
For example:
/** lpszCmd is a pointer to an ANSI string **/ /** containing the command(s) we wish to **/ /** send to GroupWise **/ DdeClientTransaction( (LPBYTE)lpszCmd, (DWORD)_fstrlen(lpszCmd)+1, hConv, NULL, CF_TEXT, XTYP_EXECUTE, (DWORD)TIMEOUT_ASYNC, NULL );
Using DDE To Obtain GroupWise Error Information
Your solution can use DDE to request GroupWise error data. DDEGetLastError( ) returns information about the cause of the last error when DDEClientTransaction( ) returns FALSE. A DMLERR_NOTPROCESSED return value indicates GroupWise has received a command but cannot process it. Send an EnvLastError( ) DDE Request to GroupWise (see below) to return an error information string. Successful GroupWise commands empty the error value, and EnvLastError( ) returns an empty string.
Value
|
Description
|
10E1 |
BadParameterx, where x is the index of the bad parameter. |
10E2 |
Failed. |
10E3 |
Commandis invalid given current state of GroupWise. |
10E4 |
Not found. |
10E5 |
Syntax error. |
10E7 |
BC(Blind Copy) doesn't apply to personal items. |
10E8 |
Notsupported for encapsulated item attachments. |
10E9 |
Notsupported for OLE attachments. |
10EA |
Themessage ID references an Out Box message that does not exist yet. |
10EB |
Youcannot set an alarm for a time that has already expired. |
10EC |
Thesource attributes of the In Box filter cannot be changed. |
10ED |
Thesource attributes of the Out Box filter cannot be changed. |
xxxx |
OtherGroupWise error. |
For example:
HSZ hCmd; /** Create a valid string handle for our command string**/ hCmd = DdeCreateStringHandle (dwDDEInst, "EnvLastError()", CP_WINANSI);" /** Request the information **/ if ( 0 != (hReqData = DdeClientTransaction( NULL, (DWORD)0L, hConv, hCmd, CF_TEXT, XTYP_REQUEST, (DWORD)2000, NULL ))) { /** Free our string handle **/ DdeFreeStringHandle (dwDDEInst, hCmd); /** Get a valid pointer to the data that we can access **/ lpDataByte = DdeAccessData (hReqData, &cbDataLen);& /** Copy the data into the return buffer */ lstrcpy (lpszBuf, (LPSTR)lpDataByte); /** THE ERROR MESSAGE IS NOW STORED IN lpszBuf **/ /** Free up the pointer we locked down **/ DdeUnaccessData (hReqData); return TRUE; }
Requesting GroupWise Information
To obtain GroupWise return value information, use EnvLastCmdResult( ) macro command, DDE Request, and DDE Advise loop. GroupWise returns information in ANSI strings. You can convert returned ANSI character string data to its native data type. For example, GroupWise returns a numeric value 96 as the ANSI string "96".
NativeData Type
|
ANSICharacter String Returned by GroupWise
|
Numeric |
Numeric characters |
Boolean |
"TRUE","FALSE" |
ANSI string |
ANSI string |
You can request GroupWise DDE Execute return information using DDE Request including EnvLastCmdResult( ).
For example:
HSZ hCmd; /** Create a valid string handle for our command string **/ hCmd = DdeCreateStringHandle(dwDDEInst, "EnvLastCmdResult()", CP_WINANSI);" /** Request the information **/ if ( 0 != (hReqData = DdeClientTransaction( NULL, (DWORD)0L, hConv, hCmd, CF_TEXT, XTYP_REQUEST, (DWORD)2000, NULL))) { /** Free our string handle **/ DdeFreeStringHandle (dwDDEInst, hCmd); /** Get a valid pointer to the data that we can access **/ lpDataByte = DdeAccessData(hReqData, &cbDataLen);& /** Copy the data into the return buffer */ lstrcpy (lpszBuf, (LPSTR)lpDataByte); /** THE COMMAND RESULT DATA IS NOW STORED IN lpszBuf **/ /** Free up the pointer we locked down **/ DdeUnaccessData (hReqData); return TRUE; }
DDE Request. DDE Request substitutes DDE Execute command strings for DDE Item names and obtains return values. DDE Request returns a DDE data handle, then lets your solution have it. Windows imposes a 255-character limit on DDE Request command string length, including the terminating NULL character.
For example:
HSZ hCmd; /** Create a valid string handle for our command string **/ hCmd = DdeCreateStringHandle(dwDDEInst, "AddressBookGetField( ABField: USERSNETID! )", CP_WINANSI);" /** Request the information **/ if ( 0 != (hReqData = DdeClientTransaction( NULL, (DWORD)0L, hConv, hCmd, CF_TEXT, XTYP_REQUEST, (DWORD)2000,NULL))) { /** Free our string handle **/ DdeFreeStringHandle (dwDDEInst, hCmd); /** Get a valid pointer to the data that we can access **/ lpDataByte = DdeAccessData (hReqData, &cbDataLen);& /** Copy the data into the return buffer */ lstrcpy (lpszBuf, (LPSTR)lpDataByte); /** THE COMMAND RESULT DATA IS NOW STORED IN lpszBuf **/ /** Free up the pointer we locked down **/ DdeUnaccessData (hReqData); return TRUE; }
DDE Advise Loop. You can establish a DDE Advise loop instead of using EnvLastCmdResult( ). A DDE Advise loop returns DDE Execute values to DDE Advise Data, then GroupWise, then notifies your solution. DDE notifies your solution only of DDE Advise Data values for commands that return values and commands sent to GroupWise not using DDE Request. In an established DDE conversation, create a DDE Advise loop by sending DDE Advise Start to GroupWise with the item name string, "CommandReturn". Track the DDEClientTransaction identifier to match DDE Advise notifications and DDE Execute transactions.
For example:
HSZ hItem; HCONV hConv; // These two variables are DWORD dwDDEInst; // assigned valid values // during DDE initialization /** Create a valid string handle for our command string **/ hItem = DdeCreateStringHandle (dwDDEInst, "CommandReturn", CP_WINANSI);" /** Start the Advise Loop **/ DdeClientTransaction( (LPBYTE)NULL, 0, hConv, hItem, CF_TEXT, XTYP_ADVSTART, (DWORD)TIMEOUT_ASYNC, &dwTransResult );&
Simultaneous Commands. DDE does not let your solution send DDE Execute during another same-conversation command. Make sure your solution does not send simultaneous multiple DDE Execute or DDE Request commands. Otherwise, a DDE Reentrancy error results and your commands may not execute.
Using the 3rd-Party Handler
The 3rd-Party Handler lets your DLLs monitor the GroupWise token stream. The interaction between GroupWise and third-party DLLs is as follows: GroupWise loads third-party DLLs at startup; GroupWise passes tokens to third-party DLLs (calling Entry once initially and then using HandleToken to direct tokens); DLLs return values indicating they did not process tokens or changing how GroupWise processes a token. (Otherwise, GroupWise does not process the token.)
Novell has removed Shared Code from GroupWise XTD. Third-party DLLs must provide their own installation and Windows Registry entries:
Key: |
"HKEY_CURRENT_USER\Software\Novell\GroupWise\5.0\ThirdParty" |
Item: |
"DLLx"(x is a number) |
ItemType: |
ANSISTRING |
ItemValue: |
<DLLpath and filename< |
DLL Loading
As GroupWise opens, it finds third-party DLLs in the Registry, then loads them in Item number order. For example, finding DLL1, DLL2, DLL4, then DLL0, GroupWise loads DLL1, then DLL2. GroupWise loads only consecutively numbered entries, starting with the first found. In the example above, GroupWise does not load DLL4 and DLL0.
Intercepting Tokens
A loaded DLL can monitor and intercept GroupWise tokens and:
Let a token pass to GroupWise. DLLs can pass a token unprocessed or use a token value as a trigger to process a token, then pass it on, indicating it was unprocessed. DLLs can also generate, then pass new tokens.
Block a token. A DLL can return a token, indicating it was processed. Processed tokens are not passed to other DLLs or GroupWise. The DLL that processes a token must provide required return values.
Modify the token. DLLs can monitor the token stream, intercept a token, modify it, pass it to GroupWise as a new token, then indicate that the original token was processed or modify the token, then return a value indicating it was unprocessed.
Third-Party Handler DLL Entry Points
This section describes required DLL entry points. You can call them using their ordinal values. Please note the required ordinal value of each function.
TPHVersion
Lets the DLL register its major/minor version numbers with GroupWise and pass the DLL instance handle to GroupWise. The ordinal value for TPHVersion( ) must be 1 (one).
Prototype |
DWORD WINAPI TPHVersion ( VOID ); |
|
Parameters |
None. |
|
Return Values |
LOWORD-LOBYTE DLL major version.LOWORD-HIBYTE DLL minor version.HIWORDDLL instance handle. |
|
Example |
DWORD WINAPI TPHVersion ( VOID ){ return MAKELONG (1, hInstance); |
Compatibility
Required for DLLs. Compatibility( ) lets a DLL specify the GroupWise version to load it with and ensures compatibility between GroupWise and third-party DLLs. Your DLL can verify GroupWise versions, then return GroupWise a value indicating whether to load your DLL. A Novell application name and GroupWise version are passed as parameters to Compatibility( ). You must export Compatibility( ) at ordinal value 2 (two).
The GroupWise AppName is GROUPWISE. The AppVersion is a word value with the low-order byte containing the GroupWise major version, and the high-order byte containing the minor version.
Prototype |
DWORD WINAPI Compatibility (ATOM AppName, WORD AppVersion ); |
|
Parameters |
AppName Atom of the calling application. See a Windows programming manual for Atoms information.AppVersion GroupWise version being loaded for the calling application. |
|
Return Values |
Make sure the Compatibility( ) return value is TRUE or FALSE cast as a DWORD value. An incompatible DLL returns FALSE. |
|
Example |
DWORD WINAPI Compatibility ( ATOM AppName, WORD AppVersion){ UINT uBytes; char szAppName [BUF_SIZE]; uBytes = GetAtomName (AppName, szAppName, BUF_SIZE-1);//Get the Atom name if (uBytes -- (!lstrcmpi(szAppName, -GROUPWISE-)) --//GroupWise Atom (LOWORD (AppVersion)) == GW_MAJOR_VERSION)//GroupWise 5.x return (DWORD) TRUE; //return non-zero else //else return (DWORD) FALSE; //return FALSE} |
TimeStamp
GroupWise uses TimeStamp( ) to request DLL release dates. Make sure your DLL returns its file time stamp (date and time) to GroupWise. You may return a value of zero. Although GroupWise does not use the date and time values returned, it nonetheless calls TimeStamp( ). Export TimeStamp( ) as ordinal value 3 (three).
Prototype |
DWORD WINAPI TimeStamp ( VOID ); |
|
Parameters |
None. |
|
Return Values |
The return value uses: |
Value
|
Meaning
|
Bits
|
Code
|
LOWORD |
Date |
0-4 |
Day:1=Sun., 2=Mon, and so forth. |
5-8 |
Month:1=January, 2=February, and so forth. |
||
9-15 |
Year: 1980=0. |
||
HIWORD |
Time |
0-4 |
Seconds:0-29 in 2 second increments. |
5-10 |
Minutes: 0-59. |
||
11-15 |
Hours: 0-23. |
Example |
DWORD WINAPI TimeStamp ( VOID ){ return 0;} |
Entry
Called to allow the DLL to perform any required initialization; called prior to any tokens passed to DLLs. DLLs are provided with the resource language code to indicate the language being used in the calling application. Must be exported at ordinal value 4 (four).
Prototype |
WORD WINAPI Entry ( WORD wLanguage ); |
Parameters |
LanguageThe default language for the calling application.For the US version of GroupWise, the valueof the wLanguage parameter would be: LOBYTE 'U'HIBYTE 'S' |
ReturnValues |
Avalue greater than zero should be returnedto indicate success. A return value lessthan or equal to zero indicates an erroroccurred. |
Example |
WORD WINAPI Entry ( WORD wLanguage ){ hRequestor = GlobalAddAtom ("GroupWise DLL");//Set up requestor return 1;} |
Exit
Allows the DLL to execute any code for cleanup purposes (closing files or destroying dialogs) before the DLL is unloaded. This function must be exported as ordinal value 5 (five).
Prototype |
WORD WINAPI Exit( VOID ); |
Parameters |
None. |
Return Values |
The return value is ignored. |
Example |
WORD WINAPI Exit ( VOID ){ GlobalDeleteAtom (hRequestor); //Free the requestor return 1;} |
HandleToken
GroupWise passes token values and parameters to HandleToken( ). GroupWise calls HandleToken( ) to pass tokens to DLLs. A DLL can then forward, modify, or block the token. A DLL can also use token values to trigger events. See Token Handling below for detailed information on handling, building and sending tokens. HandleToken( ) is called using ordinal value 6 (six).
Prototype |
int WINAPI HandleToken (LPTH_RETURNVAL lpDataHWND hLinkWnd,WORD msg ); |
Parameters |
lpDataA LPTPH_RETURNVAL structure contains two members.The first is a pointer to an LPMAC_TOKENstructure, which contains the token ID andparameter data. The second member is a pointerto an LPLPMAC_RETURNVAL structure, whichis used for return values from value-returningtokens. hLinkWndHandle to the link window. msgLink window execute message. |
Return Values |
LL_HAN_NOT_HANDLEDThe token was not processed. DLL_HAN_NO_ERRORThe token was processed. This value should bereturned to block a token. DLL_HAN_NOT_FOUNDThe token resulted in a GroupWise "not found"condition. DLL_HAN_CANCELThe user cancelled the function. DLL_HAN_TOKEN_ERRORThe token was not valid. DLL_HAN_PARM_ERROROne or more of the parameters were invalid. |
Example |
int WINAPI HandleToken (LPMAC_TOKEN lpTokenData, HWND hLinkWnd, WORD msg ){return DLL_HAN_NOT_HANDLED; //Return all tokens to GroupWise unchanged} |
ValidateToken
Allows a DLL to control the display of an entry on a GroupWise menu or Toolbar. Must be exported at ordinal value 7 (seven).
Prototype |
DWORD WINAPI ValidateToken ( LPMAC_TOKEN lpTokenData, LPVOID lpDataTypeInfo ); |
Parameters |
lpTokenDataLong pointer to a MAC_TOKEN structure. lpDataTypeInfoPointer to a TPValInfo structure cast to LPVOID. |
Return Values |
Thereturn value should be a DWORD value containingthe appropriate table entries as the low-orderand high-order words: |
Low-Order Word (LOWORD)
|
Description
|
DLL_VAL_UNKNOWN_TOKEN |
This token is not recognized by the DLL. |
DLL_VAL_VALIDATED |
Thistoken was validated by the DLL. |
DLL_VAL_UNVALIDATED |
Thistoken was unvalidated by the DLL. |
High-OrderWord (HIWORD)
|
Description
|
MT_MENU_ITEM_CHECKED |
Changemenu item state to be checked. |
MT_MENU_ITEM_UNCHECKED |
Changemenu item state to be unchecked. |
MT_MENU_ITEM_ENABLED |
Enable menu item. |
MT_MENU_ITEM_GRAYED |
Gray menu item. |
MT_MENU_ITEM_TRISTATE |
Indicatesthe item may be in an indeterminate state. |
Example |
DWORD WINAPI ValidateToken ( LPMAC_TOKEN lpTokenData, LPVOID lpDataTypeInfo ){ if (lpTokenData->wTokenID == MyTheta) return MAKELONG (DLL_VAL_UNKNOWN_TOKEN, MT_MENU_ITEM_GRAYED); else return DLL_VAL_UNKNOWN_TOKEN;} |
Structures, Types, and Enumerations
This section discusses MAC_PARAM, MAC_RETURNVAL, MAC_TOKEN, MAC_TOKENERROR, MAC_TOKENID, MAC_VALUE_TYPE, MAC_VARIABLE, TPH_RETURNVAL,and TPVALINFO.
MAC_PARAM
A structure used to store token parameter information.
Definition |
typedef struct _tagMAC_PARAM{ MAC_VALUE_TYPE eType; WORD wReserved; WORD wFlags; union { DWORD dwValue; void far *lpvPtr; double drValue; } uData;} MAC_PARAM, NEAR *NPMAC_PARAM, FAR *LPMAC_PARAM, *PMAC_PARAM; |
Types |
MAC_PARAMStructure containing token parameter information. NPMAC_PARAMNear pointer to a MAC_PARAM structure. LPMAC_PARAMFar pointer to a MAC_PARAM structure. PMAC_PARAMPointer to a MAC_PARAM structure. |
Members |
eTypeParameter type enumeration. (See MAC_VALUE_TYPE definition). wFlagsWhen using token parameter, set wFlags to 00000;when token parameter is optional and unused,set wFlags to 08000. StDataUnion containing parameter data. |
Member
|
Description
|
dwValue |
Integer data. |
lpvPtr |
String data. |
drValue |
Floating point data. |
MAC_RETURNVAL
Structure is used to hold the return value information for value-returning tokens.
Definition |
typedef struct _tag MAC_RETURNVAL { HSZ hszRequestor; DWORD dwMacroID; MAC_TOKENERROR eReturnCode; MAC_VARIABLE rv; } MAC_RETURNVAL, NEAR *NPMAC_RETURNVAL, FAR *LPMAC_RETURNVAL;typedef LPMAC_RETURNVAL FAR *LPLPMAC_RETURNVAL; |
Types |
MAC_RETURNVALStructure holding the token return value information. PMAC_RETURNVALNear pointer to a MAC_RETURNVAL structure. LPMAC_RETURNVALFar pointer to a MAC_RETURNVAL structure. LPLPMAC_RETURNVALFar pointer to a LPMAC_RETURNVAL. |
Members |
hszRequestorUnique application identifier that sent the token. dwMacroIDToken application identifier. Should always be0L. eReturnCodeToken error return code. (See MAC_TOKENERRORdefinition). rvToken return value. (See MAC_VARIABLEdefinition.) |
MAC_TOKEN
Structure used to represent GroupWise tokens; contains data identifying token as well as token parameter data. When allocating memory for a MAC_TOKEN structure, memory for the first parameter is provided. If the token has more than one parameter, additional contiguous memory must be allocated for MAC.PARAM.
Definition |
typedef struct _tag MAC_TOKEN{HSZ hszCommand;MAC_IPCVERSION version;HSZ hszRequestor;DWORD dwMacroId;ATOM atomApp;WORD wReserved;MAC_TOKENID wTokenId;MAC_COUNT cParam;DWORD dwFlags;DWORD dwReserved;MAC_PARAM rsParam[1];} MAC_TOKEN, NEAR *NPMAC_TOKEN, FAR *LPMAC_TOKEN; |
Types |
MAC_TOKENStructure used to represent actual tokens. NPMAC_TOKENNear pointer to a MAC_TOKEN structure. LPMAC_TOKENFar pointer to a MAC_TOKEN structure. |
Members |
szCommandIndicates where the token originated. versionIndicates the IPC version and must be set to 0 (==0). hszRequestorUnique application identifier. dwMacroIdApplication ID for this macro token. Should always be 0L. atomAppWhere the token is bound. wTokenIdToken ID. cParamNumber of token parameters. dwFlagsWriteable or non-writeable. dwReservedReserved. rsParamParameter data block pointer. rsParam[0] contains data for the first parameter. Allocate memory next to the first parameter for added parameters. See MAC_PARAMdefinition. |
MAC_TOKENERROR
Defines various error conditions resulting from token processing.
Definition |
typedef enum{ MAC_FUNCTION_OK = MAC_NO_ERROR, MAC_FUNCTION_UNKNOWN = MAC_BASE_GENERAL_ERRORS, MAC_FUNCTION_NOTFOUND, MAC_FUNCTION_CANCEL, MAC_FUNCTION_ERROR, MAC_FUNCTION_INVALID_PARM, MAC_FUNCTION_INVALID, MAC_FUNCTION_NOT_HANDLED, MAC_FUNCTION_RETURN_LATER} MAC_TOKENERROR; |
Types |
MAC_TOKENERROR Enumerated token processing error type. |
Members |
MAC_FUNCTION_OKFunction returned with no error condition. MAC_NO_ERRORFunction returned with no error condition. MAC_FUNCTION_UNKNOWNFunction is unknown. MAC_BASE_GENERAL_ERRORSFunction is unknown. MAC_FUNCTION_NOTFOUNDFunction resulted in a Not Found condition. MAC_FUNCTION_CANCELFunction resulted in a Cancel condition. MAC_FUNCTION_ERRORFunction resulted in an Error condition. MAC_FUNCTION_INVALID_PARMFunction contained an invalid parameter. MAC_FUNCTION_INVALIDFunction is invalid at this time. MAC_FUNCTION_NOT_HANDLEDFunction was not handled. MAC_FUNCTION_RETURN_LATERDelays from token handling function returns. |
MAC_TOKENID
A defined type used to pass token values.
Definition |
#define MAC_TOKENID WORD |
MAC_VALUE_TYPE
Defines various parameter types supported by tokens.
Definition |
typedef enum{ eValUndefined = VALUE_GENERAL_TYPES, eParmAny = VALUE_PARAMETER_TYPES, eParmBoolean, eParmByteSigned, eParmByteUnsigned, eParmCentimeters, eParmDwordSigned, eParmDwordUnsigned, eParmDWPUSigned, eParmDWPUUnsigned, eParmEnumeration, eParmFloat, eParmInches, eParmMillimeters, eParmPoints, eParmStringAnsi, eParmStringLabel, eParmStringOem, eParmStringWord, eParmStringVariable, eParmTokenID, eParmWordSigned, eParmWordUnsigned, eParmWPFname, eParmWPUSigned, eParmWPUUnsigned, eParmUserDialog, eValArrayDefinition = VALUE_VARIABLE_TYPES, eValBoolean, eValCentimeters, eValFloat, eValInches, eValInteger, eValMillimeters, eValPoints, eValString, eValStringAnsi, eValStringOem, eValWPUnits, eValZzzzzNoMore = VALUE_END_OF_TYPES} MAC_VALUE_TYPE; |
Types |
MAC_VALUE_TYPEEnumeration defining the various token parameter types. |
Members |
eParmUndefinedUndefined parameter type; do not use in 3rd-party DLLs. eParmAnyDecided at run_time; do not use in 3rd-party DLLs. eParmBooleanC Boolean type. eParmByteSignedSigned 8-bit value. eParmByteUnsignedUnsigned 8-bit value. eParmCentimetersDouble. eParmDwordSignedSigned 32-bit value. eParmDwordUnsignedUnsigned 32-bit value. eParmDWPUSignedSigned 32-bit unit (WPU). eParmDWPUUnsignedUnsigned 32-bit unit (WPU). eParmEnumerationEnumeration 16-bit value. eParmFloatDouble. eParmInchesDouble. eParmMillimetersDouble. eParmPointsDouble. eParmStringAnsiNull-terminated ANSI string. eParmStringLabelNull-terminated WPC word string containing a label reference. eParmStringOemNull-terminated OEM string. eParmStringWordNull-terminated WPC word string. eParmStringVariableWord string containing a variable name. eParmTokenIDUnsigned 16-bit value. eParmWordSignedSigned 16-bit value. eParmWordUnsignedUnsigned 16-bit value. eParmWPFnameNull-terminated ANSI string containing a filename. eParmWPUSignedSigned 16-bit unit (WPU). eParmWPUUnsignedUnsigned 16-bit unit (WPU). eParmUserDialogUser dialog buffer (like a string). eValArrayDefinitionArray definition variable type. eValBooleanC Boolean variable type. eValCentimetersDouble variable type. eValFloatDouble variable type. eValInchesDouble variable type. eValIntegerSigned 32-bit variable type. eValMillimetersDouble variable type. eValPointsDouble variable type. eValStringNull-terminated Word String variable type. eValStringAnsiNull-terminated ANSI string variable type. eValStringOemNull-terminated OEM string variable type. eValWPUnitsSigned 32-bit variable type. eValZzzzzNoMoreNot used. Only an indication of final value in enumeration. |
MAC_VARIABLE
Contains return value data for value-returning tokens.
Definition |
typedef struct _tag MAC_VARIABLE { HSZ hszCommand; HSZ hszRequestor; MAC_IPCVERSION version; MAC_MACROID dwMacroID; ATOM atomApp; WORD wReserved; MAC_TOKENID wSysVarID; WZ wzSymbolName[MAC_NAME_WZCOUNT + 1]; MAC_VALUE_TYPE eType; union { BOOL fData; VALUE_FLOAT drData; VALUE_INT lData; struct { WORD wStrLen; union { WZ wzData[1]; AZ azData[1]; } uStr; } stData; } uValue;} MAC_VARIABLE, FAR *LPMAC_VARIABLE; |
Types |
MAC_VARIABLEStructure containing the return value information for a token. LPMAC_VARIABLEFar pointer to a MAC_VARIABLE structure. MAC_IPCVERSION versionIndicates the IPC version and must be set to 0 (==0). |
Members |
hszCommandHandle to the string representing the command type. Either VariableGet or VariableSet. hszRequestorHandle to a string representing name of requesting application. dwMacroIDApplication defined macro identifier. atomAppApplication where the request is bound. wSysVarIDSystem variable identifier. wzSymoblNameWord string containing the symbol name. eTypeReturn value type. Must be in the range between VALUE_VARIABLE_TYPES+1and VALUE_END_OF_TYPES. (See MAC_VALUE_TYPEdefinition). uValueUnion containing the actual return value. |
Token Handling
This section discusses intercepting, building, and sending tokens.
Intercepting Tokens
GroupWise uses HandleToken and a valid function pointer to pass tokens to 3rd-party DLLs. DLLs can monitor tokens that the handling function receives. The handling function, which can use tokens as action triggers, has a default return value of DLL_HAN_NO_ERROR. When DLLs intercept and process value-returning tokens and do not provide GroupWise data, a system error can result. When DLLs intercept tokens that return no value, they need return only the value that indicates having processed the token. DLLs must provide return value data and allocate memory to contain it. The calling app and not DLLs deallocate return value memory when token is returned.
GroupWise supports two messages which can be sent to the link window to handle allocating memory for return value information. Applications should use this method of allocating memory for return value information in order for the calling application to be able to free the memory once the return value has been received.
Message |
WPLM_ALLOC_MEM |
|
Purpose |
Allocatetoken return value memory |
|
Example |
lpMem = SendMessage( hLinkWnd, WPLM_ALLOC_MEM, 0, (LPARAM)cbMemory ); |
Variable
|
Description
|
lpMem |
Longpointer to the block of memory allocated. |
hLinkWnd |
Handleto the link window. This is the HWND passedin to the token handler function. |
CbMemory |
Numberof bytes to allocate. |
Message |
WPLM_FREE_MEM |
Purpose |
Freetoken return value memory |
Example |
lpMem = SendMessage( hLinkWnd, WPLM_FREE_MEM, 0,(LPARAM)(DWORD)lpMem ); |
Variables
|
Description
|
lpMem |
Longpointer to the block of memory to be freed. |
hLinkWnd |
Handleto the link window. This is the HWND passedin to the token handler function. |
EventNotify Token
A special-case token sent to third-party DLLs to indicate GroupWise internal events. Do not generate in your DLLs.
Definition |
EventNotify( Event: { AppInitialized! BadCustomCommand! BadCustomMessage! ContextMenu! } REQUIRED Command: ANSISTRING REQUIRED)TokenID: AFTKN_EVENT_NOTIFYReturn Value: None |
Events |
AppInitialized!Indicates GroupWise is loaded and running. The command string is set to "GROUPWISE: App Initialized." BadCustomCommand!Indicates failed custom command setup. The command string is set to "GROUPWISE: Custom command improperly defined." BadCustomMessage!Indicates failed custom message setup. The command string is set to "GROUPWISE: Custom message improperly defined." ContextMenu!Indicates context-sensitive QuickMenu display on right click. The command string contains an ANSI-string menu identifier representation and the menu handle-both space delimited. Intercept the EventNotify token and monitor the ContextMenu! case to add GroupWise QuickMenu items. |
MENU_ID
|
QuickMenuContext
|
20 |
OLE Object. |
21 |
ShelfIcon or Quick Start Icon. |
22 |
AttachmentControl (composing message, attachment selected). |
23 |
AttachmentControl (reading message). |
24 |
SoundItem or Control. |
25 |
ItemList Control (In Box, Out Box, Calendar Views). |
26 |
Movie Control. |
27 |
Reserved. |
28 |
MainWindow Icons (In Box, Out Box, Calendar,Mail, Appointment, and so forth). |
29 |
In Box View. |
30 |
Out Box View. |
31 |
Trash View. |
32 |
Reserved. |
33 |
Reserved. |
34 |
Reserved. |
35 |
ItemList (preempted by local menu ID 25, butcan be accessed in the control space to theleft of the Column Manager). |
36 |
BasicView (might be overridden by more specific view menus). |
37 |
BasicItem View (might be overridden by more specific view menus). |
38 |
FolderList Control (In Box, Out Box, Trash, Calendar Views). |
39 |
Button Bar. |
40 |
CC:and BC: Controls (composing message). |
41 |
MainWindow's Shelf (no Shelf Icon selected). |
42 |
AttachmentControl (composing message, no attachment selected). |
43 |
Trash'sItem List (preempted by local menu ID 31but can be accessed in the control spaceto the left of the column Manager). |
44 |
Reserved. |
45 |
Reserved. |
46 |
StartDate/Auto-Date Control (composing message). |
47 |
EndDate/Duration Control (composing message). |
48 |
To:Control (composing message). |
49 |
MainWindow's Trash Icon. |
Building Tokens
Your DLLs can generate tokens, then send them to GroupWise for processing. To build a token, (1) Create token, parameter, and return value structures; (2) fill in token data; and (3) send token to link window. Although tokens can have multiple parameters, the token structure contains a declaration for one parameter structure because parameter memory must remain together. The following functions let you allocate and manage token structures.
AllocPtr. Used to allocate memory and called by InitToken().
LPVOID WINAPI AllocPtr ( int nSize, WORD wFlags ) { LPVOID lpvPtr; if ( (hMem = GlobalAlloc (wFlags, nSize)) != NULL ) { if ( (lpvPtr = GlobalLock (hMem)) != NULL ) return lpvPtr; else { GlobalFree (hMem); return NULL; } } else return NULL; }
FreePtr. Used to free memory allocated by ALLocPtr( ).
void WINAPI FreePtr ( LPVOID lpvPtr ) { HGLOBAL hMem; if (( hMem = (HGLOBAL)LOWORD(GlobalHandle(SELECTOROF(lpvPtr)))) != NULL) { if (!(GlobalUnlock (hMem))) GlobalFree (hMem); } }
InitTkn. Attempts to allocate a memory block to contain a token and its specified number of parameters.
void WINAPI InitTkn ( WORD nParmCount ) { //Allocate one less mac_param because 1 is already defined //in the MAC_TOKEN structure if ((lpTknData = (LPMAC_TOKEN)AllocPtr (sizeof (MAC_TOKEN) +(sizeof (MAC_PARAM) *(nParmCount-1) - + 100), GHND)) == NULL) { lpTknData = (LPMAC_TOKEN)NULL; } }
AddTknParm. Used to add parameter values to a previously allocated MAC_PARAM structure. It should be called once for each parameter a token has. If a token parameter is optional, the token value should be set to 0x8000 to inform GroupWise to ignore the parameter, otherwise it should be 00000.
void WINAPI AddTknParm ( MAC_VALUE_TYPE eType, WORD cParmNum, WORD wFlags, LPVOID lpvParm, DWORD dwParm, double dbParm ) { lpTknData--DataBlock[cParmNum].eType = eType;- lpTknData--DataBlock[cParmNum].wFlags = wFlags;- if (dwParm != 0) lpTknData--DataBlock[cParmNum].uData.dwValue = dwParm;- else if (dbParm != 0) lpTknData--DataBlock[cParmNum].uData.drValue = dbParm;- else if (lpvParm != NULL) lpTknData--DataBlock[cParmNum].uData.lpvPtr = lpvParm;- }
Sending Tokens
Once the token and parameter structures have been allocated and initialized, your DLL can send the token to GroupWise by sending a message to the link window.
SendTkn. Sends the token structure to the link window using SendMessage.
hLinkWindow is the link window handle passed to TokenHandle. WPLM_EXECUTE_VALRETURN_TOKEN is the msg parameter passed to TokenHandle.
lpTPHData is a long pointer to the TPH_RETURNVAL structure.
SendMessage returns a value indicating the token processing result defined below. If the message is successful and the token can return a value, TPH_RETURNVAL structure (lpTPHData) is filled in with data.
DWORD WINAPI SendTkn ( MAC_TOKENID wTknID, WORD nParmCnt, LPLPMAC_RETURNVAL lplpTknReturn ) { TPH_RETURNVAL TknData; LPTPH_RETURNVAL lpTPHData; // Fill global token structure // lpTknData--hszCommand = NULL;- lpTknData--hszRequestor = (HSZ)hRequestor;- lpTknData--dwMacroID = 0L;- lpTknData--wTokenID = wTknID;- lpTknData--cParam = nParmCnt;- lpTknData--dwFlags = NULL;- lpTknData--dwReserved = NULL;- // Fill ReturnVal structure // TknData.lpTokenData = lpTknData; TknData.lplpmacRetVal = lplpTknReturn; lpTPHData = &TknData;& // Value-returning token // dwRV = SendMessage (WPLnkWnd, WPLM_EXECUTE_VALRETURN_TOKEN, 0, (LPARAM)lpTPHData); FreePtr (lpTknData); return dwRV; } // End of SendTkn( ) function //
ReturnValues
|
Description
|
DLL_HAN_NOT_HANDLED |
The token was not processed. |
DLL_HAN_NO_ERROR |
The token was processed with no error. |
DLL_HAN_NOT_FOUND |
Thetoken resulted in a GroupWise "not found" condition. |
DLL_HAN_CANCEL |
Theuser cancelled the function. |
DLL_HAN_TOKEN_ERROR |
The token was not valid. |
DLL_HAN_PARM_ERROR |
Oneor more of the parameters were invalid. |
Memory. GroupWise allots memory to contain a return value when a DLL sends it a value-returning token. The DLL must free memory allotted for the return value structure by sending WPLM_FREE_MEM to the link window as outlined in Intercepting Tokens above.
Building Tokens
Your DLLs can generate tokens, then send them to GroupWise for processing. To build a token, (1) Create token, parameter, and return value structures; (2) fill in token data; and (3) send token to link window. Although tokens can have multiple parameters, the token structure contains a declaration for one parameter structure because parameter memory must remain together. The following functions let you allocate and manage token structures.
AllocPtr
Used to allocate memory and called by InitToken( ).
LPVOID WINAPI AllocPtr ( int nSize, WORD wFlags ) { LPVOID lpvPtr; if ( (hMem = GlobalAlloc (wFlags, nSize)) != NULL ) { if ( (lpvPtr = GlobalLock (hMem)) != NULL ) return lpvPtr; else { GlobalFree (hMem); return NULL; } } else return NULL; }
FreePtr
Used to free memory allocated by ALLocPtr( ).
void WINAPI FreePtr ( LPVOID lpvPtr ) { HGLOBAL hMem; if (( hMem = (HGLOBAL)LOWORD(GlobalHandle( SELECTOROF(lpvPtr)))) != NULL) { if (!(GlobalUnlock (hMem))) GlobalFree (hMem); } }
InitTkn
Attempts to allocate a memory block to contain a token and its specified number of parameters.
void WINAPI InitTkn ( WORD nParmCount ) { //Allocate one less mac_param because 1 is already defined //in the MAC_TOKEN structure if ((lpTknData = (LPMAC_TOKEN)AllocPtr (sizeof (MAC_TOKEN) +(sizeof (MAC_PARAM) *(nParmCount-1) + 100), GHND)) == NULL) { lpTknData = (LPMAC_TOKEN)NULL; } }
AddTknParm
Used to add parameter values to a previously allocated MAC_PARAM structure. It should be called once for each parameter a token has. If a token parameter is optional, the token value should be set to 0x8000 to inform GroupWise to ignore the parameter, otherwise it should be 00000.
void WINAPI AddTknParm ( MAC_VALUE_TYPE eType, WORD cParmNum, WORD wFlags, LPVOID lpvParm, DWORD dwParm, double dbParm ) { lpTknData- DataBlock[cParmNum].eType = eType; lpTknData- DataBlock[cParmNum].wFlags = wFlags; if (dwParm != 0) lpTknData- DataBlock[cParmNum].uData.dwValue = dwParm; else if (dbParm != 0) lpTknData- DataBlock[cParmNum].uData.drValue = dbParm; else if (lpvParm != NULL) lpTknData- DataBlock[cParmNum].uData.lpvPtr = lpvParm; }
-->
Sending Tokens
Once the token and parameter structures have been allocated and initialized, your DLL can send the token to GroupWise by sending a message to the link window.
SendTkn
Sends the token structure to the link window using SendMessage.
hLinkWindow is the link window handle passed to TokenHandle. WPLM_EXECUTE_VALRETURN_TOKEN is the msg parameter passed to TokenHandle.
lpTPHData is a long pointer to the TPH_RETURNVAL structure.
SendMessage returns a value indicating the token processing result defined below. If the message is successful and the token can return a value, TPH_RETURNVAL structure (lpTPHData) is filled in with data.
DWORD WINAPI SendTkn( MAC_TOKENID wTknID, WORD nParmCnt, LPLPMAC_RETURNVAL lplpTknReturn ) { TPH_RETURNVAL TknData; LPTPH_RETURNVAL lpTPHData; // Fill global token structure // lpTknData- hszCommand = NULL; lpTknData- hszRequestor = (HSZ)hRequestor; lpTknData- dwMacroID = 0L; lpTknData- wTokenID = wTknID; lpTknData- cParam = nParmCnt; lpTknData- dwFlags = NULL; lpTknData- dwReserved = NULL; // Fill ReturnVal structure // TknData.lpTokenData = lpTknData; TknData.lplpmacRetVal = lplpTknReturn; lpTPHData = TknData; // Value-returning token // dwRV = SendMessage (WPLnkWnd, WPLM_EXECUTE_VALRETURN_TOKEN, 0, (LPARAM)lpTPHData); FreePtr (lpTknData); return dwRV; } // End of SendTkn( ) function //
Return Values |
Description |
DLL_HAN_NOT_HANDLED |
The token was not processed. |
DLL_HAN_NO_ERROR |
The token was processed with no error. |
DLL_HAN_NOT_FOUND |
The token resulted in a GroupWise "not found" condition. |
DLL_HAN_CANCEL |
The user cancelled the function. |
DLL_HAN_TOKEN_ERROR |
The token was not valid. |
DLL_HAN_PARM_ERROR |
One or more of the parameters were invalid. |
Memory
GroupWise allots memory to contain a return value when a DLL sends it a value-returning token. The DLL must free memory allotted for the return value structure by sending WPLM_FREE_MEM to the link window as outlined in Intercepting Tokens above.
* Originally published in Novell AppNotes
Disclaimer
The origin of this information may be internal or external to Novell. While Novell makes all reasonable efforts to verify this information, Novell does not make explicit or implied claims to its validity.