Issues and Examples: Microsoft Windows

Building an Application that Calls IDL

To build your Microsoft Windows application that calls IDL, you must take the following steps:

  1. Use a #include line to include the declarations from idl_export.h into your source code. This include file is found in the external/include subdirectory of the IDL distribution.
  2. Compile your application.
  3. Link your application with IDL.LIB.
  4. Place IDL.DLL in a directory with your application. See the readme.txt file located in the IDL_DIR/external/callable for more information.

Example: A Simple Application

The following program demonstrates how to display message text sent from IDL, execute IDL statements entered by a user, and how to obtain data from IDL variables. It performs the following actions:

  1. Creates a Main window with four client controls; a scrolling edit control to display text messages from IDL, a single line edit control to allow a user to enter an IDL command, a Send button to send the user command to IDL, and a Quit button to exit the application.
  2. Registers a callback function to handle text messages sent by IDL to the application.
  3. Initializes Callable IDL.
  4. Call IDL_Cleanup() when we receive the WM_CLOSE message.

Each line is numbered to make discussion easier. These numbers are not part of the actual program. The source code for this program can be found in the file simple.c, located in the callable subdirectory of the external subdirectory of the IDL distribution. See the source code for details of the program not printed here.

1  /*------------------------------------------------------------- 
2  * simple.c Source code for sample IDL callable application 
3  * 
4  * Copyright (c) 1992-1995, ITT Visual Information Solutions 
9  *--------------------------------------------------------------
*/ 
10 #include <windows.h> 
11 #include <windowsx.h> 
12 #include <ctl3d.h> 
13 #include <string.h> 
14 #include <stdio.h> 
15 #include "simple.h" 
16 #include "idl_export.h" 
17 
18 /*------------------------------------------------------------- 
19  * WinMain 
20  * 
21  * This is the required entry point for all windows 
applications. 
22  * 
23  * RETURNS:      TRUE if successful 
24  *-----------------------------------------------------------*/ 
25 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE 
hInstancePrev, 
26     LPSTR lpszCmndline, int nCmdShow) 
27 { 
28     IDL_INIT_DATA     init_data; 
29     HWND              hwnd; 
30     MSG               msg; 
31 
32     // Register the main window class. 
33     if (!RegisterWinClass(hInstance)) { 
34         return(0); 
35     } 
36 
37         ... 
38 
39     // Create and display the main window. 
40     if ((hwnd = InitMainWindow(hInstance)) == NULL) { 
41         return(0); 
42     } 
43     MainhWnd = hwnd; 
44 
45     // Register our output function with IDL. 
46     IDL_ToutPush(OutFunc); 
47 
48     // Initialize IDL 
49     init_data.options = IDL_INIT_BACKGROUND; 
50     init_data.options |= IDL_INIT_HWND; 
51     init_data.hwnd = hwnd; 
52     if (!IDL_Initialize(&init_data)) 
53         return(FALSE); 
54 
55     // Main message loop. 
56     while (GetMessage(&msg, NULL, 0, 0)) { 
57       TranslateMessage(&msg); 
58       DispatchMessage(&msg); 
59     } 
60 
61     return(msg.wParam); 
62 } 
63 
64 
65 /*------------------------------------------------------------- 
66  * RegisterWinClass 
67  * 
68  * To create a Main window (TLB in IDL speak). You must first 
69  * register the class for that window 
70  * 
71  * RETURNS:      TRUE if successful 
72  *-----------------------------------------------------------*/ 
73 BOOL RegisterWinClass(HINSTANCE hInst) 
74 { 
75     WNDCLASS            wc; 
76 
77     wc.style            = CS_HREDRAW | CS_VREDRAW; 
78     wc.lpfnWndProc      = MainWndProc; 
79     wc.cbClsExtra       = 0; 
80     wc.cbWndExtra       = 0; 
81     wc.hInstance        = hInst; 
82     wc.hIcon            = NULL; 
83     wc.hCursor          = LoadCursor(NULL, IDC_ARROW); 
84     wc.hbrBackground    = (HBRUSH)(COLOR_BTNFACE + 1); 
85     wc.lpszMenuName     = NULL; 
86     wc.lpszClassName    = "Simple"; 
87 
88     if (!RegisterClass(&wc)) { 
89         return(FALSE); 
90     } 
91 
92     return(TRUE); 
93} 
94 
95 /*------------------------------------------------------------- 
96  * InitMainWindow 
97  * 
98  * This is where our Main window is created and displayed 
99  * 
100 * RETURNS:      Handle to window 
101 *-----------------------------------------------------------*/ 
102 HWND InitMainWindow(HINSTANCE hInst) 
103 { 
104    HWND                hwnd; 
105    CREATESTRUCT        cs; 
106 
107 
108    hwnd = CreateWindow("Simple", 
109        "Callable IDL Sample Application", 
110        WS_DLGFRAME | WS_SYSMENU | WS_MINIMIZEBOX | WS_VISIBLE, 
111        CW_USEDEFAULT, 
112        0, 
113        600, 
114        480, 
115        NULL, 
116        NULL, 
117        hInst, 
118        &cs); 
119 
120    if (hwnd) { 
121       ShowWindow(hwnd, SW_SHOWNORMAL); 
122       UpdateWindow(hwnd); 
123    } 
124 
125    return(hwnd); 
126 } 
127 
128 /*------------------------------------------------------------ 
129  * MainWndProc 
130  * 
131  * The window procedure (event handler) for our main window. 
132  * All messages (events) sent to our app are routed through  
133  * here 
134  * RETURNS:          Depends of message. 
135  *----------------------------------------------------------*/ 
136 LRESULT WINAPI MainWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 
137 { 
138    static int               nDisplayable = 0; 
139 
140 
141    switch (uMsg) { 
142    //When our app is first created, we are sent this message. 
143    //We take this opportunity to create our child controls and 
144   //place them in their desired locations on the window. 
145       case WM_CREATE: 
146        if (!CreateControls(((LPCREATESTRUCT)lParam)->hInstance, hwnd)) { 
147            return(0); 
148        } 
149        if (!LayoutControls(hwnd)) { 
150            return(0); 
151        } 
152        nDisplayable = GetCharacterHeight(GetDlgItem(hwnd, IDE_COMMANDLOG)); 
153        break; 
154 
155        ... 
156 
157       case WM_DESTROY: 
158           PostQuitMessage(1); 
159           break; 
160 
161     //Each time a button or menu item is selected, we get this message 
162       case WM_COMMAND: 
163           OnCommand(hwnd, LOWORD(wParam), wParam, lParam); 
164           return(FALSE); 
165 
166   //This is a message we send ourselves to indicate the need to 
167  //display a text message in our log window. 
168       case IDL_OUTPUT: 
169           OutputMessage(wParam, lParam, nDisplayable); 
170           return(FALSE); 
171 
172       case WM_CLOSE: 
173           IDL_Cleanup(TRUE); 
174           return(FALSE); 
175 
176       default: 
177           break; 
178    } 
179 
180    return(DefWindowProc(hwnd, uMsg, wParam, lParam)); 
181 } 
182 
183 /*------------------------------------------------------------ 
184  * OnCommand 
185  * 
186  * This is the message handle for our WM_COMMAND messages 
187  * 
188  * RETURNS:          FALSE 
189  *----------------------------------------------------------*/ 
190 BOOL OnCommand(HWND hWnd, UINT uId, WPARAM wParam, LPARAM lParam) 
191 { 
192 
193    switch(uId){ 
194       case IDB_SENDCOMMAND:{ 
195           LPSTR     lpCommand; 
196           LPSTR     lpOut; 
197 
198           lpCommand = GlobalAllocPtr(GHND, 256); 
199           lpOut = GlobalAllocPtr(GHND, 256); 
200           if(!lpCommand) 
201              return(FALSE); 
202 
203       /* First we get the string that is in the input window */ 
204           GetDlgItemText(hWnd, IDE_COMMANDLINE, lpCommand, 
255); 
205 
206           /* and then clear the window */ 
207           SetDlgItemText(hWnd, IDE_COMMANDLINE, ""); 
208 
209           lstrcpy(lpOut, "\r\nSent to IDL: "); 
210           lstrcat(lpOut, lpCommand); 
211 
212           /* Send the string to our "log" window */ 
213           OutFunc(IDL_TOUT_F_NLPOST, lpOut, strlen(lpOut)); 
214 
215           /* then send the string to IDL */ 
216           IDL_ExecuteStr(lpCommand); 
217 
218           /* Now clean up */ 
219           GlobalFreePtr(lpCommand); 
220           GlobalFreePtr(lpOut); 
221     } 
222           break;     
223  } 
224  return(FALSE); 
225 } 
226 
227 /*------------------------------------------------------------ 
228  * OutFunc 
229  * 
230  * This is the output function that receives messages from IDL  
231  * and displays them for the user 
232  * 
233  * RETURNS:          NONE 
234  *----------------------------------------------------------*/ 
235 void OutFunc(long flags, char *buf, long n) 
236 { 
237    static    fShowMain = FALSE; 
238 
239    /* If there is a message, post it to our MAIN window */ 
240    if (n){ 
241        SendMessage (MainhWnd, IDL_OUTPUT, 0, (LPARAM)buf); 
242    } 
243 
244    /* If we need to post a new line message... */ 
245    if (flags & IDL_TOUT_F_NLPOST){ 
246        SendMessage (MainhWnd, IDL_OUTPUT, 0, (LPARAM)(LPSTR)"\r\n\0"); 
247    } 
248 
249  /* This message gets sent to the log window to have it scroll 
250     and display the last message at the bottom of the window. 
251     With this, the user will always see the last screen full of 
252    messages sent 
253    */ 
254    SendMessage (MainhWnd, IDL_OUTPUT, (WPARAM)TRUE,   
255                 (LPARAM)(LPSTR)"\0"); 
256 
257    return; 
258 } 
259 
260 /*------------------------------------------------------------ 
261  * OutputMessage 
262  * 
263  * Here we do the actual display of the text to our log window 
264  * 
265  * RETURNS:          nothing 
266  * 
267  *----------------------------------------------------------*/ 
268 void OutputMessage(WPARAM wParam, LPARAM lParam, int nDisplayable) 
269 { 
270    LRESULT   lRet; 
271    LONG      lBufflen, lNumLines, lFirstView; 
272 
273    /* Turn off the READONLY bit and postpone redraw */ 
274    lRet = SendMessage(hwndLog, EM_SETREADONLY, FALSE, 0L); 
275    lRet = SendMessage(hwndLog, WM_SETREDRAW, FALSE, 0L); 
276 
277   /* Get the length of the text in the log window*/ 
278   lBufflen = SendMessage (hwndLog, WM_GETTEXTLENGTH, 0, 0L); 
279   lNumLines = SendMessage (hwndLog, EM_GETLINECOUNT, 0, 0L); 
280   lFirstView = SendMessage (hwndLog, EM_GETFIRSTVISIBLELINE, 0, 0L); 
281   lRet = SendMessage (hwndLog, EM_SETSEL, lBufflen, lBufflen); 
282 
283    /* If we are adding text, wParam will be 0 */ 
284  if(!wParam) { 
285     lRet = SendMessage (hwndLog, EM_REPLACESEL, 0, lParam); 
286  } else { 
287     if (lNumLines > (lFirstView + nDisplayable)){ 
288          int        iLineLen = 0; 
289          int        iChar; 
290          int        iLines = 0; 
291          lNumLines--; 
292          while(!iLineLen){ 
293              iChar = SendMessage(hwndLog, EM_LINEINDEX,    
294                      (WPARAM)lNumLines, 0L); 
295              iLineLen = SendMessage(hwndLog, EM_LINELENGTH, 
296                      iChar, 0L); 
297              if(!iLineLen) 
298                  lNumLines--; 
299          } 
300          iLines = lNumLines-(lFirstView + (nDisplayable - 1)); 
301         iLines = iLines >= 0 ? iLines : 0; 
302         SendMessage (hwndLog, EM_LINESCROLL, 0, (LPARAM)iLines); 
303     } 
304  } 
305 
306    /* Set the window to redraw and reset the READONLY bit */ 
307    lRet = SendMessage(hwndLog, WM_SETREDRAW, TRUE, 0L); 
308    lRet = SendMessage(hwndLog, EM_SETREADONLY, TRUE, 0L); 
309 
310    return; 
311 } 

