For Programmers - Using ICQ From Delphi In 10 Simple Steps
 
Step 1 - Download ICQ
 
Go to www.icq.com and download the latest version. Or, if you are pleased with your current version you can keep it. Sometimes older versions of ICQ are more stable than the latest build.
 
   
 
Step 2 - Download the ICQ API
 
Go to www.icq.com/api, register and download the ICQ API. You will receive an email containing *VERY* important information. Keep this email safe, or write down the connection information.
 
   
 
Step 3 - The ICQ units
 

From the API you have just downloaded, get the ICQMAPI.DLL. This dll is in charge with the link from your program to the ICQ. Put it in the same folder with your program. This is *NOT* an ActiveX dll, so it does not need to be register.

In Delphi, the Uses clause must include the ICQ units. This units are just translations from the API C headers to Object Pascal. Download them here, or copy them from here.

There are three units:

ICQAPIData - the programming structures needed for ICQ and three procedures for cleaning.

ICQAPICalls - the main functions for using the ICQ.

ICQAPINotifications - functions for the ICQ events. Use them for the list of parameters.

 
 

uses

ICQAPIData, ICQAPICalls, ICQAPINotifications

 
Step 4 - The ICQ connection
 

First you need to connect to ICQ. This is done by the function ICQAPICall_SetLicenseKey, witch has three parameters, the connection information from the email received with the API.

After that, it is recommended to find the version of the API that the ICQ version is supporting. Use the function ICQAPICall_GetVersion.

 
 

var

iVersion: integer; // global variable

if ICQAPICall_SetLicenseKey('name', 'pass', 'XXXXXXXXXXXXXXXXX') = True then //...

if ICQAPICall_GetVersion(iVersion) = True then //...

 
Step 5 - The owner
 

The owner is the user that is currently using the ICQ. The function ICQAPICall_GetFullOwnerData retrieve the owner informations in a PBSICQAPI_User structure.

After getting the desired information the cleaning function ICQAPIUtil_FreeUser must be called.

 
 

var

pUser: PBSICQAPI_User;

if ICQAPICall_GetFullOwnerData(pUser, iVersion) = True then

begin

OwnerUIN := pUser^.m_iUIN; // Owner's ICQ number

OwnerNickname := pUser^.m_szNickname; // Owner's nickname

ICQAPIUtil_FreeUser(pUser);

end //...

 
Step 6 - Online users list
 

The function ICQAPICall_GetOnlineListDetails retrieve the list of the users that are currently online into an array of PBSICQAPI_User structures.

Anyway, the structures will contain only the UINs (ICQ numbers) of the users. To get the nicks and other information use the function ICQAPICall_GetFullUserData for each user.

Finally, call the function ICQAPIUtil_FreeUsers after getting the information.

 
 

type

TUserList = Array of PBSICQAPI_User;

var

iCount: integer;

ppUsers: TUserList;

if ICQAPICall_GetOnlineListDetails(iCount, @ppUsers) = True then

begin

for i := 0 to iCount - 1 do

begin

UserUIN := ppUsers[i]^.m_iUIN; // Only the UIN of the user is charged at this moment

ICQAPICall_GetFullUserData(ppUsers[i]^, iVersion);

UserNick := ppUsers[i]^.m_szNickname; // Now the whole structure is filled

end

ICQAPIUtil_FreeUsers(iCount, @ppUsers);

end //...

 
Step 7 - Sending
 

Some of the send dialogs of ICQ can be accessed with API functions. Anyway, the user must validate the ICQ send dialog, except for the request for an external application, which can be automatically send.

These functions are:

ICQAPICall_SendFile - the send file dialog.

ICQAPICall_SendMessage - the message window, containing the message.

ICQAPICall_SendURL - the URL send dialog.

ICQAPICall_SendExternal - the request for an external application.

 
 

// Send file example

if ICQAPICall_SendFile(ReceiverUIN, PChar(sFileNamePath)) = True then // ...

 
Step 8 - Events
 

For each event in the ICQAPINotifications unit, must be defined a procedure that will have the same parameter list as the event. In this procedure the event will be treated. The declaration of the procedure must be followed by the stdcall keyword. Is a good practice to name the procedure as "On" and the name of the event.

Then, the event must be register, so the ICQ to know which procedure to call when the event is happening. This could be done in a procedure for all the events that wish to be registered. Call the ICQAPIUtil_SetUserNotificationFunc for each event procedure, and then ICQAPICall_RegisterNotify for all the events.

It is possible that after an event call the application to lose the event registration with the ICQ. So, is recommended to put the previous procedure in a timer, this way verifying also if the ICQ is still running OK.

When want to disconnect from ICQ, the function ICQAPICall_unRegisterNotify must be called to inform the ICQ that the notification is no longer needed.

 
 

// Events declaration

procedure OnOnlineListChange(iType: integer); stdcall;

procedure OnOwnerChange(iUIN: integer); stdcall;

procedure OnFileReceived(pszFileNames: PChar); stdcall;

// stdcall is *VERY* important

// implementation code for this procedures...

 

// the registration procedure

procedure ICQRegisterNotify;

var piEvents: array[1..3] of byte;

begin

piEvents[1] := ICQAPINOTIFY_ONLINELIST_CHANGE;

piEvents[2] := ICQAPINOTIFY_OWNER_CHANGE;

piEvents[3] := ICQAPINOTIFY_FILE_RECEIVED;

ICQAPIUtil_SetUserNotificationFunc(piEvents[1], @OnOnlineListChange);

ICQAPIUtil_SetUserNotificationFunc(piEvents[2], @OnOwnerChange);

ICQAPIUtil_SetUserNotificationFunc(piEvents[3], @OnFileReceived);

if ICQAPICall_RegisterNotify(iVersion, 3, @piEvents) = True then // ...

end;

 

// the timer

procedure TfrmMain.TimerICQTimer(Sender: TObject);

begin

// ...

ICQRegisterNotify;

// ...

end;

 

// disconnect from ICQ

if ICQAPICall_unRegisterNotify = True then // ...

 
Step 9 - Trap the errors
 

As can be seen from the examples, each API function returns a Boolean value. This value must always be tested for success, and in case of fail to be processed accordingly. So, if an API function fails, is recommended to disconnect from ICQ.

Due to the nature of ICQ and the internet, a lot of things could go wrong (internet connection down, local network down, proxy checks that disconnect the ICQ, slow connection that makes ICQ to reconnect etc.) so is highly recommended to protect your code very carefully (try... finally for every piece of code!) and to always have an way out (don't hang the application waiting for ICQ to do something, it may never will).

Also, even if the ICQ API is a little limited, try to stay on its limits and don't bypass it with code tricks. The result could be unpredictable and different from version to version.

 
   
 
Step 10 - The ICQ look & feel
 

People using ICQ are used to certain features such as the tray icon which tells them if they are connected, the blinking task bar title when a message is arriving, the sizeable window panels, etc. Try to provide the same features, so the application to be easier to use. Things such as the trayicon, the blinking title (FlashWindow function) are easy to do in Delphi.

Read carefully the documentation that came with the API, and for any problems is recommended to search groups.google.com. Also check the Windows interface guidelines from Microsoft.

Good luck!