Adding C3PO Custom Button with Object API in VB
Articles and Tips: article
Developer Support Engineer
Americas Developers Support
01 Aug 2000
A Custom 3rd Party Object (C3PO) provides developers the ability to add more functionality to the existing GroupWise Client. This article provides an introduction on the C3POWizard and the classes it creates, an overview of the creation of a custom button, and the usage of GroupWise Object APIs.
Copyright ©2000 by Novell, Inc. All rights reserved. No part of this document may be reproduced or transmitted in any form or by any means, electronic or mechanical, including photocopying and recording, for any purpose without the express written permission of Novell.
All product names mentioned are trademarks of their respective companies or distributors.
A C3PO is a Custom 3rd Party Object (with no association with R2D2 from Star Wars) that allows an application to be added to the GroupWise client. With a C3PO, an application can add all sorts of functionality to the GW client -- as if the added features come with the client. These features include the ability to:
add new menus
add menu items
add separators to existing menus
add new buttons (with user-defined bitmaps) to the toolbar
define new custom message types with their own custom icons
add context menus
modify or enhance the functionality of existing menus
trap predefined commands and events
Getting Started with the C3POWizard
The C3PO wizard is available at http://developer.novell.com/ndk/downloadaz.htm under GroupWise 5.x C3PO(the file name is gwc3po_all.exe). The file includes the C3PO Tracer, header files, and samples as well as the C3POWizard. After extracting the file, the wizard is placed under C:\Novell->NDK->GroupWise->Gw_5->C3po-> Tools->C3POWizard. This is only the default directory, you are able to use another directory (i.e. change Novell to another directory). The samples are included under other subdirectories beneath the C3POWizard subdirectory.
After starting the wizard, the first input required by the wizard is naming the C3PO and placing it in a specific directory. You are able to specify which feature(s) C3PO should handle and where to place the customized feature(s). The wizard will create workspaces (projects) in one of following languages: C++, Delphi, and Visual Basic. In Visual Basic and Delphi you can also choose whether to write a DLL or an exe application.
Classes Created by the Wizard
The C3PO wizard creates five classes: C3POServer, EventMonitor, IconFactory, GWCommand, and CommandFactory. In Visual Basic the wizard also creates a Startup.bas file, a readme text file, and the project that you will use as your application (in this article I focus mainly on Visual Basic).
Within the C3POServer class several objects are instantiated including the C3POManager. The C3POManager is set to the objGWManager which interacts with all the interfaces (interface is defined as a contract between an object and its clients), manages all the handlers, and carries out all the commands required of it by the classes discussed later. Overall the C3POServer class is somewhat like a Constructor and Destructor. It includes both Init and DeInit methods.
The EventMonitor class simply has one method -- Notify. Notify is passed to monitor low level actions which are Delivery, Ready, ShutDown, and Overflow. Delivery indicates that an item has been sent to the GroupWise mailbox. The Ready notification occurs right after GroupWise is initialized. ShutDown notifies the C3PO server when shut down is occurring or when the user is exiting GroupWise. Overflow notifies the C3PO server when over flow errors occur. The Overflow event occurs when there are too many messages being delivered at the same time to the Post Office Agent that it doesn't have time to fire the Delivery event for each of them.
The IconFactory class is used to retrieve icons that represent message classes or their state. For example, in the GroupWise client, notice the icons that look like envelopes next to each message. The IconFactory (GetIcon Method) allows you to change these icons for opened and unopened messages. However, the IconFactory will not allow inheritance (meaning two C3POs cannot both offer icons for the same message).
The GWCommand class has more methods than the previously mentioned classes. The Execute() method is the most important to developers. When an event is captured or when you click on the button you have created through a C3PO, the C3POManager will call the Execute method. This is where you add your code that is specific to the C3PO you are developing. Figure 1 shows the contract between the client and the GWCommand object (its interface). The other classes created by the wizard have a similar interface --the only difference being the methods that are invoked.
Figure 1: Contract between the client and the GWCommand object.
The CommandFactory class is used to manage commands in GroupWise. You are also able to determine the area of the GroupWise client where you are going to place your button or customized menu item. It is within the Init method that will tell GroupWise what User Interface item will be modified. According to the Init method the CustomizeContextMenu, CustomizeMenu, and/or the CustomizeToolBar functions will be called. The BuildCommand method interacts with the WantCommand, and the BaseCommand methods. These properties handle predefined commands that are beyond the scope of this article.
The wizard creates other files in Visual Basic as well -- Readme.txt, Startup.bas, the .wiz file and the project (.vbp) file. Within the Startup.bas file the C3PO is registered and unregistered through the RegC3PO() and UnRegC3PO() calls. The Readme.text file describes the .wiz file and the other files created by the wizard. The project file includes all the classes previously mentioned.
Now let's begin customizing the toolbar. I have created a C3PO that shows the amount of emails, appointments, tasks, and notes sent for the day, week, and month. It also lists uncompleted tasks and appointments.
To add a button to the toolbar, begin by creating a custom 16x16 bitmap image. These images can be downloaded from the Internet or other sources. However, a bitmap can be created using any application such as Paint or VC++. Be aware that the GroupWise client will not show anything larger than a 16x16 bit image. If your image is larger than 16x16 only the top left corner of the image will be displayed.
Incorporate Bitmap Image
You can incorporate your bitmap image into either a new EXE or an ActiveX DLL. To do so in Visual Basic:
Click on File->New Project. (A popup will allow you to choose what type of project to create. In my C3PO I have chosen ActiveX DLL.)
Click Add-Ins-> Add-In Manager on the toolbar.
Choose VB 6 Resource Editor (if the Resource Editor has already been created steps 3 and 4 can be ignored).
Click on the new green icon (looks like a portion of a cube) on the toolbar to bring up the VB Resource Editor.
On the toolbar of the popup screen Click the icon for adding a bitmap.
Retrieve your custom 16x16 bitmap (VB will name the bitmap 101).
Double click on 101 and change the ID to a string name that will describe the image. (In my C3PO I changed 101 to the string "Diamond". Changing the bitmap to a string name is not necessary but it makes the bitmap more distinguishable in case another bitmap is added. By this time, the project should be saved under a new name (the wizard calls its DLL icon.DLL). I gave my DLL the name of "bitmap.DLL". The DLL I created has several different images in case I want to use another image with the same DLL.)
Click File->Make bitmap.DLL, to create the DLL file. The file will later need to be saved into the same directory as the C3PO.
Create the C3PO in Visual Basic from the C3POWizard
Now that the DLL has been created, you can begin creating the C3PO in Visual Basic from the C3POWizard.
Start the wizard. The file is called C3poWizard.exe.
The first form asks for the name of the C3PO. My C3PO gives the statistics of emails sent for the day, week, and month, so I called mine "Statistics". Along with the name of the project or C3PO the wizard also asks for the path in which to save the files, so type in the appropriate directory.
Just below the path and C3PO name, the wizard asks which items you would like your C3PO to handle. I have chosen just the Toolbars for my Statistics C3PO. My objective is to only add a button to the toolbar .
Next, the wizard asks which toolbar in the GroupWise client you would like to add the button to. I have added to the GW.CLIENT.WINDOW.BROWSER GW.MESSAGE.MAIL, GW.MESSAGE.APPOINTMENT, GW.MESSAGE.NOTE, and GW.MESSAGE.TASK. Thus, every time a user sends an appointment, mail, note, or task they will see my custom button.
Next, the wizard asks for a new toolbar button in the window browser since I have previously asked to add my custom button to the windows browser.
Click New Toolbar Button. It is here that the name of the variable for the custom button is given. You may also add the caption and a tool tip. The caption for my C3PO is "Statistics". As for the tool tip, you can add "Statistics for Messages Sent", or you can leave that space blank. I have given the variable name of STATS_ID.
Click Next. Notice that similar forms follow for each toolbar I have specified earlier. In other words, you will have to add a new toolbar button to GW.MESSAGE.APPOINTMENT, GW.MESSAGE.NOTE, and GW.MESSAGE.TASK. The steps for adding the variable, caption, and tooltip need to be repeated for each toolbar.
The data is then collected by the wizard and is shown on a listbox for you to check. If the data you entered is correct click Next.
Now, you are given the option of three different language to create your C3PO in. These are also the three languages that are officially supported by Novell Developer Support. For my Statistics C3PO, I have chosen Visual Basic 6.0. You are then asked if you would like to create an exe. If you choose "no" than a project is not created and you will need to create your own DLL project. I chose "yes" and "Statistics.vbp" was created. The wizard then proceeds to show you the path where your C3PO files are saved and all the files that have been created.
Now that the C3PO has been created let's take a look at each class. In the Commandfactory class, the Init() method in my C3PO has the following:
Init = eGW_CMDINIT_TOOLBARS
I want to add my C3PO to the toolbars and not the context menus or menus, otherwise the Init method could also have eGW_CMDINIT_MENUS and eGW_CMDINIT_CONTEXT_MENUS. Below is the code in Visual Basic added by the wizard for my C3PO in the CommandFactory class in the CustomizeToolbar method.
Custom Button for the Browser Context
If sGWContext = "GW.CLIENT.WINDOW.BROWSER" Then ' Check for correct context Dim Cmd00 As New GWCommand ' Build GWCommand object Let Cmd00.PersistentID = STATS_ID ' Set persistent ID for GWCommand object Let Cmd00.ToolTip = "" ' Set Button tooltip Set Button = objGWToolbar.ToolbarItems.Add("Incoming/Outgoing Statistics", Cmd00) ' Add button to toolbar FilePath = App.Path "\BitMaps.dll" ' Set bitmap for Button 'C3PO WIZARD icons.dll can be replaced by the full path name of any .exe or .dll thatcontains a 16x16 and a 32x32 pixel bitmap. ' BUTTON_1 can be replaced with the name of the bitmap contained in the .exe or .dll Call Button.SetBitmap(FilePath, "DIAMOND") ' set were the bitmap is found and its name End If
The context is passed into the method and this determines where the button will be placed. The same "if" block as shown above is also repeated for the following contexts: "GW.MESSAGE.APPOINTMENT"; "GW.MESSAGE.MAIL"; "GW.MESSAGE.NOTE"; and "GW.MESSAGE.TASK". In the above code, the GWCommand is instantiated and the PersistentID is given. Remember the variable given when I created my C3PO with the wizard? It is now used as the PersistentID called "STATS_ID". The filePath is given and it is here that I add my BitMaps.DLL. Notice that I changed the default icons.DLL to BitMaps.DLL. The name of the icon from icons.DLL was called "BUTTON_1". I have changed "BUTTON_1" to "DIAMOND", as my custom button is named "DIAMOND". I can also use a different bitmap for each of my contexts, but I chose to keep the same image for all the contexts. By this time it would be necessary to put or copy the DLL created earlier in the same directory as the C3PO.
Now let us take a look at the Execute method in GWCommand.cls. The wizard creates the following code:
Public Sub Execute()Dim res On Error GoTo Execute_Err Select Case m_sPersistentID Case STATS_ID: Res = MsgBox("Incoming/Outgoing Statistics Toolbar Button", vbOKOnly, "Execute") 'C3PO WIZARD Put execute command code here for Incoming/Outgoing Statistics Custom menu. Case Else MsgBox "Unsupported Case" End Select Exit SubExecute_Err: ...
In my C3PO I have commented out the line "Res = MsgBox("Incoming/Outgoing Statistics Toolbar Button", vbOKOnly, "Execute")" and "Form1.Show" is added. Form1 is my own popup when the user clicks on my custom button. My C3PO then proceeds to get a count of all the emails, appointments, tasks, and notes that the user has had for the current day, current week, and the current month. It also provides a list of uncompleted tasks and appointments for the day, week, and month according to the tab.
A form is added and created through Visual Basic. To get the data, I call the object APIs available from the GroupWise SDK. A full detailed explanation of the object API is not given in this article, however code is displayed to show how I obtained the data provided by my custom button.
In my C3PO, I called the find method of the AllMessages object to get the numbers I am looking for in my C3PO. The following shows how I login to GroupWise and then retrieve all the incoming messages, appointments, tasks, and notes for the day. A search string is passed into the Find method and I do a further search on the list that is returned by the first Find. I then display the results on the label captions on the form.
Finding Today's Incoming Messages
Set objGW = CreateObject("NovellGroupwareSession") Set objAccount = objGW.Login 'Start with incoming messages for todaysearchString = "(BOX_TYPE = INCOMING)" Set oMessageList1 = objAccount.AllMessages.Find(searchString)FurtherSearch = "(DELIVERED_DATE = TODAY)" Set oMessageList2 = oMessageList1.Find(furtherSearch)Label19.Caption = oMessageList2.CountEmailType = "(APPOINTMENT)" Set oMessagelist3 = oMessageList2.Find(emailType)Label20.Caption = oMessagelist3.CountEmailType = "(TASK)" Set oMessagelist3 = oMessageList2.Find(emailType)Label21.Caption = oMessagelist3.CountEmailType = "(NOTE)"Label22.Caption = oMessagelist3.Count
To get the list of uncompleted tasks is a little different, but not much. The idea is the same, a search string is passed into the Find method, and a further search string is put into the Find method using the returned Messagelist object returned by the first Find call. Other filter expressions are also available through the GroupWise Object API SDK (Available at: http://developer.novell.com/ndk/doc/docui/index.htm#../gwobjapi/gwobjenu/data/h7ikbsqg.htm). The results of the find are added to a list box.
lTasks.Clear emailType = "(TASK AND DUEEND_DATE <= TODAY)"< Set oMessageList1 = objAccount.AllMessages.Find(emailType)< searchString = "(ACCEPTED AND NOT COMPLETED)"< Set oMessageList2 = oMessageList1.Find(searchString)< If oMessageList2.Count << 0 Then< For Each oTask In oMessageList2< lTasks.AddItem "Subject: " < oTask.Subject< lTasks.AddItem " Sender: " < oTask.Sender< lTasks.AddItem ""< Next< End If
After the application is compiled and an executable or DLL made, you are now ready to register your C3PO. There are several ways to register a C3PO. One way is through MSDOS. Go to the command prompt in MSDOS and switch to the directory containing your C3PO. Type the name of the executable followed by "/r". For my C3PO, my subdirectory and command is this:
The C3PO is now registered and can be found in the Registry. To double check, go to:
At the prompt type "regedit". The C3PO (in Windows 95) should be under HKEY_LOCAL_MACHINE-> SOFTWARE->Novell->Groupwise->5.0->C3PO->DataTypes. Statistics.C3POServer is under GW.WINDOWS.BROWSER, GW.MESSAGE.APPOINTMENT, GW.MESSAGE.NOTE, AND GW.MESSAGE.TASK.
Now, run the GroupWise client and the custom button should be in the toolbars that you have specified.
Note: If you already have another C3PO registered with the GW client that also adds to the browser, message, appointment, note, or task, you will not be able to see the C3PO you just created. You will need to unregister the previous C3PO or change the order of the C3PO within the registry. Only the first C3PO will show up in the contexts given.
A Custom 3rd Party Object provides developers the ability to add more functionality to the existing GroupWise Client. The application or C3PO can use further technologies given by the GroupWise SDK. Although only the GroupWise Object API example is given in this article, you can also use GroupWise 5.x Tokens, GroupWise 5.x Mapi, and GroupWise Controls for ActiveX (just to name a few).
Not all C3POs need to call GroupWise technologies. For instance, a calculator can be added as a C3PO, which uses Windows API (Sample available at http://developer.novell.com/support/sample/tids/gw5c3x21/c3pocalc.pas). The wizard creates the necessary skeleton (i.e. the classes and other files) and allows you to determine which context to add to as well as which event to capture. The rest of the application is up to you to add. In my application I chose to use the find method to gather data about the current user and to display that data in a form when the user clicks on my custom button. C3POs are simple to understand and allow you to customize the GroupWise client to your environment and needs.
* Originally published in Novell AppNotes
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.