The following is a commentary on the program, by line number:

16

idl_export.h contains the IDL_ function prototypes, IDL specific structures, and IDL constants.

46

Call IDL_ToutPush() with the address of the output function (OutFunc) as it's only argument. This will register OutFunc as a callback for IDL. IDL will call OutFunc when it needs to display text.

49–53

Initialize IDL as a non-interactive session and supply it with the handle to the main window.

56

Start the windows message loop.

136-181

This is the Main window procedure. It will handle any messages that are sent to the main window. This includes WM_COMMAND messages that occur as a result of user interaction with the client controls. In addition, it handles a user defined message called IDL_OUTPUT (the name doesn't matter but this is a clue as to its purpose).

163

When the user presses either the "Send" or "Quit" buttons, route the message to the OnCommand function.

169

When we receive an IDL_OUTPUT message, call the function that displays text in the scrolling window (OutputMessage. See line 263).

173

When we receive the WM_CLOSE message, call IDL_Cleanup() to unlink IDL from our application.

190-225

OnCommand handles the WM_COMMAND messages generated when the user clicks on the application's buttons.

204

Get the IDL command that the user has entered in the single line edit control and store it in a buffer.

207

Clear the text in the edit control.

213

Display the command sent to IDL in the output window.

216

Call IDL_ExecuteStr() with the IDL command retrieved in line 204.

235-258

OutFunc is the callback registered with IDL to handle text messages IDL sends to our application. In addition it will handle text from IDL routines that display information, such as PRINT.

268-311

OutputMessage handles displaying the text to the output window. Since this window is a multi-line edit control, we have created it as a read-only window. See the source code for additional information on handling this situation.

285

OutputMessage appends new messages to the existing text in the control.

286-304

When the text has been displayed, OutputMessage scrolls the window to display the last line of text in the bottom of the window.