Advertisment

API Programming

author-image
PCQ Bureau
New Update

Till now, we’ve concentrated on switching over to API

calls for creating objects, etc, making as little use of Delphi as possible. Last time, we

managed to create a project (application) which was written using API calls. We now know

of the message loop, and how the application will handle events that happen on a child

object.

Advertisment

One of the most common object that one sees in a Windows

program is a "menu-bar". The menu-bar is what gives all Windows programs the

standard look, and familiarity with the interface. For example, even someone who has

worked in the Windows environment only for a short period, will know that Exit would be

under the File menu.

In this issue, we’ll see how to build a menu in our

application. For the sake of simplicity, we’ll continue with the same application

that we’ve been developing (the text editor), but will now remove the buttons that we

added earlier, and trade them in for the menu. Also, we’ll discuss another important

aspect–resource files.

align="right"> #define IDM_OPEN 301



#define IDM_SAVE 302


#define IDM_EXIT 399


#define IDM_CUT 401


#define IDM_COPY 402


#define IDM_PASTE 403


#define IDM_SELECTALL 404






api MENU



      BEGIN

     POPUP

"&File"



      BEGIN


MENUITEM "&Open", IDM_OPEN


MENUITEM "&Save", IDM_SAVE


MENUITEM SEPARATOR


MENUITEM "E&xit", IDM_EXIT


       END


       POPUP "&Edit"


BEGIN


  MENUITEM "Cu&t", IDM_CUT


  MENUITEM "&Copy", IDM_COPY


   MENUITEM "&Paste", IDM_PASTE


   MENUITEM "Select &All", IDM_SELECTALL


END


     END












Advertisment

A resource is binary data that a resource compiler or

developer adds to an application’s executable file. The resource describes an icon,

cursor, menu, dialog box, bitmap, font, etc. In our case, we want to add a menu to our

application. Thus, we’ll first have to create a resource which defines the menu. The

resource is usually written as a plain text file, so it needs to be compiled to a binary

resource file using a resource compiler. All Windows compilers ship with some resource

compiler, and Delphi ships with brcc32.exe (borland resource compiler). The source (text)

for the resource is kept in .RC files, which becomes .RES when compiled. This .RES file

can then be included in the application, and the data in it can be referred from anywhere.

There are several reasons why menus should be put in as

resources. Mainly, it’s much simpler to design complex menu structures when you just

have to write down the structure and let Windows take care of the actual creation of

objects. Also, when the menu is in a separate resource, it’s very convenient to

modify the resource if need be, such as, when the language of the menu items needs to be

changed. Let’s take a look at the resource file for our menu (see the sidebar).

In the first part of the resource file (called

"api.rc" in our case), we define the constants that we’ll be using as

identifiers. If you recall, these identifiers will be used to identify the child objects

when we receive a WM_COMMAND message. The menu starts with the line "api MENU". Here,

we specify the name of the resource (api), and also the type (MENU). Thus, this line

signifies the start of the definition of a menu called api. Note that the body of the menu

and also of the items is enclosed in the BEGIN-END blocks. This is not because of Delphi,

but because this is the standard way of writing a resource no matter what language or tool

one uses.

Advertisment

The first thing we specify in the menu is the name of the

drop-down or pop-up, as it’s called here. To do this, we say:

POPUP "MenuName"

where "MenuName" is what appears in the menu,

which will be clicked to get the drop down. In our case of the text editor, we’ll

have two pop-ups, namely, File and Edit.

Advertisment

For each pop-up, we then specify the items. For example,

for the pop-up File, we’ll have Open, Save, and Exit as the menu items. When we list

the menu items, Windows knows that all these belong to the File pop-up, as they have been

enclosed in the BEGIN-END statements for the same.

While specifying the menu item, we specify the keyword

"MENUITEM", followed by the string that’ll be displayed (the actual menu

item), and the identifier that our application will use to link this menu item to some

code (separated by a comma). Instead of the menu item’s name, we can include another

keyword "SEPERATOR", which will make Windows draw a horizontal line instead of

