| 1 | /* $Id: Win32kCC.c,v 1.3 2000-09-03 23:53:18 bird Exp $ | 
|---|
| 2 | * | 
|---|
| 3 | * Win32CC - Win32k Control Center. | 
|---|
| 4 | * | 
|---|
| 5 | * Copyright (c) 2000 knut st. osmundsen (knut.stange.osmundsen@mynd.no) | 
|---|
| 6 | * | 
|---|
| 7 | * Project Odin Software License can be found in LICENSE.TXT | 
|---|
| 8 | * | 
|---|
| 9 | */ | 
|---|
| 10 |  | 
|---|
| 11 |  | 
|---|
| 12 | /******************************************************************************* | 
|---|
| 13 | *   Defined Constants And Macros                                               * | 
|---|
| 14 | *******************************************************************************/ | 
|---|
| 15 |  | 
|---|
| 16 | /* | 
|---|
| 17 | * Private Window Messages | 
|---|
| 18 | */ | 
|---|
| 19 | #define  WM_SETCONTROLS         (WM_USER + 10) | 
|---|
| 20 | #define  WM_QUERYCONTROLS       (WM_USER + 11) | 
|---|
| 21 |  | 
|---|
| 22 |  | 
|---|
| 23 | /* | 
|---|
| 24 | * Include defines | 
|---|
| 25 | */ | 
|---|
| 26 | #define INCL_DOSERRORS | 
|---|
| 27 | #define INCL_DOSFILEMGR | 
|---|
| 28 | #define INCL_DOSRESOURCES | 
|---|
| 29 | #define INCL_WINERRORS | 
|---|
| 30 | #define INCL_WINDIALOGS | 
|---|
| 31 | #define INCL_WINMESSAGEMGR | 
|---|
| 32 | #define INCL_WINSTDSPIN | 
|---|
| 33 | #define INCL_WINBUTTONS | 
|---|
| 34 | #define INCL_WINWINDOWMGR | 
|---|
| 35 |  | 
|---|
| 36 | /******************************************************************************* | 
|---|
| 37 | *   Header Files                                                               * | 
|---|
| 38 | *******************************************************************************/ | 
|---|
| 39 | #include <os2.h> | 
|---|
| 40 |  | 
|---|
| 41 | #include <string.h> | 
|---|
| 42 | #include <stdio.h> | 
|---|
| 43 | #include <stdarg.h> | 
|---|
| 44 | #include <malloc.h> | 
|---|
| 45 |  | 
|---|
| 46 | #include <Win32k.h> | 
|---|
| 47 | #include <devSegDf.h>                   /* Win32k segment definitions. */ | 
|---|
| 48 | #include <Options.h> | 
|---|
| 49 |  | 
|---|
| 50 | #include "Win32kCC.h" | 
|---|
| 51 |  | 
|---|
| 52 |  | 
|---|
| 53 |  | 
|---|
| 54 | /******************************************************************************* | 
|---|
| 55 | *   Structures and Typedefs                                                    * | 
|---|
| 56 | *******************************************************************************/ | 
|---|
| 57 | typedef struct _WIN32KCC | 
|---|
| 58 | { | 
|---|
| 59 | HWND    hwnd; | 
|---|
| 60 | HAB     hab; | 
|---|
| 61 | BOOL    fDirty; | 
|---|
| 62 |  | 
|---|
| 63 | K32OPTIONS Options; | 
|---|
| 64 | K32OPTIONS NewOptions; | 
|---|
| 65 | K32STATUS  Status; | 
|---|
| 66 |  | 
|---|
| 67 | } WIN32KCC, *PWIN32KCC; | 
|---|
| 68 |  | 
|---|
| 69 |  | 
|---|
| 70 | /******************************************************************************* | 
|---|
| 71 | *   Global Variables                                                           * | 
|---|
| 72 | *******************************************************************************/ | 
|---|
| 73 | BOOL    fNotExit;                       /* Global variable used to stop WM_QUITS. | 
|---|
| 74 | * As long as this is true the message | 
|---|
| 75 | * loop will never exit, but ignore all | 
|---|
| 76 | * WM_QUITs. | 
|---|
| 77 | */ | 
|---|
| 78 |  | 
|---|
| 79 | /******************************************************************************* | 
|---|
| 80 | *   Internal Functions                                                         * | 
|---|
| 81 | *******************************************************************************/ | 
|---|
| 82 | MRESULT EXPENTRY    Win32kCCDlgProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2); | 
|---|
| 83 | BOOL                Complain(HWND hwndOwner, int id, ...); | 
|---|
| 84 | PCSZ                getLastErrorMsg(HAB hab); | 
|---|
| 85 | PSZ                 getMessage(ULONG id); | 
|---|
| 86 | int                 GetFixpackDesc(ULONG ulBuild, ULONG flKernel, PSZ pszBuffer); | 
|---|
| 87 |  | 
|---|
| 88 |  | 
|---|
| 89 |  | 
|---|
| 90 |  | 
|---|
| 91 | /** | 
|---|
| 92 | * Main function. | 
|---|
| 93 | * (No parameters) | 
|---|
| 94 | * @returns     -1  WinInitialize failed. | 
|---|
| 95 | *              -2  Failed to create message queue. | 
|---|
| 96 | *              -3  Failed to load dialog. | 
|---|
| 97 | *              0   Dialog was closed using cancel. | 
|---|
| 98 | *              1   Dialog was close using ok. | 
|---|
| 99 | */ | 
|---|
| 100 | int main(void) | 
|---|
| 101 | { | 
|---|
| 102 | HAB     hab; | 
|---|
| 103 | HMQ     hmq; | 
|---|
| 104 | ULONG   rc = 0; | 
|---|
| 105 | HWND    hwnd; | 
|---|
| 106 |  | 
|---|
| 107 | /* | 
|---|
| 108 | * Initialize PM. | 
|---|
| 109 | */ | 
|---|
| 110 | hab = WinInitialize(0); | 
|---|
| 111 | if (hab == NULLHANDLE) | 
|---|
| 112 | { | 
|---|
| 113 | return -1; | 
|---|
| 114 | } | 
|---|
| 115 |  | 
|---|
| 116 | /* | 
|---|
| 117 | * Create Message Queue. | 
|---|
| 118 | */ | 
|---|
| 119 | hmq = WinCreateMsgQueue(hab, 0); | 
|---|
| 120 | if (hmq == NULLHANDLE) | 
|---|
| 121 | { | 
|---|
| 122 | WinTerminate(hab); | 
|---|
| 123 | return -2; | 
|---|
| 124 | } | 
|---|
| 125 |  | 
|---|
| 126 | /* | 
|---|
| 127 | * Init Win32k library. | 
|---|
| 128 | */ | 
|---|
| 129 | rc = libWin32kInit(); | 
|---|
| 130 | if (rc != NO_ERROR) | 
|---|
| 131 | { | 
|---|
| 132 | switch (rc) | 
|---|
| 133 | { | 
|---|
| 134 | case ERROR_FILE_NOT_FOUND: | 
|---|
| 135 | Complain(HWND_DESKTOP, IDS_ERR_WIN32K_NOT_LOADED); | 
|---|
| 136 | break; | 
|---|
| 137 |  | 
|---|
| 138 | default: | 
|---|
| 139 | Complain(HWND_DESKTOP, IDS_ERR_WIN32K_OPEN_FAILED, rc); | 
|---|
| 140 | } | 
|---|
| 141 | } | 
|---|
| 142 |  | 
|---|
| 143 | /* | 
|---|
| 144 | * Load the dialog. | 
|---|
| 145 | */ | 
|---|
| 146 | hwnd = WinLoadDlg(HWND_DESKTOP, HWND_DESKTOP, | 
|---|
| 147 | Win32kCCDlgProc, | 
|---|
| 148 | NULLHANDLE, | 
|---|
| 149 | DL_WIN32KCC, | 
|---|
| 150 | NULL); | 
|---|
| 151 |  | 
|---|
| 152 | /* | 
|---|
| 153 | * Process the dialog. | 
|---|
| 154 | */ | 
|---|
| 155 | if (hwnd != NULLHANDLE) | 
|---|
| 156 | { | 
|---|
| 157 | QMSG qmsg; | 
|---|
| 158 | do | 
|---|
| 159 | { | 
|---|
| 160 | fNotExit = FALSE; | 
|---|
| 161 | while(WinGetMsg(hab, &qmsg, NULLHANDLE, NULLHANDLE, NULLHANDLE)) | 
|---|
| 162 | WinDispatchMsg(hab, &qmsg); | 
|---|
| 163 | } while (fNotExit); | 
|---|
| 164 |  | 
|---|
| 165 |  | 
|---|
| 166 | } | 
|---|
| 167 | else | 
|---|
| 168 | { | 
|---|
| 169 | Complain(HWND_DESKTOP, | 
|---|
| 170 | IDS_ERR_DIALOGLOAD, | 
|---|
| 171 | DL_WIN32KCC, | 
|---|
| 172 | WinGetLastError(hab), | 
|---|
| 173 | getLastErrorMsg(hab) | 
|---|
| 174 | ); | 
|---|
| 175 | rc = -3; | 
|---|
| 176 | } | 
|---|
| 177 |  | 
|---|
| 178 | /* | 
|---|
| 179 | * Cleanup. | 
|---|
| 180 | */ | 
|---|
| 181 | WinDestroyMsgQueue(hmq); | 
|---|
| 182 | WinTerminate(hab); | 
|---|
| 183 | libWin32kTerm(); | 
|---|
| 184 |  | 
|---|
| 185 | return rc; | 
|---|
| 186 | } | 
|---|
| 187 |  | 
|---|
| 188 | #pragma info(noord) /*remove annoying (and possible incorrect) messages on the MP* macros */ | 
|---|
| 189 |  | 
|---|
| 190 | /** | 
|---|
| 191 | * Dialog procedure for the DL_WIN32KCC dialog. | 
|---|
| 192 | * (See PMREF for the general specifications of this function.) | 
|---|
| 193 | */ | 
|---|
| 194 | MRESULT EXPENTRY Win32kCCDlgProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2) | 
|---|
| 195 | { | 
|---|
| 196 | PWIN32KCC   pThis; | 
|---|
| 197 |  | 
|---|
| 198 |  | 
|---|
| 199 | /* | 
|---|
| 200 | * Get instance data pointer (pThis). | 
|---|
| 201 | */ | 
|---|
| 202 | if (msg != WM_INITDLG) | 
|---|
| 203 | { | 
|---|
| 204 | pThis = (PWIN32KCC)WinQueryWindowPtr(hwnd, QWL_USER); | 
|---|
| 205 | if (pThis == NULL) | 
|---|
| 206 | return WinDefDlgProc(hwnd, msg, mp1, mp2); | 
|---|
| 207 | } | 
|---|
| 208 |  | 
|---|
| 209 |  | 
|---|
| 210 | /* | 
|---|
| 211 | * Message switch. | 
|---|
| 212 | */ | 
|---|
| 213 | switch (msg) | 
|---|
| 214 | { | 
|---|
| 215 | /* | 
|---|
| 216 | * Sets the controls according to the data from win32k. | 
|---|
| 217 | * | 
|---|
| 218 | * mr:  Focus changed or not. | 
|---|
| 219 | * mp1: hwnd of dialog | 
|---|
| 220 | * mp2: (user data) (NULL) | 
|---|
| 221 | */ | 
|---|
| 222 | case WM_INITDLG: | 
|---|
| 223 | { | 
|---|
| 224 |  | 
|---|
| 225 | /* | 
|---|
| 226 | * Initiate controls (ie. behaviour not data). | 
|---|
| 227 | *  - Ranges of the info level spinbuttons. | 
|---|
| 228 | *  - Max length of the max heap size entry fields. | 
|---|
| 229 | */ | 
|---|
| 230 | WinSendDlgItemMsg(hwnd, SB_LDR_PE_INFOLEVEL, SPBM_SETLIMITS, (MPARAM)4, (MPARAM)0); | 
|---|
| 231 | WinSendDlgItemMsg(hwnd, SB_LDR_ELF_INFOLEVEL, SPBM_SETLIMITS, (MPARAM)4, (MPARAM)0); | 
|---|
| 232 |  | 
|---|
| 233 | WinSendDlgItemMsg(hwnd, SB_HEAP_RES_MAX, SPBM_SETLIMITS, (MPARAM)32678, (MPARAM)128); | 
|---|
| 234 | WinSendDlgItemMsg(hwnd, SB_HEAP_SWP_MAX, SPBM_SETLIMITS, (MPARAM)32678, (MPARAM)128); | 
|---|
| 235 |  | 
|---|
| 236 |  | 
|---|
| 237 | /* | 
|---|
| 238 | * Init and set instance data. | 
|---|
| 239 | */ | 
|---|
| 240 | pThis = malloc(sizeof(*pThis)); | 
|---|
| 241 | if (pThis == NULL) | 
|---|
| 242 | { | 
|---|
| 243 | /* complain, dismiss and return. */ | 
|---|
| 244 | Complain(hwnd, IDS_ERR_MALLOC_FAILED, __FILE__, __LINE__, __FUNCTION__); | 
|---|
| 245 | WinPostMsg(hwnd, WM_QUIT, NULL, NULL); | 
|---|
| 246 | return FALSE; | 
|---|
| 247 | } | 
|---|
| 248 | pThis->hwnd = hwnd; | 
|---|
| 249 | pThis->hab = WinQueryAnchorBlock(hwnd); | 
|---|
| 250 | if (!WinSetWindowPtr(hwnd, QWL_USER, pThis)) | 
|---|
| 251 | { | 
|---|
| 252 | /* complain, dismiss and return. */ | 
|---|
| 253 | Complain(hwnd, IDS_ERR_SET_INSTACEDATA, | 
|---|
| 254 | WinGetLastError(pThis->hab), | 
|---|
| 255 | getLastErrorMsg(pThis->hab)); | 
|---|
| 256 | WinDismissDlg(hwnd, 0); | 
|---|
| 257 | WinPostMsg(hwnd, WM_QUIT, NULL, NULL); | 
|---|
| 258 | free(pThis); | 
|---|
| 259 | return FALSE; | 
|---|
| 260 | } | 
|---|
| 261 |  | 
|---|
| 262 | /* | 
|---|
| 263 | * Send a set controls message which gets data from | 
|---|
| 264 | * win32k and puts it into the controls. | 
|---|
| 265 | */ | 
|---|
| 266 | WinSendMsg(hwnd, WM_SETCONTROLS, NULL, NULL); | 
|---|
| 267 | break; | 
|---|
| 268 | } | 
|---|
| 269 |  | 
|---|
| 270 |  | 
|---|
| 271 | /* | 
|---|
| 272 | * The user wants me to do something... | 
|---|
| 273 | */ | 
|---|
| 274 | case WM_COMMAND: | 
|---|
| 275 | switch (SHORT1FROMMP(mp1)) | 
|---|
| 276 | { | 
|---|
| 277 | /* | 
|---|
| 278 | * The user pushed the "Apply" button. | 
|---|
| 279 | */ | 
|---|
| 280 | case PB_APPLY: | 
|---|
| 281 | { | 
|---|
| 282 | /* Check and get data from the dialog. */ | 
|---|
| 283 | if (WinSendMsg(hwnd, WM_QUERYCONTROLS, (MPARAM)TRUE, NULL) | 
|---|
| 284 | && pThis->fDirty | 
|---|
| 285 | ) | 
|---|
| 286 | { | 
|---|
| 287 | APIRET rc; | 
|---|
| 288 | rc = libWin32kSetOptions(&pThis->NewOptions); | 
|---|
| 289 | if (rc != NO_ERROR) | 
|---|
| 290 | Complain(hwnd, IDS_ERR_SETPOPTIONS, rc); | 
|---|
| 291 | WinSendMsg(hwnd, WM_SETCONTROLS, NULL, NULL); | 
|---|
| 292 | } | 
|---|
| 293 | } | 
|---|
| 294 | break; | 
|---|
| 295 |  | 
|---|
| 296 |  | 
|---|
| 297 | /* | 
|---|
| 298 | * User pushed the "Refresh" button. | 
|---|
| 299 | */ | 
|---|
| 300 | case PB_REFRESH: | 
|---|
| 301 | WinSendMsg(hwnd, WM_SETCONTROLS, NULL, NULL); | 
|---|
| 302 | break; | 
|---|
| 303 |  | 
|---|
| 304 |  | 
|---|
| 305 | /* | 
|---|
| 306 | * The user pushed the "Close" button. | 
|---|
| 307 | */ | 
|---|
| 308 | case DID_OK: | 
|---|
| 309 | /* Check if data is dirty */ | 
|---|
| 310 | if (!WinSendMsg(hwnd, WM_QUERYCONTROLS, (MPARAM)FALSE, NULL) || pThis->fDirty) | 
|---|
| 311 | { | 
|---|
| 312 | if (WinMessageBox(HWND_DESKTOP, hwnd, | 
|---|
| 313 | getMessage(IDM_INFO_DIRTY), | 
|---|
| 314 | "Win32k Control Center", 0, MB_YESNO | MB_WARNING | MB_MOVEABLE) | 
|---|
| 315 | != MBID_YES) | 
|---|
| 316 | { | 
|---|
| 317 | fNotExit = TRUE; | 
|---|
| 318 | return NULL; | 
|---|
| 319 | } | 
|---|
| 320 | } | 
|---|
| 321 | /* Close the dialog */ | 
|---|
| 322 | fNotExit = FALSE; | 
|---|
| 323 | WinDismissDlg(hwnd, 0); | 
|---|
| 324 | WinPostMsg(hwnd, WM_QUIT, NULL, NULL); | 
|---|
| 325 | break; | 
|---|
| 326 | } | 
|---|
| 327 | return NULL; | 
|---|
| 328 |  | 
|---|
| 329 |  | 
|---|
| 330 | /* | 
|---|
| 331 | * Close window. Typically sent when Alt-F4 pressed or system-menu-Close is selected. | 
|---|
| 332 | */ | 
|---|
| 333 | case WM_CLOSE: | 
|---|
| 334 | fNotExit = TRUE; | 
|---|
| 335 | WinSendMsg(hwnd, WM_COMMAND, | 
|---|
| 336 | MPFROMSHORT(DID_OK), MPFROM2SHORT(CMDSRC_MENU, FALSE)); | 
|---|
| 337 | break; | 
|---|
| 338 |  | 
|---|
| 339 |  | 
|---|
| 340 | /* | 
|---|
| 341 | * Window is destroyed (last message which ever should reach us!) | 
|---|
| 342 | *  -Free instance data | 
|---|
| 343 | *  -Set the instance data pointer to NULL (just in case). | 
|---|
| 344 | */ | 
|---|
| 345 | case WM_DESTROY: | 
|---|
| 346 | { | 
|---|
| 347 | free(pThis); | 
|---|
| 348 | WinSetWindowPtr(hwnd, QWL_USER, NULL); | 
|---|
| 349 | break; | 
|---|
| 350 | } | 
|---|
| 351 |  | 
|---|
| 352 |  | 
|---|
| 353 | /* | 
|---|
| 354 | * Gets data from win32k. | 
|---|
| 355 | * Sets the controls according to the data from win32k. | 
|---|
| 356 | * | 
|---|
| 357 | * mr:  reserved | 
|---|
| 358 | * mp1: reserved | 
|---|
| 359 | * mp2: reserved | 
|---|
| 360 | */ | 
|---|
| 361 | case WM_SETCONTROLS: | 
|---|
| 362 | { | 
|---|
| 363 | APIRET  rc; | 
|---|
| 364 | CHAR    szNumber[32]; | 
|---|
| 365 | CHAR    szBuffer[100]; | 
|---|
| 366 |  | 
|---|
| 367 |  | 
|---|
| 368 | /* | 
|---|
| 369 | * Call Win32k.sys to get options and statuses. | 
|---|
| 370 | */ | 
|---|
| 371 | memset(&pThis->Options, 0, sizeof(K32OPTIONS)); | 
|---|
| 372 | pThis->Options.cb = sizeof(K32OPTIONS); | 
|---|
| 373 | memset(&pThis->Status, 0, sizeof(K32STATUS)); | 
|---|
| 374 | pThis->Status.cb = sizeof(K32STATUS); | 
|---|
| 375 | rc = libWin32kQueryOptionsStatus(&pThis->Options, &pThis->Status); | 
|---|
| 376 | if (rc != NO_ERROR) | 
|---|
| 377 | { | 
|---|
| 378 | Complain(hwnd, IDS_ERR_QUERYOPTIONSTATUS, rc); | 
|---|
| 379 | fNotExit = FALSE; | 
|---|
| 380 | WinDismissDlg(hwnd, 0); | 
|---|
| 381 | WinPostMsg(hwnd, WM_QUIT, NULL, NULL); | 
|---|
| 382 | return NULL; | 
|---|
| 383 | } | 
|---|
| 384 |  | 
|---|
| 385 | /* | 
|---|
| 386 | * Set the controls. | 
|---|
| 387 | */ | 
|---|
| 388 | /* win32k */ | 
|---|
| 389 | sprintf(szBuffer, "%d.%d", 0, pThis->Status.ulVersion); | 
|---|
| 390 | WinSetDlgItemText(hwnd, TX_W32K_VERSION_VAL,        szBuffer); | 
|---|
| 391 | sprintf(szBuffer, "%s %s", pThis->Status.szBuildTime, pThis->Status.szBuildDate); | 
|---|
| 392 | WinSetDlgItemText(hwnd, TX_W32K_BUILD_DATETIME_VAL, szBuffer); | 
|---|
| 393 | WinSetDlgItemText(hwnd, TX_W32K_SYMBOLFILE_VAL,     pThis->Status.szSymFile); | 
|---|
| 394 | sprintf(szBuffer, "%d - ", pThis->Status.ulBuild); | 
|---|
| 395 | if (GetFixpackDesc(pThis->Status.ulBuild, pThis->Status.fKernel, szBuffer + strlen(szBuffer))) | 
|---|
| 396 | sprintf(szBuffer, "%d", pThis->Status.ulBuild); | 
|---|
| 397 | WinSetDlgItemText(hwnd, TX_W32K_KERNELBUILD_VAL,    szBuffer); | 
|---|
| 398 |  | 
|---|
| 399 | /* logging */ | 
|---|
| 400 | WinSendDlgItemMsg(hwnd, CB_LOGGING_ENABLED,     BM_SETCHECK,    (MPARAM)(pThis->Options.fLogging),                  NULL); | 
|---|
| 401 | WinSendDlgItemMsg(hwnd, RB_LOGGING_COM1,        BM_SETCHECK,    (MPARAM)(pThis->Options.usCom == 0x3f8),            NULL); | 
|---|
| 402 | WinSendDlgItemMsg(hwnd, RB_LOGGING_COM2,        BM_SETCHECK,    (MPARAM)(pThis->Options.usCom == 0x2f8),            NULL); | 
|---|
| 403 | WinSendDlgItemMsg(hwnd, RB_LOGGING_COM3,        BM_SETCHECK,    (MPARAM)(pThis->Options.usCom == 0x3e8),            NULL); | 
|---|
| 404 | WinSendDlgItemMsg(hwnd, RB_LOGGING_COM4,        BM_SETCHECK,    (MPARAM)(pThis->Options.usCom == 0x2e8),            NULL); | 
|---|
| 405 |  | 
|---|
| 406 | /* loaders */ | 
|---|
| 407 | WinSendDlgItemMsg(hwnd, CB_LDR_DISABLE_ALL,     BM_SETCHECK,    (MPARAM)(pThis->Options.fNoLoader),                  NULL); | 
|---|
| 408 | /* PE */ | 
|---|
| 409 | WinSendDlgItemMsg(hwnd, RB_LDR_PE_PURE,         BM_SETCHECK,    (MPARAM)(pThis->Options.fPE == FLAGS_PE_PE2LX),     NULL); | 
|---|
| 410 | WinSendDlgItemMsg(hwnd, RB_LDR_PE_MIXED,        BM_SETCHECK,    (MPARAM)(pThis->Options.fPE == FLAGS_PE_MIXED),     NULL); | 
|---|
| 411 | WinSendDlgItemMsg(hwnd, RB_LDR_PE_PE,           BM_SETCHECK,    (MPARAM)(pThis->Options.fPE == FLAGS_PE_PE),        NULL); | 
|---|
| 412 | WinSendDlgItemMsg(hwnd, RB_LDR_PE_NOT,          BM_SETCHECK,    (MPARAM)(pThis->Options.fPE == FLAGS_PE_NOT),       NULL); | 
|---|
| 413 | WinSendDlgItemMsg(hwnd, SB_LDR_PE_INFOLEVEL,    SPBM_SETCURRENTVALUE, (MPARAM)(pThis->Options.ulInfoLevel),         NULL); /* FIXME to be changed */ | 
|---|
| 414 | sprintf(szNumber, "%d", pThis->Status.cPe2LxModules); | 
|---|
| 415 | WinSetDlgItemText(hwnd, TX_LDR_PE_MODULES_VAL, szNumber); | 
|---|
| 416 | /* Elf */ | 
|---|
| 417 | WinSendDlgItemMsg(hwnd, CB_LDR_ELF_ENABLED,     BM_SETCHECK,    (MPARAM)(pThis->Options.fElf),                      NULL); | 
|---|
| 418 | WinSendDlgItemMsg(hwnd, SB_LDR_ELF_INFOLEVEL,   SPBM_SETCURRENTVALUE, (MPARAM)(pThis->Options.ulInfoLevel),         NULL); /* FIXME to be changed */ | 
|---|
| 419 | sprintf(szNumber, "%d", pThis->Status.cElf2LxModules); | 
|---|
| 420 | WinSetDlgItemText(hwnd, TX_LDR_ELF_MODULES_VAL, szNumber); | 
|---|
| 421 | /* UNIX Shell Scripts */ | 
|---|
| 422 | WinSendDlgItemMsg(hwnd, CB_LDR_SHELL_SCRIPTS,   BM_SETCHECK,    (MPARAM)(pThis->Options.fUNIXScript),               NULL); | 
|---|
| 423 | /* JAVA */ | 
|---|
| 424 | WinSendDlgItemMsg(hwnd, CB_LDR_JAVA,            BM_SETCHECK,    (MPARAM)(pThis->Options.fJava),                     NULL); | 
|---|
| 425 | /* REXX Scripts */ | 
|---|
| 426 | WinSendDlgItemMsg(hwnd, CB_LDR_REXX,            BM_SETCHECK,    (MPARAM)(pThis->Options.fREXXScript),               NULL); | 
|---|
| 427 |  | 
|---|
| 428 | /* heaps */ | 
|---|
| 429 | /* Resident */ | 
|---|
| 430 | WinSendDlgItemMsg(hwnd, SB_HEAP_RES_MAX,        SPBM_SETCURRENTVALUE, (MPARAM)(pThis->Options.cbResHeapMax / 1024), NULL); | 
|---|
| 431 | sprintf(szNumber, "%d", pThis->Status.cbResHeapInit / 1024); | 
|---|
| 432 | WinSetDlgItemText(hwnd, TX_HEAP_RES_INIT_VAL,   szNumber); | 
|---|
| 433 | sprintf(szNumber, "%d", pThis->Status.cbResHeapSize / 1024); | 
|---|
| 434 | WinSetDlgItemText(hwnd, TX_HEAP_RES_SIZE_VAL,   szNumber); | 
|---|
| 435 | sprintf(szNumber, "%d", pThis->Status.cbResHeapUsed / 1024); | 
|---|
| 436 | WinSetDlgItemText(hwnd, TX_HEAP_RES_USED_VAL,   szNumber); | 
|---|
| 437 | sprintf(szNumber, "%d", pThis->Status.cbResHeapFree / 1024); | 
|---|
| 438 | WinSetDlgItemText(hwnd, TX_HEAP_RES_FREE_VAL,   szNumber); | 
|---|
| 439 | sprintf(szNumber, "%d", pThis->Status.cResBlocksUsed); | 
|---|
| 440 | WinSetDlgItemText(hwnd, TX_HEAP_RES_USED_BLOCKS_VAL,   szNumber); | 
|---|
| 441 | sprintf(szNumber, "%d", pThis->Status.cResBlocksFree); | 
|---|
| 442 | WinSetDlgItemText(hwnd, TX_HEAP_RES_FREE_BLOCKS_VAL,   szNumber); | 
|---|
| 443 | /* Swappable */ | 
|---|
| 444 | WinSendDlgItemMsg(hwnd, SB_HEAP_SWP_MAX,        SPBM_SETCURRENTVALUE, (MPARAM)(pThis->Options.cbSwpHeapMax / 1024), NULL); | 
|---|
| 445 | sprintf(szNumber, "%d", pThis->Status.cbSwpHeapInit / 1024); | 
|---|
| 446 | WinSetDlgItemText(hwnd, TX_HEAP_SWP_INIT_VAL,   szNumber); | 
|---|
| 447 | sprintf(szNumber, "%d", pThis->Status.cbSwpHeapSize / 1024); | 
|---|
| 448 | WinSetDlgItemText(hwnd, TX_HEAP_SWP_SIZE_VAL,   szNumber); | 
|---|
| 449 | sprintf(szNumber, "%d", pThis->Status.cbSwpHeapUsed / 1024); | 
|---|
| 450 | WinSetDlgItemText(hwnd, TX_HEAP_SWP_USED_VAL,   szNumber); | 
|---|
| 451 | sprintf(szNumber, "%d", pThis->Status.cbSwpHeapFree / 1024); | 
|---|
| 452 | WinSetDlgItemText(hwnd, TX_HEAP_SWP_FREE_VAL,   szNumber); | 
|---|
| 453 | sprintf(szNumber, "%d", pThis->Status.cSwpBlocksUsed); | 
|---|
| 454 | WinSetDlgItemText(hwnd, TX_HEAP_SWP_USED_BLOCKS_VAL,   szNumber); | 
|---|
| 455 | sprintf(szNumber, "%d", pThis->Status.cSwpBlocksFree); | 
|---|
| 456 | WinSetDlgItemText(hwnd, TX_HEAP_SWP_FREE_BLOCKS_VAL,   szNumber); | 
|---|
| 457 |  | 
|---|
| 458 | pThis->fDirty = FALSE; | 
|---|
| 459 | return NULL; | 
|---|
| 460 | } | 
|---|
| 461 |  | 
|---|
| 462 |  | 
|---|
| 463 | /* | 
|---|
| 464 | * Validate data in the controls. Complains accoring to mp1. | 
|---|
| 465 | * Put the data into the win32k option struct. | 
|---|
| 466 | * | 
|---|
| 467 | * mr:  Valid indicator. | 
|---|
| 468 | *      TRUE:   Valid data. | 
|---|
| 469 | *      FALSE:  Not valid data. | 
|---|
| 470 | * mp1: BOOL fComplain. | 
|---|
| 471 | *      TRUE:   Do complain about errors. The pThis->Options struct | 
|---|
| 472 | *              is updated on successful return. | 
|---|
| 473 | *      FALSE:  Do not complain about errors, and don't update the | 
|---|
| 474 | *              pThis->Options struct. | 
|---|
| 475 | * mp2: reserved. | 
|---|
| 476 | */ | 
|---|
| 477 | case WM_QUERYCONTROLS: | 
|---|
| 478 | { | 
|---|
| 479 | BOOL        fComplain = (BOOL)mp1; | 
|---|
| 480 | ULONG       ul; | 
|---|
| 481 |  | 
|---|
| 482 | /* | 
|---|
| 483 | * Init temporary option struct. | 
|---|
| 484 | */ | 
|---|
| 485 | memset(&pThis->NewOptions, 0, sizeof(K32OPTIONS)); | 
|---|
| 486 | pThis->NewOptions.cb = sizeof(K32OPTIONS); | 
|---|
| 487 |  | 
|---|
| 488 | /* | 
|---|
| 489 | * Logging. | 
|---|
| 490 | */ | 
|---|
| 491 | pThis->NewOptions.fLogging = WinSendDlgItemMsg(hwnd, CB_LOGGING_ENABLED, BM_QUERYCHECK, NULL, NULL) != 0; | 
|---|
| 492 | if (WinSendDlgItemMsg(hwnd, RB_LOGGING_COM1, BM_QUERYCHECK, NULL, NULL)) | 
|---|
| 493 | pThis->NewOptions.usCom = 0x3f8; | 
|---|
| 494 | else if (WinSendDlgItemMsg(hwnd, RB_LOGGING_COM2, BM_QUERYCHECK, NULL, NULL)) | 
|---|
| 495 | pThis->NewOptions.usCom = 0x2f8; | 
|---|
| 496 | else if (WinSendDlgItemMsg(hwnd, RB_LOGGING_COM3, BM_QUERYCHECK, NULL, NULL)) | 
|---|
| 497 | pThis->NewOptions.usCom = 0x3e8; | 
|---|
| 498 | else if (WinSendDlgItemMsg(hwnd, RB_LOGGING_COM4, BM_QUERYCHECK, NULL, NULL)) | 
|---|
| 499 | pThis->NewOptions.usCom = 0x2e8; | 
|---|
| 500 | else | 
|---|
| 501 | { | 
|---|
| 502 | if (fComplain) | 
|---|
| 503 | Complain(hwnd, IDS_ERR_NO_COM_RADIOBUTTON); | 
|---|
| 504 | return (MPARAM)FALSE; | 
|---|
| 505 | } | 
|---|
| 506 |  | 
|---|
| 507 | /* | 
|---|
| 508 | * Loaders | 
|---|
| 509 | */ | 
|---|
| 510 | pThis->NewOptions.fNoLoader = WinSendDlgItemMsg(hwnd, CB_LDR_DISABLE_ALL, BM_QUERYCHECK, NULL, NULL) != 0; | 
|---|
| 511 | /* PE */ | 
|---|
| 512 | if (WinSendDlgItemMsg(hwnd, RB_LDR_PE_PURE, BM_QUERYCHECK, NULL, NULL)) | 
|---|
| 513 | pThis->NewOptions.fPE = FLAGS_PE_PE2LX; | 
|---|
| 514 | else if (WinSendDlgItemMsg(hwnd, RB_LDR_PE_MIXED, BM_QUERYCHECK, NULL, NULL)) | 
|---|
| 515 | pThis->NewOptions.fPE = FLAGS_PE_MIXED; | 
|---|
| 516 | else if (WinSendDlgItemMsg(hwnd, RB_LDR_PE_PE, BM_QUERYCHECK, NULL, NULL)) | 
|---|
| 517 | pThis->NewOptions.fPE = FLAGS_PE_PE; | 
|---|
| 518 | else if (WinSendDlgItemMsg(hwnd, RB_LDR_PE_NOT, BM_QUERYCHECK, NULL, NULL)) | 
|---|
| 519 | pThis->NewOptions.fPE = FLAGS_PE_NOT; | 
|---|
| 520 | else | 
|---|
| 521 | { | 
|---|
| 522 | if (fComplain) | 
|---|
| 523 | Complain(hwnd, IDS_ERR_NO_PE_RADIOBUTTON); | 
|---|
| 524 | return (MPARAM)FALSE; | 
|---|
| 525 | } | 
|---|
| 526 | if (!WinSendDlgItemMsg(hwnd, SB_LDR_PE_INFOLEVEL, SPBM_QUERYVALUE, (MPARAM)&ul, MPFROM2SHORT(0, SPBQ_UPDATEIFVALID))) | 
|---|
| 527 | { | 
|---|
| 528 | if (fComplain) | 
|---|
| 529 | { | 
|---|
| 530 | Complain(hwnd, IDS_ERR_INVALID_INFOLEVEL); | 
|---|
| 531 | WinSetFocus(HWND_DESKTOP, WinWindowFromID(hwnd, SB_LDR_PE_INFOLEVEL)); | 
|---|
| 532 | } | 
|---|
| 533 | return (MPARAM)FALSE; | 
|---|
| 534 | } | 
|---|
| 535 | pThis->NewOptions.ulInfoLevel = ul; /* FIXME to be changed */ | 
|---|
| 536 |  | 
|---|
| 537 | /* Elf */ | 
|---|
| 538 | pThis->NewOptions.fElf = WinSendDlgItemMsg(hwnd, CB_LDR_ELF_ENABLED, BM_QUERYCHECK, NULL, NULL) != 0; | 
|---|
| 539 | if (!WinSendDlgItemMsg(hwnd, SB_LDR_ELF_INFOLEVEL, SPBM_QUERYVALUE, (MPARAM)&ul, MPFROM2SHORT(0, SPBQ_UPDATEIFVALID))) | 
|---|
| 540 | { | 
|---|
| 541 | if (fComplain) | 
|---|
| 542 | { | 
|---|
| 543 | Complain(hwnd, IDS_ERR_INVALID_INFOLEVEL); | 
|---|
| 544 | WinSetFocus(HWND_DESKTOP, WinWindowFromID(hwnd, SB_LDR_ELF_INFOLEVEL)); | 
|---|
| 545 | } | 
|---|
| 546 | return (MPARAM)FALSE; | 
|---|
| 547 | } | 
|---|
| 548 | //pThis->NewOptions.ulInfoLevel = ul; /* FIXME to be changed */ | 
|---|
| 549 | /* UNIX Shell Scripts */ | 
|---|
| 550 | pThis->NewOptions.fUNIXScript = WinSendDlgItemMsg(hwnd, CB_LDR_SHELL_SCRIPTS, BM_QUERYCHECK, NULL, NULL) != 0; | 
|---|
| 551 | /* JAVA */ | 
|---|
| 552 | pThis->NewOptions.fJava = WinSendDlgItemMsg(hwnd, CB_LDR_JAVA, BM_QUERYCHECK, NULL, NULL) != 0; | 
|---|
| 553 | /* REXX Scripts */ | 
|---|
| 554 | pThis->NewOptions.fREXXScript = WinSendDlgItemMsg(hwnd, CB_LDR_REXX, BM_QUERYCHECK, NULL, NULL) != 0; | 
|---|
| 555 |  | 
|---|
| 556 | /* | 
|---|
| 557 | * Heaps | 
|---|
| 558 | */ | 
|---|
| 559 | /* Resident */ | 
|---|
| 560 | if (!WinSendDlgItemMsg(hwnd, SB_HEAP_RES_MAX, SPBM_QUERYVALUE, (MPARAM)&ul, MPFROM2SHORT(0, SPBQ_UPDATEIFVALID))) | 
|---|
| 561 | { | 
|---|
| 562 | if (fComplain) | 
|---|
| 563 | { | 
|---|
| 564 | Complain(hwnd, IDS_ERR_INVALID_MAXHEAPSIZE); | 
|---|
| 565 | WinSetFocus(HWND_DESKTOP, WinWindowFromID(hwnd, SB_HEAP_RES_MAX)); | 
|---|
| 566 | } | 
|---|
| 567 | return (MPARAM)FALSE; | 
|---|
| 568 | } | 
|---|
| 569 | pThis->NewOptions.cbResHeapMax = ul*1024; | 
|---|
| 570 | /* Swappable */ | 
|---|
| 571 | if (!WinSendDlgItemMsg(hwnd, SB_HEAP_SWP_MAX, SPBM_QUERYVALUE, (MPARAM)&ul, MPFROM2SHORT(0, SPBQ_UPDATEIFVALID))) | 
|---|
| 572 | { | 
|---|
| 573 | if (fComplain) | 
|---|
| 574 | { | 
|---|
| 575 | Complain(hwnd, IDS_ERR_INVALID_MAXHEAPSIZE); | 
|---|
| 576 | WinSetFocus(HWND_DESKTOP, WinWindowFromID(hwnd, SB_HEAP_SWP_MAX)); | 
|---|
| 577 | } | 
|---|
| 578 | return (MPARAM)FALSE; | 
|---|
| 579 | } | 
|---|
| 580 | pThis->NewOptions.cbSwpHeapMax = ul*1024; | 
|---|
| 581 |  | 
|---|
| 582 | /* | 
|---|
| 583 | * Check if there is any change and set the fDirty flag accordingly. | 
|---|
| 584 | */ | 
|---|
| 585 | pThis->fDirty = memcmp(&pThis->NewOptions, &pThis->Options, sizeof(K32OPTIONS)) != 0; | 
|---|
| 586 | return (MPARAM)TRUE; | 
|---|
| 587 | } | 
|---|
| 588 |  | 
|---|
| 589 |  | 
|---|
| 590 | } | 
|---|
| 591 |  | 
|---|
| 592 | /* | 
|---|
| 593 | * Return thru the default dialog procedure. | 
|---|
| 594 | */ | 
|---|
| 595 | return WinDefDlgProc(hwnd, msg, mp1, mp2); | 
|---|
| 596 | } | 
|---|
| 597 |  | 
|---|
| 598 |  | 
|---|
| 599 | /** | 
|---|
| 600 | * Pops up a message box displaying some complaint or error. | 
|---|
| 601 | * @returns     Success indicator. | 
|---|
| 602 | * @param       hwndOwner   Handle of owner window. | 
|---|
| 603 | * @param       id          String table id of the message. | 
|---|
| 604 | * @param       ...         Arguments passed on to vsprintf to format the message. | 
|---|
| 605 | */ | 
|---|
| 606 | BOOL Complain(HWND hwndOwner, int id, ...) | 
|---|
| 607 | { | 
|---|
| 608 | ULONG   rc; | 
|---|
| 609 | char    szMsg[1024]; | 
|---|
| 610 | char    szMsgOutput[4096]; | 
|---|
| 611 |  | 
|---|
| 612 |  | 
|---|
| 613 | /* | 
|---|
| 614 | * Load the string and format it. | 
|---|
| 615 | */ | 
|---|
| 616 | if (WinLoadString(WinQueryAnchorBlock(hwndOwner), 0, id, sizeof(szMsg), szMsg)) | 
|---|
| 617 | { | 
|---|
| 618 | va_list args; | 
|---|
| 619 | va_start(args, id); | 
|---|
| 620 | vsprintf(szMsgOutput, szMsg, args); | 
|---|
| 621 | va_end(args); | 
|---|
| 622 | } | 
|---|
| 623 | else | 
|---|
| 624 | sprintf(szMsgOutput, "Failed to load the message id %id.\n", id); | 
|---|
| 625 |  | 
|---|
| 626 |  | 
|---|
| 627 | /* | 
|---|
| 628 | * Show message. | 
|---|
| 629 | */ | 
|---|
| 630 | rc = WinMessageBox(HWND_DESKTOP, hwndOwner, | 
|---|
| 631 | szMsgOutput, | 
|---|
| 632 | "Win32k Control Center - error", | 
|---|
| 633 | 0, | 
|---|
| 634 | MB_APPLMODAL | MB_ICONHAND | MB_OK | MB_MOVEABLE); | 
|---|
| 635 | if (rc == (ULONG)MBID_ERROR) | 
|---|
| 636 | { | 
|---|
| 637 | rc = WinMessageBox(HWND_DESKTOP, HWND_DESKTOP, | 
|---|
| 638 | szMsgOutput, | 
|---|
| 639 | "Win32k Control Center - error", | 
|---|
| 640 | 0, | 
|---|
| 641 | MB_ICONHAND | MB_OK | MB_MOVEABLE); | 
|---|
| 642 | } | 
|---|
| 643 |  | 
|---|
| 644 |  | 
|---|
| 645 | /* | 
|---|
| 646 | * Return according to rc. | 
|---|
| 647 | */ | 
|---|
| 648 | return rc != MBID_ERROR; | 
|---|
| 649 | } | 
|---|
| 650 |  | 
|---|
| 651 |  | 
|---|
| 652 | /** | 
|---|
| 653 | * Gets the message string for the last error message. | 
|---|
| 654 | * @returns     Pointer to message string. | 
|---|
| 655 | * @param       hab     Handle of application anchor block. | 
|---|
| 656 | */ | 
|---|
| 657 | PCSZ getLastErrorMsg(HAB hab) | 
|---|
| 658 | { | 
|---|
| 659 | char     *pszErrInfo; | 
|---|
| 660 | PERRINFO pErrInfo = WinGetErrorInfo(hab); | 
|---|
| 661 |  | 
|---|
| 662 | if (pErrInfo != NULL && pErrInfo->cDetailLevel > 0) | 
|---|
| 663 | { | 
|---|
| 664 | pszErrInfo = (char*)(void*)pErrInfo; | 
|---|
| 665 | pszErrInfo += ((PUSHORT)(void*)(pszErrInfo + pErrInfo->offaoffszMsg))[pErrInfo->cDetailLevel-1]; | 
|---|
| 666 | } | 
|---|
| 667 | else | 
|---|
| 668 | pszErrInfo = "<none>"; | 
|---|
| 669 |  | 
|---|
| 670 | return pszErrInfo; | 
|---|
| 671 | } | 
|---|
| 672 |  | 
|---|
| 673 |  | 
|---|
| 674 | /** | 
|---|
| 675 | * Gets a message from the executable resources. | 
|---|
| 676 | * @returns     Pointer to read-only string. | 
|---|
| 677 | *              NULL if not found/error. | 
|---|
| 678 | * @param       id      String Id. | 
|---|
| 679 | */ | 
|---|
| 680 | PSZ getMessage(ULONG id) | 
|---|
| 681 | { | 
|---|
| 682 | PSZ psz; | 
|---|
| 683 |  | 
|---|
| 684 | if (DosGetResource(NULLHANDLE, RT_MESSAGE, id / 16 + 1, (PPVOID)(void*)&psz) == NO_ERROR) | 
|---|
| 685 | { | 
|---|
| 686 | psz +=2; | 
|---|
| 687 | id %= 16; | 
|---|
| 688 | while (id-- > 0) | 
|---|
| 689 | psz += 1 + *psz; | 
|---|
| 690 | return psz+1; | 
|---|
| 691 | } | 
|---|
| 692 | else | 
|---|
| 693 | psz = NULL; | 
|---|
| 694 |  | 
|---|
| 695 | return psz; | 
|---|
| 696 | } | 
|---|
| 697 |  | 
|---|
| 698 |  | 
|---|
| 699 | /** | 
|---|
| 700 | * Determin the fixpack+kernel description from build no. and kernel flags. | 
|---|
| 701 | * @returns     0 on success. Description i szBuffer. | 
|---|
| 702 | *              -1 on error. | 
|---|
| 703 | * @param       ulBuild     Kernel build no. | 
|---|
| 704 | * @param       flKernel    Win32k kernel flags. | 
|---|
| 705 | * @param       szBuffer    Pointer to buffer | 
|---|
| 706 | */ | 
|---|
| 707 | int GetFixpackDesc(ULONG ulBuild, ULONG flKernel, PSZ pszBuffer) | 
|---|
| 708 | { | 
|---|
| 709 |  | 
|---|
| 710 | pszBuffer[0] = '\0'; | 
|---|
| 711 | if (ulBuild == 9023) | 
|---|
| 712 | strcpy(pszBuffer, "Warp 4 GA"); | 
|---|
| 713 | else if (ulBuild > 9023 && ulBuild <= 9036) | 
|---|
| 714 | sprintf(pszBuffer, "Warp 4 FP %d", ulBuild - 9024); | 
|---|
| 715 | else if (ulBuild == 14039) | 
|---|
| 716 | strcpy(pszBuffer, "WS4eB GA"); | 
|---|
| 717 | else if (ulBuild == 14040) | 
|---|
| 718 | strcpy(pszBuffer, flKernel & KF_W4 ? "Warp 4 FP13" : "WS4eB FP1"); | 
|---|
| 719 | else if (ulBuild >= 14041 && ulBuild <= 14046) | 
|---|
| 720 | strcpy(pszBuffer, "Warp 4 FP14"); | 
|---|
| 721 | else if (ulBuild >= 14048) | 
|---|
| 722 | { | 
|---|
| 723 | if (flKernel & KF_W4) | 
|---|
| 724 | sprintf(pszBuffer, "Warp 4 FP%d", ulBuild - 14049 + 15); //??? | 
|---|
| 725 | else | 
|---|
| 726 | sprintf(pszBuffer, "WS4eB FP%d", ulBuild - 14048 + 2); //??? | 
|---|
| 727 | } | 
|---|
| 728 | else if (ulBuild >= 8255 && ulBuild <= 8270) | 
|---|
| 729 | sprintf(pszBuffer, "Warp 3 FP%d", ulBuild - 8255 + 32); | 
|---|
| 730 | else | 
|---|
| 731 | return -1; | 
|---|
| 732 |  | 
|---|
| 733 | /* | 
|---|
| 734 | * Check type. | 
|---|
| 735 | */ | 
|---|
| 736 | if (pszBuffer[0] != '\0') | 
|---|
| 737 | { | 
|---|
| 738 | char *pszAdd; | 
|---|
| 739 |  | 
|---|
| 740 | if (flKernel & KF_SMP) | 
|---|
| 741 | pszAdd = "SMP "; | 
|---|
| 742 | else | 
|---|
| 743 | pszAdd = " "; | 
|---|
| 744 | strcpy(pszBuffer + strlen(pszBuffer), pszAdd); | 
|---|
| 745 |  | 
|---|
| 746 | if (flKernel & KF_DEBUG) | 
|---|
| 747 | { | 
|---|
| 748 | if (flKernel & KF_HAS_DEBUGTYPE) | 
|---|
| 749 | pszAdd = (flKernel & KF_ALLSTRICT) ? "(Allstrict)" : "(Halfstrict)"; | 
|---|
| 750 | else | 
|---|
| 751 | pszAdd = "(Debug)"; | 
|---|
| 752 | } | 
|---|
| 753 | else | 
|---|
| 754 | pszAdd = "(Retail)"; | 
|---|
| 755 | strcpy(pszBuffer + strlen(pszBuffer), pszAdd); | 
|---|
| 756 | } | 
|---|
| 757 |  | 
|---|
| 758 | return 0; | 
|---|
| 759 | } | 
|---|