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:
- Use a #include line to include the declarations from
idl_export.hinto your source code. This include file is found in theexternal/includesubdirectory of the IDL distribution. - Compile your application.
- Link your application with
IDL.LIB. - Place
IDL.DLLin a directory with your application. See thereadme.txtfile located in the IDL_DIR/external/callablefor 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:
- 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.
- Registers a callback function to handle text messages sent by IDL to the application.
- Initializes Callable IDL.
- 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.