the menu item there. This is used to logically group several menu items.

After specifying all the pop-ups and menu items, we close

the menu by putting an END in the end, to match the opening BEGIN, and we save the file.

This will create the source for the resource file. To actually convert it to a Windows

resource, we need to compile it. For that, on the DOS prompt type: brcc32 api.rc.

Advertisment

(This assumes that brcc32 is in the search path, which it

normally is). This will create a compiled Windows resource api.res in the same directory.

We now include the resource in our program, using the $R compiler directive. Our complete

program now looks like this (including the functionality for all the Edit menu items).

Note how simple it’s to link the menu items and perform operations, just as

cut/copy/paste, etc, with just one line of code.

Note that simply including the resource containing the menu

will not suffice. We still have to link the menu to the window that’ll contain that

menu. This is done at the time of defining the window class, in the TWndClass structure:

lpszMenuName:=PChar(‘api’);

Advertisment

This is the name that we specified in the resource file.

This links the menu in the resource, with the window that we are creating. Note that the

processing of the menu items is the same as when we used buttons, by checking the

identifiers when a WM_COMMAND is received.

As you might’ve noticed, making menus is a simple

task, but not very straightforward. Nothing can beat the simplicity of using a WYSIWYG

menu designer that all RAD tools include. However, when you notice that our program still

compiles to a 16 kB executable, one is tempted to go in for API every now and then.

It’s up to you to decide which method to adopt when. Till next time then, happy

coding.

  program ed;



  uses


    Windows, Messages;


    var


   eh:HWND;


msg:TMsg;


const


      idm_open=301;


      idm_save=302;


      idm_exit=399;


      idm_cut=401;


      idm_copy=402;


      idm_paste=403;


      idm_selectall=404;


{$R api.res}


   function windproc (wh:HWND; msg:U INT; wparam,lparam: wparam):
longint;stdcall;



begin


  result:=0;


  case msg of


  WM_CREATE:


begin


   eh:=CreateWindow (Pchar(‘Edit’),PChar(‘The stuff
inside...’),



      WS_VISIBLE+W0,00,632,352,


      wh,0,hInstance,nil);


         end;


      WM_DESTROY:PostQuitMessage(0);


      WM_COMMAND:


begin


   if hiword(wparam)=BN_CLICKED then


   case loword(wparam) of


     idm_open:setwindowtext (eh,PChar(‘Open button
clicked.’));



    idm_save:setwindowtext(eh,PChar(‘Save button clicked.’));


     idm_exit:sendmessage(wh,WM_CLOSE,0,0);


     idm_cut:sendmessage(eh,WM_CUT,0,0);


     idm_copy:sendmessage(eh,WM_COPY,0,0);


     idm_paste:sendmessage(eh,WM_PASTE,0,0);


   idm_selectall:sendmessage(eh,EM_SETSEL,0,-1);


end;


    end;


else


   result:=DefWindowProc(wh,msg,wparam,lparam);


  end;


    end;


procedure defineMyWindow;


   var


   wh:HWND;


   wc: TWndClass;


begin


   with wc do


begin


   style:=0;


   lpfnWndProc := @windproc;


   cbClsExtra:=0;


   cbWndExtra:=0;


   hCursor:=LoadCursor(0, IDC_ARROW);


   hIcon:=LoadIcon(0, IDI_APPLICATION);


   lpszMenuName:=PChar(‘api’);


      hbrBackGround:=GetStockObject(LTGRAY_BRUSH);


lpszClassName:=PChar(‘MyEditor’);


   end;


    wc.hInstance:=sysinit.hInstance;


    Windows.RegisterClass(wc);


    wh:=CreateWindow(Pchar(‘MyEditor’),PChar(‘My First
     Editor’),WS_VISIBLE+WS_OVERLAPPEDWINDOW,



0,0,640,400,


0,0,hInstance,nil);


   end;


     begin


     definemywindow;


while true do


    begin


    if longint(getmessage(msg,0,0,0))<1 then exit;


    translatemessage(msg);


    dispatchmessage(msg);


       end;


          end.








































































Advertisment