Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenwinhelp.c
Go to the documentation of this file.
00001 /* 00002 * Help Viewer 00003 * 00004 * Copyright 1996 Ulrich Schmid <uschmid@mail.hh.provi.de> 00005 * 2002 Sylvain Petreolle <spetreolle@yahoo.fr> 00006 * 2002, 2008 Eric Pouech <eric.pouech@wanadoo.fr> 00007 * 2004 Ken Belleau <jamez@ivic.qc.ca> 00008 * 2008 Kirill K. Smirnov <lich@math.spbu.ru> 00009 * 00010 * This library is free software; you can redistribute it and/or 00011 * modify it under the terms of the GNU Lesser General Public 00012 * License as published by the Free Software Foundation; either 00013 * version 2.1 of the License, or (at your option) any later version. 00014 * 00015 * This library is distributed in the hope that it will be useful, 00016 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00017 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00018 * Lesser General Public License for more details. 00019 * 00020 * You should have received a copy of the GNU Lesser General Public 00021 * License along with this library; if not, write to the Free Software 00022 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 00023 */ 00024 00025 #include <assert.h> 00026 #include <stdio.h> 00027 #include <string.h> 00028 #include <stdarg.h> 00029 #include <stdlib.h> 00030 00031 #define NONAMELESSUNION 00032 #define NONAMELESSSTRUCT 00033 00034 #include "windef.h" 00035 #include "winbase.h" 00036 #include "wingdi.h" 00037 #include "winuser.h" 00038 #include "commdlg.h" 00039 #include "winhelp.h" 00040 #include "winhelp_res.h" 00041 #include "shellapi.h" 00042 #include "richedit.h" 00043 #include "commctrl.h" 00044 00045 #include "wine/debug.h" 00046 00047 WINE_DEFAULT_DEBUG_CHANNEL(winhelp); 00048 00049 WINHELP_GLOBALS Globals = {3, NULL, TRUE, NULL, NULL, NULL, NULL, NULL, {{{NULL,NULL}},0}, NULL}; 00050 00051 #define CTL_ID_BUTTON 0x700 00052 #define CTL_ID_TEXT 0x701 00053 00054 00055 /*********************************************************************** 00056 * 00057 * WINHELP_InitFonts 00058 */ 00059 static void WINHELP_InitFonts(HWND hWnd) 00060 { 00061 WINHELP_WINDOW *win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0); 00062 LOGFONT logfontlist[] = { 00063 {-10, 0, 0, 0, 400, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 32, "Helv"}, 00064 {-12, 0, 0, 0, 700, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 32, "Helv"}, 00065 {-12, 0, 0, 0, 700, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 32, "Helv"}, 00066 {-12, 0, 0, 0, 400, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 32, "Helv"}, 00067 {-12, 0, 0, 0, 700, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 32, "Helv"}, 00068 {-10, 0, 0, 0, 700, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 32, "Helv"}, 00069 { -8, 0, 0, 0, 400, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 32, "Helv"}}; 00070 #define FONTS_LEN (sizeof(logfontlist)/sizeof(*logfontlist)) 00071 00072 static HFONT fonts[FONTS_LEN]; 00073 static BOOL init = 0; 00074 00075 win->fonts_len = FONTS_LEN; 00076 win->fonts = fonts; 00077 00078 if (!init) 00079 { 00080 UINT i; 00081 00082 for (i = 0; i < FONTS_LEN; i++) 00083 { 00084 fonts[i] = CreateFontIndirect(&logfontlist[i]); 00085 } 00086 00087 init = 1; 00088 } 00089 } 00090 00091 static DWORD CALLBACK WINHELP_RtfStreamIn(DWORD_PTR cookie, BYTE* buff, 00092 LONG cb, LONG* pcb) 00093 { 00094 struct RtfData* rd = (struct RtfData*)cookie; 00095 00096 if (rd->where >= rd->ptr) return 1; 00097 if (rd->where + cb > rd->ptr) 00098 cb = rd->ptr - rd->where; 00099 memcpy(buff, rd->where, cb); 00100 rd->where += cb; 00101 *pcb = cb; 00102 return 0; 00103 } 00104 00105 static void WINHELP_SetupText(HWND hTextWnd, WINHELP_WINDOW* win, ULONG relative) 00106 { 00107 /* At first clear area - needed by EM_POSFROMCHAR/EM_SETSCROLLPOS */ 00108 SendMessage(hTextWnd, WM_SETTEXT, 0, (LPARAM)""); 00109 SendMessage(hTextWnd, WM_SETREDRAW, FALSE, 0); 00110 SendMessage(hTextWnd, EM_SETBKGNDCOLOR, 0, (LPARAM)win->info->sr_color); 00111 /* set word-wrap to window size (undocumented) */ 00112 SendMessage(hTextWnd, EM_SETTARGETDEVICE, 0, 0); 00113 if (win->page) 00114 { 00115 struct RtfData rd; 00116 EDITSTREAM es; 00117 unsigned cp = 0; 00118 POINTL ptl; 00119 POINT pt; 00120 00121 00122 if (HLPFILE_BrowsePage(win->page, &rd, win->font_scale, relative)) 00123 { 00124 rd.where = rd.data; 00125 es.dwCookie = (DWORD_PTR)&rd; 00126 es.dwError = 0; 00127 es.pfnCallback = WINHELP_RtfStreamIn; 00128 00129 SendMessageW(hTextWnd, EM_STREAMIN, SF_RTF, (LPARAM)&es); 00130 cp = rd.char_pos_rel; 00131 } 00132 /* FIXME: else leaking potentially the rd.first_link chain */ 00133 HeapFree(GetProcessHeap(), 0, rd.data); 00134 SendMessage(hTextWnd, EM_POSFROMCHAR, (WPARAM)&ptl, cp ? cp - 1 : 0); 00135 pt.x = 0; pt.y = ptl.y; 00136 SendMessage(hTextWnd, EM_SETSCROLLPOS, 0, (LPARAM)&pt); 00137 } 00138 SendMessage(hTextWnd, WM_SETREDRAW, TRUE, 0); 00139 RedrawWindow(hTextWnd, NULL, NULL, RDW_FRAME|RDW_INVALIDATE); 00140 } 00141 00142 /*********************************************************************** 00143 * 00144 * WINHELP_GetOpenFileName 00145 */ 00146 BOOL WINHELP_GetOpenFileName(LPSTR lpszFile, int len) 00147 { 00148 OPENFILENAME openfilename; 00149 CHAR szDir[MAX_PATH]; 00150 CHAR szzFilter[2 * MAX_STRING_LEN + 100]; 00151 LPSTR p = szzFilter; 00152 00153 WINE_TRACE("()\n"); 00154 00155 LoadString(Globals.hInstance, STID_HELP_FILES_HLP, p, MAX_STRING_LEN); 00156 p += strlen(p) + 1; 00157 lstrcpy(p, "*.hlp"); 00158 p += strlen(p) + 1; 00159 LoadString(Globals.hInstance, STID_ALL_FILES, p, MAX_STRING_LEN); 00160 p += strlen(p) + 1; 00161 lstrcpy(p, "*.*"); 00162 p += strlen(p) + 1; 00163 *p = '\0'; 00164 00165 GetCurrentDirectory(sizeof(szDir), szDir); 00166 00167 lpszFile[0]='\0'; 00168 00169 openfilename.lStructSize = sizeof(OPENFILENAME); 00170 openfilename.hwndOwner = (Globals.active_win ? Globals.active_win->hMainWnd : 0); 00171 openfilename.hInstance = Globals.hInstance; 00172 openfilename.lpstrFilter = szzFilter; 00173 openfilename.lpstrCustomFilter = 0; 00174 openfilename.nMaxCustFilter = 0; 00175 openfilename.nFilterIndex = 1; 00176 openfilename.lpstrFile = lpszFile; 00177 openfilename.nMaxFile = len; 00178 openfilename.lpstrFileTitle = 0; 00179 openfilename.nMaxFileTitle = 0; 00180 openfilename.lpstrInitialDir = szDir; 00181 openfilename.lpstrTitle = 0; 00182 openfilename.Flags = OFN_ENABLESIZING; 00183 openfilename.nFileOffset = 0; 00184 openfilename.nFileExtension = 0; 00185 openfilename.lpstrDefExt = 0; 00186 openfilename.lCustData = 0; 00187 openfilename.lpfnHook = 0; 00188 openfilename.lpTemplateName = 0; 00189 00190 return GetOpenFileName(&openfilename); 00191 } 00192 00193 /*********************************************************************** 00194 * 00195 * WINHELP_MessageBoxIDS_s 00196 */ 00197 static INT WINHELP_MessageBoxIDS_s(UINT ids_text, LPCSTR str, UINT ids_title, WORD type) 00198 { 00199 CHAR text[MAX_STRING_LEN]; 00200 CHAR newtext[MAX_STRING_LEN + MAX_PATH]; 00201 00202 LoadString(Globals.hInstance, ids_text, text, sizeof(text)); 00203 wsprintf(newtext, text, str); 00204 00205 return MessageBox(0, newtext, MAKEINTRESOURCE(ids_title), type); 00206 } 00207 00208 /*********************************************************************** 00209 * 00210 * WINHELP_LookupHelpFile 00211 */ 00212 HLPFILE* WINHELP_LookupHelpFile(LPCSTR lpszFile) 00213 { 00214 HLPFILE* hlpfile; 00215 char szFullName[MAX_PATH]; 00216 char szAddPath[MAX_PATH]; 00217 char *p; 00218 00219 /* 00220 * NOTE: This is needed by popup windows only. 00221 * In other cases it's not needed but does not hurt though. 00222 */ 00223 if (Globals.active_win && Globals.active_win->page && Globals.active_win->page->file) 00224 { 00225 strcpy(szAddPath, Globals.active_win->page->file->lpszPath); 00226 p = strrchr(szAddPath, '\\'); 00227 if (p) *p = 0; 00228 } 00229 00230 /* 00231 * FIXME: Should we swap conditions? 00232 */ 00233 if (!SearchPath(NULL, lpszFile, ".hlp", MAX_PATH, szFullName, NULL) && 00234 !SearchPath(szAddPath, lpszFile, ".hlp", MAX_PATH, szFullName, NULL)) 00235 { 00236 if (WINHELP_MessageBoxIDS_s(STID_FILE_NOT_FOUND_s, lpszFile, STID_WHERROR, 00237 MB_YESNO|MB_ICONQUESTION) != IDYES) 00238 return NULL; 00239 if (!WINHELP_GetOpenFileName(szFullName, MAX_PATH)) 00240 return NULL; 00241 } 00242 hlpfile = HLPFILE_ReadHlpFile(szFullName); 00243 if (!hlpfile) 00244 WINHELP_MessageBoxIDS_s(STID_HLPFILE_ERROR_s, lpszFile, 00245 STID_WHERROR, MB_OK|MB_ICONSTOP); 00246 return hlpfile; 00247 } 00248 00249 /****************************************************************** 00250 * WINHELP_GetWindowInfo 00251 * 00252 * 00253 */ 00254 HLPFILE_WINDOWINFO* WINHELP_GetWindowInfo(HLPFILE* hlpfile, LPCSTR name) 00255 { 00256 static HLPFILE_WINDOWINFO mwi; 00257 unsigned int i; 00258 00259 if (!name || !name[0]) 00260 name = Globals.active_win->info->name; 00261 00262 if (hlpfile) 00263 for (i = 0; i < hlpfile->numWindows; i++) 00264 if (!lstrcmpi(hlpfile->windows[i].name, name)) 00265 return &hlpfile->windows[i]; 00266 00267 if (strcmp(name, "main") != 0) 00268 { 00269 WINE_FIXME("Couldn't find window info for %s\n", name); 00270 assert(0); 00271 return NULL; 00272 } 00273 if (!mwi.name[0]) 00274 { 00275 strcpy(mwi.type, "primary"); 00276 strcpy(mwi.name, "main"); 00277 if (hlpfile && hlpfile->lpszTitle[0]) 00278 { 00279 char tmp[128]; 00280 LoadString(Globals.hInstance, STID_WINE_HELP, tmp, sizeof(tmp)); 00281 snprintf(mwi.caption, sizeof(mwi.caption), "%s %s - %s", 00282 hlpfile->lpszTitle, tmp, hlpfile->lpszPath); 00283 } 00284 else 00285 LoadString(Globals.hInstance, STID_WINE_HELP, mwi.caption, sizeof(mwi.caption)); 00286 mwi.origin.x = mwi.origin.y = mwi.size.cx = mwi.size.cy = CW_USEDEFAULT; 00287 mwi.style = SW_SHOW; 00288 mwi.win_style = WS_OVERLAPPEDWINDOW; 00289 mwi.sr_color = mwi.nsr_color = 0xFFFFFF; 00290 } 00291 return &mwi; 00292 } 00293 00294 /****************************************************************** 00295 * HLPFILE_GetPopupWindowInfo 00296 * 00297 * 00298 */ 00299 static HLPFILE_WINDOWINFO* WINHELP_GetPopupWindowInfo(HLPFILE* hlpfile, 00300 WINHELP_WINDOW* parent, LPARAM mouse) 00301 { 00302 static HLPFILE_WINDOWINFO wi; 00303 00304 RECT parent_rect; 00305 00306 wi.type[0] = wi.name[0] = wi.caption[0] = '\0'; 00307 00308 /* Calculate horizontal size and position of a popup window */ 00309 GetWindowRect(parent->hMainWnd, &parent_rect); 00310 wi.size.cx = (parent_rect.right - parent_rect.left) / 2; 00311 wi.size.cy = 10; /* need a non null value, so that border are taken into account while computing */ 00312 00313 wi.origin.x = (short)LOWORD(mouse); 00314 wi.origin.y = (short)HIWORD(mouse); 00315 ClientToScreen(parent->hMainWnd, &wi.origin); 00316 wi.origin.x -= wi.size.cx / 2; 00317 wi.origin.x = min(wi.origin.x, GetSystemMetrics(SM_CXSCREEN) - wi.size.cx); 00318 wi.origin.x = max(wi.origin.x, 0); 00319 00320 wi.style = SW_SHOW; 00321 wi.win_style = WS_POPUP | WS_BORDER; 00322 if (parent->page->file->has_popup_color) 00323 wi.sr_color = parent->page->file->popup_color; 00324 else 00325 wi.sr_color = parent->info->sr_color; 00326 wi.nsr_color = 0xFFFFFF; 00327 00328 return &wi; 00329 } 00330 00331 typedef struct 00332 { 00333 WORD size; 00334 WORD command; 00335 LONG data; 00336 LONG reserved; 00337 WORD ofsFilename; 00338 WORD ofsData; 00339 } WINHELP,*LPWINHELP; 00340 00341 static BOOL WINHELP_HasWorkingWindow(void) 00342 { 00343 if (!Globals.active_win) return FALSE; 00344 if (Globals.active_win->next || Globals.win_list != Globals.active_win) return TRUE; 00345 return Globals.active_win->page != NULL && Globals.active_win->page->file != NULL; 00346 } 00347 00348 /****************************************************************** 00349 * WINHELP_HandleCommand 00350 * 00351 * 00352 */ 00353 static LRESULT WINHELP_HandleCommand(HWND hSrcWnd, LPARAM lParam) 00354 { 00355 COPYDATASTRUCT* cds = (COPYDATASTRUCT*)lParam; 00356 WINHELP* wh; 00357 00358 if (cds->dwData != 0xA1DE505) 00359 { 00360 WINE_FIXME("Wrong magic number (%08lx)\n", cds->dwData); 00361 return 0; 00362 } 00363 00364 wh = cds->lpData; 00365 00366 if (wh) 00367 { 00368 char* ptr = (wh->ofsFilename) ? (LPSTR)wh + wh->ofsFilename : NULL; 00369 00370 WINE_TRACE("Got[%u]: cmd=%u data=%08x fn=%s\n", 00371 wh->size, wh->command, wh->data, ptr); 00372 switch (wh->command) 00373 { 00374 case HELP_CONTEXT: 00375 if (ptr) 00376 { 00377 MACRO_JumpContext(ptr, "main", wh->data); 00378 } 00379 if (!WINHELP_HasWorkingWindow()) MACRO_Exit(); 00380 break; 00381 case HELP_QUIT: 00382 MACRO_Exit(); 00383 break; 00384 case HELP_CONTENTS: 00385 if (ptr) 00386 { 00387 MACRO_JumpContents(ptr, "main"); 00388 } 00389 if (!WINHELP_HasWorkingWindow()) MACRO_Exit(); 00390 break; 00391 case HELP_HELPONHELP: 00392 MACRO_HelpOn(); 00393 if (!WINHELP_HasWorkingWindow()) MACRO_Exit(); 00394 break; 00395 /* case HELP_SETINDEX: */ 00396 case HELP_SETCONTENTS: 00397 if (ptr) 00398 { 00399 MACRO_SetContents(ptr, wh->data); 00400 } 00401 break; 00402 case HELP_CONTEXTPOPUP: 00403 if (ptr) 00404 { 00405 MACRO_PopupContext(ptr, wh->data); 00406 } 00407 break; 00408 /* case HELP_FORCEFILE:*/ 00409 /* case HELP_CONTEXTMENU: */ 00410 case HELP_FINDER: 00411 /* in fact, should be the topic dialog box */ 00412 WINE_FIXME("HELP_FINDER: stub\n"); 00413 if (ptr) 00414 { 00415 MACRO_JumpHash(ptr, "main", 0); 00416 } 00417 break; 00418 /* case HELP_WM_HELP: */ 00419 /* case HELP_SETPOPUP_POS: */ 00420 /* case HELP_KEY: */ 00421 /* case HELP_COMMAND: */ 00422 /* case HELP_PARTIALKEY: */ 00423 /* case HELP_MULTIKEY: */ 00424 /* case HELP_SETWINPOS: */ 00425 default: 00426 WINE_FIXME("Unhandled command (%x) for remote winhelp control\n", wh->command); 00427 break; 00428 } 00429 } 00430 /* Always return success for now */ 00431 return 1; 00432 } 00433 00434 void WINHELP_LayoutMainWindow(WINHELP_WINDOW* win) 00435 { 00436 RECT rect, button_box_rect; 00437 INT text_top = 0; 00438 HWND hButtonBoxWnd = GetDlgItem(win->hMainWnd, CTL_ID_BUTTON); 00439 HWND hTextWnd = GetDlgItem(win->hMainWnd, CTL_ID_TEXT); 00440 00441 GetClientRect(win->hMainWnd, &rect); 00442 00443 /* Update button box and text Window */ 00444 SetWindowPos(hButtonBoxWnd, HWND_TOP, 00445 rect.left, rect.top, 00446 rect.right - rect.left, 00447 rect.bottom - rect.top, 0); 00448 00449 if (GetWindowRect(hButtonBoxWnd, &button_box_rect)) 00450 text_top = rect.top + button_box_rect.bottom - button_box_rect.top; 00451 00452 SetWindowPos(hTextWnd, HWND_TOP, 00453 rect.left, text_top, 00454 rect.right - rect.left, 00455 rect.bottom - text_top, 0); 00456 00457 } 00458 00459 /****************************************************************** 00460 * WINHELP_DeleteButtons 00461 * 00462 */ 00463 static void WINHELP_DeleteButtons(WINHELP_WINDOW* win) 00464 { 00465 WINHELP_BUTTON* b; 00466 WINHELP_BUTTON* bp; 00467 00468 for (b = win->first_button; b; b = bp) 00469 { 00470 DestroyWindow(b->hWnd); 00471 bp = b->next; 00472 HeapFree(GetProcessHeap(), 0, b); 00473 } 00474 win->first_button = NULL; 00475 } 00476 00477 /****************************************************************** 00478 * WINHELP_DeleteBackSet 00479 * 00480 */ 00481 void WINHELP_DeleteBackSet(WINHELP_WINDOW* win) 00482 { 00483 unsigned int i; 00484 00485 for (i = 0; i < win->back.index; i++) 00486 { 00487 HLPFILE_FreeHlpFile(win->back.set[i].page->file); 00488 win->back.set[i].page = NULL; 00489 } 00490 win->back.index = 0; 00491 } 00492 00493 /****************************************************************** 00494 * WINHELP_DeletePageLinks 00495 * 00496 */ 00497 static void WINHELP_DeletePageLinks(HLPFILE_PAGE* page) 00498 { 00499 HLPFILE_LINK* curr; 00500 HLPFILE_LINK* next; 00501 00502 for (curr = page->first_link; curr; curr = next) 00503 { 00504 next = curr->next; 00505 HeapFree(GetProcessHeap(), 0, curr); 00506 } 00507 } 00508 00509 /*********************************************************************** 00510 * 00511 * WINHELP_GrabWindow 00512 */ 00513 WINHELP_WINDOW* WINHELP_GrabWindow(WINHELP_WINDOW* win) 00514 { 00515 WINE_TRACE("Grab %p#%d++\n", win, win->ref_count); 00516 win->ref_count++; 00517 return win; 00518 } 00519 00520 /*********************************************************************** 00521 * 00522 * WINHELP_RelaseWindow 00523 */ 00524 BOOL WINHELP_ReleaseWindow(WINHELP_WINDOW* win) 00525 { 00526 WINE_TRACE("Release %p#%d--\n", win, win->ref_count); 00527 00528 if (!--win->ref_count) 00529 { 00530 DestroyWindow(win->hMainWnd); 00531 return FALSE; 00532 } 00533 return TRUE; 00534 } 00535 00536 /*********************************************************************** 00537 * 00538 * WINHELP_DeleteWindow 00539 */ 00540 static void WINHELP_DeleteWindow(WINHELP_WINDOW* win) 00541 { 00542 WINHELP_WINDOW** w; 00543 BOOL bExit; 00544 HWND hTextWnd; 00545 00546 for (w = &Globals.win_list; *w; w = &(*w)->next) 00547 { 00548 if (*w == win) 00549 { 00550 *w = win->next; 00551 break; 00552 } 00553 } 00554 bExit = (Globals.wVersion >= 4 && !lstrcmpi(win->info->name, "main")); 00555 00556 if (Globals.active_win == win) 00557 { 00558 Globals.active_win = Globals.win_list; 00559 if (Globals.win_list) 00560 SetActiveWindow(Globals.win_list->hMainWnd); 00561 } 00562 00563 if (win == Globals.active_popup) 00564 Globals.active_popup = NULL; 00565 00566 hTextWnd = GetDlgItem(win->hMainWnd, CTL_ID_TEXT); 00567 SetWindowLongPtr(hTextWnd, GWLP_WNDPROC, 00568 (LONG_PTR)win->origRicheditWndProc); 00569 00570 WINHELP_DeleteButtons(win); 00571 00572 if (win->page) WINHELP_DeletePageLinks(win->page); 00573 if (win->hHistoryWnd) DestroyWindow(win->hHistoryWnd); 00574 00575 DeleteObject(win->hBrush); 00576 00577 WINHELP_DeleteBackSet(win); 00578 00579 if (win->page) HLPFILE_FreeHlpFile(win->page->file); 00580 HeapFree(GetProcessHeap(), 0, win); 00581 00582 if (bExit) MACRO_Exit(); 00583 if (!Globals.win_list) 00584 PostQuitMessage(0); 00585 } 00586 00587 static char* WINHELP_GetCaption(WINHELP_WNDPAGE* wpage) 00588 { 00589 if (wpage->wininfo->caption[0]) return wpage->wininfo->caption; 00590 return wpage->page->file->lpszTitle; 00591 } 00592 00593 static void WINHELP_RememberPage(WINHELP_WINDOW* win, WINHELP_WNDPAGE* wpage) 00594 { 00595 unsigned num; 00596 00597 if (!Globals.history.index || Globals.history.set[0].page != wpage->page) 00598 { 00599 num = sizeof(Globals.history.set) / sizeof(Globals.history.set[0]); 00600 /* we're full, remove latest entry */ 00601 if (Globals.history.index == num) 00602 { 00603 HLPFILE_FreeHlpFile(Globals.history.set[num - 1].page->file); 00604 Globals.history.index--; 00605 } 00606 memmove(&Globals.history.set[1], &Globals.history.set[0], 00607 Globals.history.index * sizeof(Globals.history.set[0])); 00608 Globals.history.set[0] = *wpage; 00609 Globals.history.index++; 00610 wpage->page->file->wRefCount++; 00611 } 00612 if (win->hHistoryWnd) InvalidateRect(win->hHistoryWnd, NULL, TRUE); 00613 00614 num = sizeof(win->back.set) / sizeof(win->back.set[0]); 00615 if (win->back.index == num) 00616 { 00617 /* we're full, remove latest entry */ 00618 HLPFILE_FreeHlpFile(win->back.set[0].page->file); 00619 memmove(&win->back.set[0], &win->back.set[1], 00620 (num - 1) * sizeof(win->back.set[0])); 00621 win->back.index--; 00622 } 00623 win->back.set[win->back.index++] = *wpage; 00624 wpage->page->file->wRefCount++; 00625 } 00626 00627 /*********************************************************************** 00628 * 00629 * WINHELP_FindLink 00630 */ 00631 static HLPFILE_LINK* WINHELP_FindLink(WINHELP_WINDOW* win, LPARAM pos) 00632 { 00633 HLPFILE_LINK* link; 00634 POINTL mouse_ptl, char_ptl, char_next_ptl; 00635 DWORD cp; 00636 00637 if (!win->page) return NULL; 00638 00639 mouse_ptl.x = (short)LOWORD(pos); 00640 mouse_ptl.y = (short)HIWORD(pos); 00641 cp = SendMessageW(GetDlgItem(win->hMainWnd, CTL_ID_TEXT), EM_CHARFROMPOS, 00642 0, (LPARAM)&mouse_ptl); 00643 00644 for (link = win->page->first_link; link; link = link->next) 00645 { 00646 if (link->cpMin <= cp && cp <= link->cpMax) 00647 { 00648 /* check whether we're at end of line */ 00649 SendMessageW(GetDlgItem(win->hMainWnd, CTL_ID_TEXT), EM_POSFROMCHAR, 00650 (LPARAM)&char_ptl, cp); 00651 SendMessageW(GetDlgItem(win->hMainWnd, CTL_ID_TEXT), EM_POSFROMCHAR, 00652 (LPARAM)&char_next_ptl, cp + 1); 00653 if (link->bHotSpot) 00654 { 00655 HLPFILE_HOTSPOTLINK* hslink = (HLPFILE_HOTSPOTLINK*)link; 00656 if ((mouse_ptl.x < char_ptl.x + hslink->x) || 00657 (mouse_ptl.x >= char_ptl.x + hslink->x + hslink->width) || 00658 (mouse_ptl.y < char_ptl.y + hslink->y) || 00659 (mouse_ptl.y >= char_ptl.y + hslink->y + hslink->height)) 00660 continue; 00661 break; 00662 } 00663 if (char_next_ptl.y != char_ptl.y || mouse_ptl.x >= char_next_ptl.x) 00664 link = NULL; 00665 break; 00666 } 00667 } 00668 return link; 00669 } 00670 00671 static LRESULT CALLBACK WINHELP_RicheditWndProc(HWND hWnd, UINT msg, 00672 WPARAM wParam, LPARAM lParam) 00673 { 00674 WINHELP_WINDOW *win = (WINHELP_WINDOW*) GetWindowLongPtr(GetParent(hWnd), 0); 00675 DWORD messagePos; 00676 POINT pt; 00677 switch(msg) 00678 { 00679 case WM_SETCURSOR: 00680 messagePos = GetMessagePos(); 00681 pt.x = (short)LOWORD(messagePos); 00682 pt.y = (short)HIWORD(messagePos); 00683 ScreenToClient(hWnd, &pt); 00684 if (win->page && WINHELP_FindLink(win, MAKELPARAM(pt.x, pt.y))) 00685 { 00686 SetCursor(win->hHandCur); 00687 return 0; 00688 } 00689 /* fall through */ 00690 default: 00691 return CallWindowProcA(win->origRicheditWndProc, hWnd, msg, wParam, lParam); 00692 } 00693 } 00694 00695 /*********************************************************************** 00696 * 00697 * WINHELP_CreateHelpWindow 00698 */ 00699 BOOL WINHELP_CreateHelpWindow(WINHELP_WNDPAGE* wpage, int nCmdShow, BOOL remember) 00700 { 00701 WINHELP_WINDOW* win = NULL; 00702 BOOL bPrimary, bPopup, bReUsed = FALSE; 00703 HICON hIcon; 00704 HWND hTextWnd = NULL; 00705 00706 bPrimary = !lstrcmpi(wpage->wininfo->name, "main"); 00707 bPopup = !bPrimary && (wpage->wininfo->win_style & WS_POPUP); 00708 00709 if (!bPopup) 00710 { 00711 for (win = Globals.win_list; win; win = win->next) 00712 { 00713 if (!lstrcmpi(win->info->name, wpage->wininfo->name)) 00714 { 00715 if (win->page == wpage->page && win->info == wpage->wininfo) 00716 { 00717 /* see #22979, some hlp files have a macro (run at page opening), which 00718 * jumps to the very same page 00719 * Exit gracefully in that case 00720 */ 00721 return TRUE; 00722 } 00723 WINHELP_DeleteButtons(win); 00724 bReUsed = TRUE; 00725 SetWindowText(win->hMainWnd, WINHELP_GetCaption(wpage)); 00726 if (win->info != wpage->wininfo) 00727 { 00728 POINT pt = {0, 0}; 00729 SIZE sz = {0, 0}; 00730 DWORD flags = SWP_NOSIZE | SWP_NOMOVE; 00731 00732 if (wpage->wininfo->origin.x != CW_USEDEFAULT && 00733 wpage->wininfo->origin.y != CW_USEDEFAULT) 00734 { 00735 pt = wpage->wininfo->origin; 00736 flags &= ~SWP_NOSIZE; 00737 } 00738 if (wpage->wininfo->size.cx != CW_USEDEFAULT && 00739 wpage->wininfo->size.cy != CW_USEDEFAULT) 00740 { 00741 sz = wpage->wininfo->size; 00742 flags &= ~SWP_NOMOVE; 00743 } 00744 SetWindowPos(win->hMainWnd, HWND_TOP, pt.x, pt.y, sz.cx, sz.cy, flags); 00745 } 00746 00747 if (wpage->page && win->page && wpage->page->file != win->page->file) 00748 WINHELP_DeleteBackSet(win); 00749 WINHELP_InitFonts(win->hMainWnd); 00750 00751 win->page = wpage->page; 00752 win->info = wpage->wininfo; 00753 hTextWnd = GetDlgItem(win->hMainWnd, CTL_ID_TEXT); 00754 WINHELP_SetupText(hTextWnd, win, wpage->relative); 00755 00756 InvalidateRect(win->hMainWnd, NULL, TRUE); 00757 if (win->hHistoryWnd) InvalidateRect(win->hHistoryWnd, NULL, TRUE); 00758 00759 break; 00760 } 00761 } 00762 } 00763 00764 if (!win) 00765 { 00766 /* Initialize WINHELP_WINDOW struct */ 00767 win = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WINHELP_WINDOW)); 00768 if (!win) return FALSE; 00769 win->next = Globals.win_list; 00770 Globals.win_list = win; 00771 00772 win->hHandCur = LoadCursorW(0, (LPWSTR)IDC_HAND); 00773 win->back.index = 0; 00774 win->font_scale = 1; 00775 WINHELP_GrabWindow(win); 00776 } 00777 win->page = wpage->page; 00778 win->info = wpage->wininfo; 00779 WINHELP_GrabWindow(win); 00780 00781 if (!bPopup && wpage->page && remember) 00782 { 00783 WINHELP_RememberPage(win, wpage); 00784 } 00785 00786 if (bPopup) 00787 Globals.active_popup = win; 00788 else 00789 Globals.active_win = win; 00790 00791 /* Initialize default pushbuttons */ 00792 if (bPrimary && wpage->page) 00793 { 00794 CHAR buffer[MAX_STRING_LEN]; 00795 00796 LoadString(Globals.hInstance, STID_CONTENTS, buffer, sizeof(buffer)); 00797 MACRO_CreateButton("BTN_CONTENTS", buffer, "Contents()"); 00798 LoadString(Globals.hInstance, STID_INDEX, buffer, sizeof(buffer)); 00799 MACRO_CreateButton("BTN_INDEX", buffer, "Finder()"); 00800 LoadString(Globals.hInstance, STID_BACK, buffer, sizeof(buffer)); 00801 MACRO_CreateButton("BTN_BACK", buffer, "Back()"); 00802 if (win->back.index <= 1) MACRO_DisableButton("BTN_BACK"); 00803 } 00804 00805 if (!bReUsed) 00806 { 00807 win->hMainWnd = CreateWindowEx((bPopup) ? WS_EX_TOOLWINDOW : 0, MAIN_WIN_CLASS_NAME, 00808 WINHELP_GetCaption(wpage), 00809 bPrimary ? WS_OVERLAPPEDWINDOW : wpage->wininfo->win_style, 00810 wpage->wininfo->origin.x, wpage->wininfo->origin.y, 00811 wpage->wininfo->size.cx, wpage->wininfo->size.cy, 00812 bPopup ? Globals.active_win->hMainWnd : NULL, 00813 bPrimary ? LoadMenu(Globals.hInstance, MAKEINTRESOURCE(MAIN_MENU)) : 0, 00814 Globals.hInstance, win); 00815 if (!bPopup) 00816 /* Create button box and text Window */ 00817 CreateWindow(BUTTON_BOX_WIN_CLASS_NAME, "", WS_CHILD | WS_VISIBLE, 00818 0, 0, 0, 0, win->hMainWnd, (HMENU)CTL_ID_BUTTON, Globals.hInstance, NULL); 00819 00820 hTextWnd = CreateWindow(RICHEDIT_CLASS, NULL, 00821 ES_MULTILINE | ES_READONLY | WS_CHILD | WS_HSCROLL | WS_VSCROLL | WS_VISIBLE, 00822 0, 0, 0, 0, win->hMainWnd, (HMENU)CTL_ID_TEXT, Globals.hInstance, NULL); 00823 SendMessage(hTextWnd, EM_SETEVENTMASK, 0, 00824 SendMessage(hTextWnd, EM_GETEVENTMASK, 0, 0) | ENM_MOUSEEVENTS); 00825 win->origRicheditWndProc = (WNDPROC)SetWindowLongPtr(hTextWnd, GWLP_WNDPROC, 00826 (LONG_PTR)WINHELP_RicheditWndProc); 00827 } 00828 00829 hIcon = (wpage->page) ? wpage->page->file->hIcon : NULL; 00830 if (!hIcon) hIcon = LoadImage(Globals.hInstance, MAKEINTRESOURCE(IDI_WINHELP), IMAGE_ICON, 00831 GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_SHARED); 00832 SendMessage(win->hMainWnd, WM_SETICON, ICON_SMALL, (DWORD_PTR)hIcon); 00833 00834 /* Initialize file specific pushbuttons */ 00835 if (!(wpage->wininfo->win_style & WS_POPUP) && wpage->page) 00836 { 00837 HLPFILE_MACRO *macro; 00838 for (macro = wpage->page->file->first_macro; macro; macro = macro->next) 00839 MACRO_ExecuteMacro(win, macro->lpszMacro); 00840 00841 for (macro = wpage->page->first_macro; macro; macro = macro->next) 00842 MACRO_ExecuteMacro(win, macro->lpszMacro); 00843 } 00844 /* See #17681, in some cases, the newly created window is closed by the macros it contains 00845 * (braindead), so deal with this case 00846 */ 00847 for (win = Globals.win_list; win; win = win->next) 00848 { 00849 if (!lstrcmpi(win->info->name, wpage->wininfo->name)) break; 00850 } 00851 if (!win || !WINHELP_ReleaseWindow(win)) return TRUE; 00852 00853 if (bPopup) 00854 { 00855 DWORD mask = SendMessage(hTextWnd, EM_GETEVENTMASK, 0, 0); 00856 00857 win->font_scale = Globals.active_win->font_scale; 00858 WINHELP_SetupText(hTextWnd, win, wpage->relative); 00859 00860 /* we need the window to be shown for richedit to compute the size */ 00861 ShowWindow(win->hMainWnd, nCmdShow); 00862 SendMessage(hTextWnd, EM_SETEVENTMASK, 0, mask | ENM_REQUESTRESIZE); 00863 SendMessage(hTextWnd, EM_REQUESTRESIZE, 0, 0); 00864 SendMessage(hTextWnd, EM_SETEVENTMASK, 0, mask); 00865 } 00866 else 00867 { 00868 WINHELP_SetupText(hTextWnd, win, wpage->relative); 00869 WINHELP_LayoutMainWindow(win); 00870 ShowWindow(win->hMainWnd, nCmdShow); 00871 } 00872 00873 return TRUE; 00874 } 00875 00876 /****************************************************************** 00877 * WINHELP_OpenHelpWindow 00878 * Main function to search for a page and display it in a window 00879 */ 00880 BOOL WINHELP_OpenHelpWindow(HLPFILE_PAGE* (*lookup)(HLPFILE*, LONG, ULONG*), 00881 HLPFILE* hlpfile, LONG val, HLPFILE_WINDOWINFO* wi, 00882 int nCmdShow) 00883 { 00884 WINHELP_WNDPAGE wpage; 00885 00886 wpage.page = lookup(hlpfile, val, &wpage.relative); 00887 if (wpage.page) wpage.page->file->wRefCount++; 00888 wpage.wininfo = wi; 00889 return WINHELP_CreateHelpWindow(&wpage, nCmdShow, TRUE); 00890 } 00891 00892 /****************************************************************** 00893 * WINHELP_HandleTextMouse 00894 * 00895 */ 00896 static BOOL WINHELP_HandleTextMouse(WINHELP_WINDOW* win, UINT msg, LPARAM lParam) 00897 { 00898 HLPFILE* hlpfile; 00899 HLPFILE_LINK* link; 00900 BOOL ret = FALSE; 00901 00902 switch (msg) 00903 { 00904 case WM_LBUTTONDOWN: 00905 if ((link = WINHELP_FindLink(win, lParam))) 00906 { 00907 HLPFILE_WINDOWINFO* wi; 00908 00909 switch (link->cookie) 00910 { 00911 case hlp_link_link: 00912 if ((hlpfile = WINHELP_LookupHelpFile(link->string))) 00913 { 00914 if (link->window == -1) 00915 { 00916 wi = win->info; 00917 if (wi->win_style & WS_POPUP) wi = Globals.active_win->info; 00918 } 00919 else if (link->window < hlpfile->numWindows) 00920 wi = &hlpfile->windows[link->window]; 00921 else 00922 { 00923 WINE_WARN("link to window %d/%d\n", link->window, hlpfile->numWindows); 00924 break; 00925 } 00926 WINHELP_OpenHelpWindow(HLPFILE_PageByHash, hlpfile, link->hash, wi, SW_NORMAL); 00927 } 00928 break; 00929 case hlp_link_popup: 00930 if ((hlpfile = WINHELP_LookupHelpFile(link->string))) 00931 WINHELP_OpenHelpWindow(HLPFILE_PageByHash, hlpfile, link->hash, 00932 WINHELP_GetPopupWindowInfo(hlpfile, win, lParam), 00933 SW_NORMAL); 00934 break; 00935 case hlp_link_macro: 00936 MACRO_ExecuteMacro(win, link->string); 00937 break; 00938 default: 00939 WINE_FIXME("Unknown link cookie %d\n", link->cookie); 00940 } 00941 ret = TRUE; 00942 } 00943 break; 00944 } 00945 return ret; 00946 } 00947 00948 /*********************************************************************** 00949 * 00950 * WINHELP_CheckPopup 00951 */ 00952 static BOOL WINHELP_CheckPopup(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, LRESULT* lret) 00953 { 00954 WINHELP_WINDOW* popup; 00955 00956 if (!Globals.active_popup) return FALSE; 00957 00958 switch (msg) 00959 { 00960 case WM_NOTIFY: 00961 { 00962 MSGFILTER* msgf = (MSGFILTER*)lParam; 00963 if (msgf->nmhdr.code == EN_MSGFILTER) 00964 { 00965 if (!WINHELP_CheckPopup(hWnd, msgf->msg, msgf->wParam, msgf->lParam, NULL)) 00966 return FALSE; 00967 if (lret) *lret = 1; 00968 return TRUE; 00969 } 00970 } 00971 break; 00972 case WM_ACTIVATE: 00973 if (LOWORD(wParam) != WA_INACTIVE || (HWND)lParam == Globals.active_win->hMainWnd || 00974 (HWND)lParam == Globals.active_popup->hMainWnd || 00975 GetWindow((HWND)lParam, GW_OWNER) == Globals.active_win->hMainWnd) 00976 break; 00977 /* fall through */ 00978 case WM_LBUTTONDOWN: 00979 if (msg == WM_LBUTTONDOWN) 00980 WINHELP_HandleTextMouse(Globals.active_popup, msg, lParam); 00981 /* fall through */ 00982 case WM_MBUTTONDOWN: 00983 case WM_RBUTTONDOWN: 00984 case WM_NCLBUTTONDOWN: 00985 case WM_NCMBUTTONDOWN: 00986 case WM_NCRBUTTONDOWN: 00987 popup = Globals.active_popup; 00988 Globals.active_popup = NULL; 00989 WINHELP_ReleaseWindow(popup); 00990 return TRUE; 00991 } 00992 return FALSE; 00993 } 00994 00995 /*********************************************************************** 00996 * 00997 * WINHELP_ButtonWndProc 00998 */ 00999 static LRESULT CALLBACK WINHELP_ButtonWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) 01000 { 01001 if (WINHELP_CheckPopup(hWnd, msg, wParam, lParam, NULL)) return 0; 01002 01003 if (msg == WM_KEYDOWN) 01004 { 01005 switch (wParam) 01006 { 01007 case VK_UP: 01008 case VK_DOWN: 01009 case VK_PRIOR: 01010 case VK_NEXT: 01011 case VK_ESCAPE: 01012 return SendMessage(GetParent(hWnd), msg, wParam, lParam); 01013 } 01014 } 01015 01016 return CallWindowProc(Globals.button_proc, hWnd, msg, wParam, lParam); 01017 } 01018 01019 /*********************************************************************** 01020 * 01021 * WINHELP_ButtonBoxWndProc 01022 */ 01023 static LRESULT CALLBACK WINHELP_ButtonBoxWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) 01024 { 01025 WINDOWPOS *winpos; 01026 WINHELP_WINDOW *win; 01027 WINHELP_BUTTON *button; 01028 SIZE button_size; 01029 INT x, y; 01030 01031 if (WINHELP_CheckPopup(hWnd, msg, wParam, lParam, NULL)) return 0L; 01032 01033 switch (msg) 01034 { 01035 case WM_WINDOWPOSCHANGING: 01036 winpos = (WINDOWPOS*) lParam; 01037 win = (WINHELP_WINDOW*) GetWindowLongPtr(GetParent(hWnd), 0); 01038 01039 /* Update buttons */ 01040 button_size.cx = 0; 01041 button_size.cy = 0; 01042 for (button = win->first_button; button; button = button->next) 01043 { 01044 HDC hDc; 01045 SIZE textsize; 01046 if (!button->hWnd) 01047 { 01048 button->hWnd = CreateWindow(STRING_BUTTON, button->lpszName, 01049 WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 01050 0, 0, 0, 0, 01051 hWnd, (HMENU) button->wParam, 01052 Globals.hInstance, 0); 01053 if (button->hWnd) 01054 { 01055 if (Globals.button_proc == NULL) 01056 { 01057 NONCLIENTMETRICSW ncm; 01058 Globals.button_proc = (WNDPROC) GetWindowLongPtr(button->hWnd, GWLP_WNDPROC); 01059 01060 ncm.cbSize = sizeof(NONCLIENTMETRICSW); 01061 SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, 01062 sizeof(NONCLIENTMETRICSW), &ncm, 0); 01063 Globals.hButtonFont = CreateFontIndirectW(&ncm.lfMenuFont); 01064 } 01065 SetWindowLongPtr(button->hWnd, GWLP_WNDPROC, (LONG_PTR) WINHELP_ButtonWndProc); 01066 if (Globals.hButtonFont) 01067 SendMessage(button->hWnd, WM_SETFONT, (WPARAM)Globals.hButtonFont, TRUE); 01068 } 01069 } 01070 hDc = GetDC(button->hWnd); 01071 GetTextExtentPoint(hDc, button->lpszName, 01072 lstrlen(button->lpszName), &textsize); 01073 ReleaseDC(button->hWnd, hDc); 01074 01075 button_size.cx = max(button_size.cx, textsize.cx + BUTTON_CX); 01076 button_size.cy = max(button_size.cy, textsize.cy + BUTTON_CY); 01077 } 01078 01079 x = 0; 01080 y = 0; 01081 for (button = win->first_button; button; button = button->next) 01082 { 01083 SetWindowPos(button->hWnd, HWND_TOP, x, y, button_size.cx, button_size.cy, 0); 01084 01085 if (x + 2 * button_size.cx <= winpos->cx) 01086 x += button_size.cx; 01087 else 01088 x = 0, y += button_size.cy; 01089 } 01090 winpos->cy = y + (x ? button_size.cy : 0); 01091 break; 01092 01093 case WM_COMMAND: 01094 SendMessage(GetParent(hWnd), msg, wParam, lParam); 01095 break; 01096 01097 case WM_KEYDOWN: 01098 switch (wParam) 01099 { 01100 case VK_UP: 01101 case VK_DOWN: 01102 case VK_PRIOR: 01103 case VK_NEXT: 01104 case VK_ESCAPE: 01105 return SendMessage(GetParent(hWnd), msg, wParam, lParam); 01106 } 01107 break; 01108 } 01109 01110 return DefWindowProc(hWnd, msg, wParam, lParam); 01111 } 01112 01113 /****************************************************************** 01114 * WINHELP_HistoryWndProc 01115 * 01116 * 01117 */ 01118 static LRESULT CALLBACK WINHELP_HistoryWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) 01119 { 01120 WINHELP_WINDOW* win; 01121 PAINTSTRUCT ps; 01122 HDC hDc; 01123 TEXTMETRIC tm; 01124 unsigned int i; 01125 RECT r; 01126 01127 switch (msg) 01128 { 01129 case WM_NCCREATE: 01130 win = (WINHELP_WINDOW*)((LPCREATESTRUCT)lParam)->lpCreateParams; 01131 SetWindowLongPtr(hWnd, 0, (ULONG_PTR)win); 01132 win->hHistoryWnd = hWnd; 01133 break; 01134 case WM_CREATE: 01135 win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0); 01136 hDc = GetDC(hWnd); 01137 GetTextMetrics(hDc, &tm); 01138 GetWindowRect(hWnd, &r); 01139 01140 r.right = r.left + 30 * tm.tmAveCharWidth; 01141 r.bottom = r.top + (sizeof(Globals.history.set) / sizeof(Globals.history.set[0])) * tm.tmHeight; 01142 AdjustWindowRect(&r, GetWindowLong(hWnd, GWL_STYLE), FALSE); 01143 if (r.left < 0) {r.right -= r.left; r.left = 0;} 01144 if (r.top < 0) {r.bottom -= r.top; r.top = 0;} 01145 01146 MoveWindow(hWnd, r.left, r.top, r.right, r.bottom, TRUE); 01147 ReleaseDC(hWnd, hDc); 01148 break; 01149 case WM_LBUTTONDOWN: 01150 win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0); 01151 hDc = GetDC(hWnd); 01152 GetTextMetrics(hDc, &tm); 01153 i = HIWORD(lParam) / tm.tmHeight; 01154 if (i < Globals.history.index) 01155 WINHELP_CreateHelpWindow(&Globals.history.set[i], SW_SHOW, TRUE); 01156 ReleaseDC(hWnd, hDc); 01157 break; 01158 case WM_PAINT: 01159 hDc = BeginPaint(hWnd, &ps); 01160 win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0); 01161 GetTextMetrics(hDc, &tm); 01162 01163 for (i = 0; i < Globals.history.index; i++) 01164 { 01165 if (Globals.history.set[i].page->file == Globals.active_win->page->file) 01166 { 01167 TextOut(hDc, 0, i * tm.tmHeight, 01168 Globals.history.set[i].page->lpszTitle, 01169 strlen(Globals.history.set[i].page->lpszTitle)); 01170 } 01171 else 01172 { 01173 char buffer[1024]; 01174 const char* ptr1; 01175 const char* ptr2; 01176 unsigned len; 01177 01178 ptr1 = strrchr(Globals.history.set[i].page->file->lpszPath, '\\'); 01179 if (!ptr1) ptr1 = Globals.history.set[i].page->file->lpszPath; 01180 else ptr1++; 01181 ptr2 = strrchr(ptr1, '.'); 01182 len = ptr2 ? ptr2 - ptr1 : strlen(ptr1); 01183 if (len > sizeof(buffer)) len = sizeof(buffer); 01184 memcpy(buffer, ptr1, len); 01185 if (len < sizeof(buffer)) buffer[len++] = ':'; 01186 strncpy(&buffer[len], Globals.history.set[i].page->lpszTitle, sizeof(buffer) - len); 01187 buffer[sizeof(buffer) - 1] = '\0'; 01188 TextOut(hDc, 0, i * tm.tmHeight, buffer, strlen(buffer)); 01189 } 01190 } 01191 EndPaint(hWnd, &ps); 01192 break; 01193 case WM_DESTROY: 01194 win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0); 01195 if (hWnd == win->hHistoryWnd) 01196 win->hHistoryWnd = 0; 01197 break; 01198 } 01199 return DefWindowProc(hWnd, msg, wParam, lParam); 01200 } 01201 01202 /************************************************************************** 01203 * cb_KWBTree 01204 * 01205 * HLPFILE_BPTreeCallback enumeration function for '|KWBTREE' internal file. 01206 * 01207 */ 01208 static void cb_KWBTree(void *p, void **next, void *cookie) 01209 { 01210 HWND hListWnd = cookie; 01211 int count; 01212 01213 WINE_TRACE("Adding '%s' to search list\n", (char *)p); 01214 SendMessage(hListWnd, LB_INSERTSTRING, -1, (LPARAM)p); 01215 count = SendMessage(hListWnd, LB_GETCOUNT, 0, 0); 01216 SendMessage(hListWnd, LB_SETITEMDATA, count-1, (LPARAM)p); 01217 *next = (char*)p + strlen((char*)p) + 7; 01218 } 01219 01220 struct index_data 01221 { 01222 HLPFILE* hlpfile; 01223 BOOL jump; 01224 ULONG offset; 01225 }; 01226 01227 /************************************************************************** 01228 * WINHELP_IndexDlgProc 01229 * 01230 */ 01231 static INT_PTR CALLBACK WINHELP_IndexDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) 01232 { 01233 static struct index_data* id; 01234 int sel; 01235 01236 switch (msg) 01237 { 01238 case WM_INITDIALOG: 01239 id = (struct index_data*)((PROPSHEETPAGE*)lParam)->lParam; 01240 HLPFILE_BPTreeEnum(id->hlpfile->kwbtree, cb_KWBTree, 01241 GetDlgItem(hWnd, IDC_INDEXLIST)); 01242 id->jump = FALSE; 01243 id->offset = 1; 01244 return TRUE; 01245 case WM_COMMAND: 01246 switch (HIWORD(wParam)) 01247 { 01248 case LBN_DBLCLK: 01249 if (LOWORD(wParam) == IDC_INDEXLIST) 01250 SendMessage(GetParent(hWnd), PSM_PRESSBUTTON, PSBTN_OK, 0); 01251 break; 01252 } 01253 break; 01254 case WM_NOTIFY: 01255 switch (((NMHDR*)lParam)->code) 01256 { 01257 case PSN_APPLY: 01258 sel = SendDlgItemMessage(hWnd, IDC_INDEXLIST, LB_GETCURSEL, 0, 0); 01259 if (sel != LB_ERR) 01260 { 01261 BYTE *p; 01262 int count; 01263 01264 p = (BYTE*)SendDlgItemMessage(hWnd, IDC_INDEXLIST, 01265 LB_GETITEMDATA, sel, 0); 01266 count = *(short*)((char *)p + strlen((char *)p) + 1); 01267 if (count > 1) 01268 { 01269 MessageBox(hWnd, "count > 1 not supported yet", "Error", MB_OK | MB_ICONSTOP); 01270 SetWindowLongPtr(hWnd, DWLP_MSGRESULT, PSNRET_INVALID); 01271 return TRUE; 01272 } 01273 id->offset = *(ULONG*)((char *)p + strlen((char *)p) + 3); 01274 id->offset = *(long*)(id->hlpfile->kwdata + id->offset + 9); 01275 if (id->offset == 0xFFFFFFFF) 01276 { 01277 MessageBox(hWnd, "macro keywords not supported yet", "Error", MB_OK | MB_ICONSTOP); 01278 SetWindowLongPtr(hWnd, DWLP_MSGRESULT, PSNRET_INVALID); 01279 return TRUE; 01280 } 01281 id->jump = TRUE; 01282 SetWindowLongPtr(hWnd, DWLP_MSGRESULT, PSNRET_NOERROR); 01283 } 01284 return TRUE; 01285 default: 01286 return FALSE; 01287 } 01288 break; 01289 default: 01290 break; 01291 } 01292 return FALSE; 01293 } 01294 01295 /************************************************************************** 01296 * WINHELP_SearchDlgProc 01297 * 01298 */ 01299 static INT_PTR CALLBACK WINHELP_SearchDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) 01300 { 01301 switch (msg) 01302 { 01303 case WM_INITDIALOG: 01304 return TRUE; 01305 case WM_NOTIFY: 01306 switch (((NMHDR*)lParam)->code) 01307 { 01308 case PSN_APPLY: 01309 SetWindowLongPtr(hWnd, DWLP_MSGRESULT, PSNRET_NOERROR); 01310 return TRUE; 01311 default: 01312 return FALSE; 01313 } 01314 break; 01315 default: 01316 break; 01317 } 01318 return FALSE; 01319 } 01320 01321 /*********************************************************************** 01322 * 01323 * WINHELP_MainWndProc 01324 */ 01325 static LRESULT CALLBACK WINHELP_MainWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) 01326 { 01327 WINHELP_WINDOW *win; 01328 WINHELP_BUTTON *button; 01329 HWND hTextWnd; 01330 LRESULT ret; 01331 01332 if (WINHELP_CheckPopup(hWnd, msg, wParam, lParam, &ret)) return ret; 01333 01334 switch (msg) 01335 { 01336 case WM_NCCREATE: 01337 win = (WINHELP_WINDOW*) ((LPCREATESTRUCT) lParam)->lpCreateParams; 01338 SetWindowLongPtr(hWnd, 0, (ULONG_PTR) win); 01339 if (!win->page && Globals.isBook) 01340 PostMessage(hWnd, WM_COMMAND, MNID_FILE_OPEN, 0); 01341 win->hMainWnd = hWnd; 01342 break; 01343 01344 case WM_WINDOWPOSCHANGED: 01345 WINHELP_LayoutMainWindow((WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0)); 01346 break; 01347 01348 case WM_COMMAND: 01349 win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0); 01350 switch (wParam) 01351 { 01352 /* Menu FILE */ 01353 case MNID_FILE_OPEN: MACRO_FileOpen(); break; 01354 case MNID_FILE_PRINT: MACRO_Print(); break; 01355 case MNID_FILE_SETUP: MACRO_PrinterSetup(); break; 01356 case MNID_FILE_EXIT: MACRO_Exit(); break; 01357 01358 /* Menu EDIT */ 01359 case MNID_EDIT_COPYDLG: 01360 SendMessage(GetDlgItem(hWnd, CTL_ID_TEXT), WM_COPY, 0, 0); 01361 break; 01362 case MNID_EDIT_ANNOTATE:MACRO_Annotate(); break; 01363 01364 /* Menu Bookmark */ 01365 case MNID_BKMK_DEFINE: MACRO_BookmarkDefine(); break; 01366 01367 /* Menu Help */ 01368 case MNID_HELP_HELPON: MACRO_HelpOn(); break; 01369 case MNID_HELP_HELPTOP: MACRO_HelpOnTop(); break; 01370 case MNID_HELP_ABOUT: MACRO_About(); break; 01371 01372 /* Context help */ 01373 case MNID_CTXT_ANNOTATE:MACRO_Annotate(); break; 01374 case MNID_CTXT_COPY: MACRO_CopyDialog(); break; 01375 case MNID_CTXT_PRINT: MACRO_Print(); break; 01376 case MNID_OPTS_HISTORY: MACRO_History(); break; 01377 case MNID_OPTS_FONTS_SMALL: 01378 case MNID_CTXT_FONTS_SMALL: 01379 win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0); 01380 if (win->font_scale != 0) 01381 { 01382 win->font_scale = 0; 01383 WINHELP_SetupText(GetDlgItem(hWnd, CTL_ID_TEXT), win, 0 /* FIXME */); 01384 } 01385 break; 01386 case MNID_OPTS_FONTS_NORMAL: 01387 case MNID_CTXT_FONTS_NORMAL: 01388 win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0); 01389 if (win->font_scale != 1) 01390 { 01391 win->font_scale = 1; 01392 WINHELP_SetupText(GetDlgItem(hWnd, CTL_ID_TEXT), win, 0 /* FIXME */); 01393 } 01394 break; 01395 case MNID_OPTS_FONTS_LARGE: 01396 case MNID_CTXT_FONTS_LARGE: 01397 win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0); 01398 if (win->font_scale != 2) 01399 { 01400 win->font_scale = 2; 01401 WINHELP_SetupText(GetDlgItem(hWnd, CTL_ID_TEXT), win, 0 /* FIXME */); 01402 } 01403 break; 01404 case MNID_OPTS_HELP_DEFAULT: 01405 case MNID_OPTS_HELP_VISIBLE: 01406 case MNID_OPTS_HELP_NONVISIBLE: 01407 case MNID_OPTS_SYSTEM_COLORS: 01408 case MNID_CTXT_HELP_DEFAULT: 01409 case MNID_CTXT_HELP_VISIBLE: 01410 case MNID_CTXT_HELP_NONVISIBLE: 01411 case MNID_CTXT_SYSTEM_COLORS: 01412 /* FIXME: NIY */ 01413 01414 default: 01415 /* Buttons */ 01416 for (button = win->first_button; button; button = button->next) 01417 if (wParam == button->wParam) break; 01418 if (button) 01419 MACRO_ExecuteMacro(win, button->lpszMacro); 01420 else if (!HIWORD(wParam)) 01421 MessageBox(0, MAKEINTRESOURCE(STID_NOT_IMPLEMENTED), 01422 MAKEINTRESOURCE(STID_WHERROR), MB_OK); 01423 break; 01424 } 01425 break; 01426 /* EPP case WM_DESTROY: */ 01427 /* EPP if (Globals.hPopupWnd) DestroyWindow(Globals.hPopupWnd); */ 01428 /* EPP break; */ 01429 case WM_COPYDATA: 01430 return WINHELP_HandleCommand((HWND)wParam, lParam); 01431 01432 case WM_CHAR: 01433 if (wParam == 3) 01434 { 01435 SendMessage(GetDlgItem(hWnd, CTL_ID_TEXT), WM_COPY, 0, 0); 01436 return 0; 01437 } 01438 break; 01439 01440 case WM_KEYDOWN: 01441 win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0); 01442 hTextWnd = GetDlgItem(win->hMainWnd, CTL_ID_TEXT); 01443 01444 switch (wParam) 01445 { 01446 case VK_UP: 01447 SendMessage(hTextWnd, EM_SCROLL, SB_LINEUP, 0); 01448 return 0; 01449 case VK_DOWN: 01450 SendMessage(hTextWnd, EM_SCROLL, SB_LINEDOWN, 0); 01451 return 0; 01452 case VK_PRIOR: 01453 SendMessage(hTextWnd, EM_SCROLL, SB_PAGEUP, 0); 01454 return 0; 01455 case VK_NEXT: 01456 SendMessage(hTextWnd, EM_SCROLL, SB_PAGEDOWN, 0); 01457 return 0; 01458 case VK_ESCAPE: 01459 MACRO_Exit(); 01460 return 0; 01461 } 01462 break; 01463 01464 case WM_NOTIFY: 01465 if (wParam == CTL_ID_TEXT) 01466 { 01467 RECT rc; 01468 01469 switch (((NMHDR*)lParam)->code) 01470 { 01471 case EN_MSGFILTER: 01472 { 01473 const MSGFILTER* msgf = (const MSGFILTER*)lParam; 01474 switch (msgf->msg) 01475 { 01476 case WM_KEYUP: 01477 if (msgf->wParam == VK_ESCAPE) 01478 WINHELP_ReleaseWindow((WINHELP_WINDOW*)GetWindowLongPtr(hWnd, 0)); 01479 break; 01480 case WM_RBUTTONDOWN: 01481 { 01482 HMENU hMenu; 01483 POINT pt; 01484 01485 win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0); 01486 hMenu = LoadMenu(Globals.hInstance, (LPSTR)CONTEXT_MENU); 01487 switch (win->font_scale) 01488 { 01489 case 0: 01490 CheckMenuItem(hMenu, MNID_CTXT_FONTS_SMALL, 01491 MF_BYCOMMAND|MF_CHECKED); 01492 break; 01493 default: 01494 WINE_FIXME("Unsupported %d\n", win->font_scale); 01495 case 1: 01496 CheckMenuItem(hMenu, MNID_CTXT_FONTS_NORMAL, 01497 MF_BYCOMMAND|MF_CHECKED); 01498 break; 01499 case 2: 01500 CheckMenuItem(hMenu, MNID_CTXT_FONTS_LARGE, 01501 MF_BYCOMMAND|MF_CHECKED); 01502 break; 01503 } 01504 pt.x = (int)(short)LOWORD(msgf->lParam); 01505 pt.y = (int)(short)HIWORD(msgf->lParam); 01506 ClientToScreen(msgf->nmhdr.hwndFrom, &pt); 01507 TrackPopupMenu(GetSubMenu(hMenu, 0), TPM_LEFTALIGN|TPM_TOPALIGN, 01508 pt.x, pt.y, 0, hWnd, NULL); 01509 DestroyMenu(hMenu); 01510 } 01511 break; 01512 default: 01513 return WINHELP_HandleTextMouse((WINHELP_WINDOW*)GetWindowLongPtr(hWnd, 0), 01514 msgf->msg, msgf->lParam); 01515 } 01516 } 01517 break; 01518 01519 case EN_REQUESTRESIZE: 01520 rc = ((REQRESIZE*)lParam)->rc; 01521 win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0); 01522 AdjustWindowRect(&rc, GetWindowLong(win->hMainWnd, GWL_STYLE), 01523 FALSE); 01524 SetWindowPos(win->hMainWnd, HWND_TOP, 0, 0, 01525 rc.right - rc.left, rc.bottom - rc.top, 01526 SWP_NOMOVE | SWP_NOZORDER); 01527 WINHELP_LayoutMainWindow(win); 01528 break; 01529 } 01530 } 01531 break; 01532 01533 case WM_INITMENUPOPUP: 01534 win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0); 01535 CheckMenuItem((HMENU)wParam, MNID_OPTS_FONTS_SMALL, 01536 MF_BYCOMMAND | (win->font_scale == 0) ? MF_CHECKED : 0); 01537 CheckMenuItem((HMENU)wParam, MNID_OPTS_FONTS_NORMAL, 01538 MF_BYCOMMAND | (win->font_scale == 1) ? MF_CHECKED : 0); 01539 CheckMenuItem((HMENU)wParam, MNID_OPTS_FONTS_LARGE, 01540 MF_BYCOMMAND | (win->font_scale == 2) ? MF_CHECKED : 0); 01541 break; 01542 case WM_DESTROY: 01543 win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0); 01544 WINHELP_DeleteWindow(win); 01545 break; 01546 } 01547 return DefWindowProc(hWnd, msg, wParam, lParam); 01548 } 01549 01550 /************************************************************************** 01551 * WINHELP_CreateIndexWindow 01552 * 01553 * Displays a dialog with keywords of current help file. 01554 * 01555 */ 01556 BOOL WINHELP_CreateIndexWindow(BOOL is_search) 01557 { 01558 HPROPSHEETPAGE psPage[3]; 01559 PROPSHEETPAGE psp; 01560 PROPSHEETHEADER psHead; 01561 struct index_data id; 01562 char buf[256]; 01563 01564 if (Globals.active_win && Globals.active_win->page && Globals.active_win->page->file) 01565 id.hlpfile = Globals.active_win->page->file; 01566 else 01567 return FALSE; 01568 01569 if (id.hlpfile->kwbtree == NULL) 01570 { 01571 WINE_TRACE("No index provided\n"); 01572 return FALSE; 01573 } 01574 01575 InitCommonControls(); 01576 01577 id.jump = FALSE; 01578 memset(&psp, 0, sizeof(psp)); 01579 psp.dwSize = sizeof(psp); 01580 psp.dwFlags = 0; 01581 psp.hInstance = Globals.hInstance; 01582 01583 psp.u.pszTemplate = MAKEINTRESOURCE(IDD_INDEX); 01584 psp.lParam = (LPARAM)&id; 01585 psp.pfnDlgProc = WINHELP_IndexDlgProc; 01586 psPage[0] = CreatePropertySheetPage(&psp); 01587 01588 psp.u.pszTemplate = MAKEINTRESOURCE(IDD_SEARCH); 01589 psp.lParam = (LPARAM)&id; 01590 psp.pfnDlgProc = WINHELP_SearchDlgProc; 01591 psPage[1] = CreatePropertySheetPage(&psp); 01592 01593 memset(&psHead, 0, sizeof(psHead)); 01594 psHead.dwSize = sizeof(psHead); 01595 01596 LoadString(Globals.hInstance, STID_PSH_INDEX, buf, sizeof(buf)); 01597 strcat(buf, Globals.active_win->info->caption); 01598 01599 psHead.pszCaption = buf; 01600 psHead.nPages = 2; 01601 psHead.u2.nStartPage = is_search ? 1 : 0; 01602 psHead.hwndParent = Globals.active_win->hMainWnd; 01603 psHead.u3.phpage = psPage; 01604 psHead.dwFlags = PSH_NOAPPLYNOW; 01605 01606 PropertySheet(&psHead); 01607 if (id.jump) 01608 { 01609 WINE_TRACE("got %d as an offset\n", id.offset); 01610 WINHELP_OpenHelpWindow(HLPFILE_PageByOffset, id.hlpfile, id.offset, 01611 Globals.active_win->info, SW_NORMAL); 01612 } 01613 return TRUE; 01614 } 01615 01616 /*********************************************************************** 01617 * 01618 * RegisterWinClasses 01619 */ 01620 static BOOL WINHELP_RegisterWinClasses(void) 01621 { 01622 WNDCLASSEX class_main, class_button_box, class_history; 01623 01624 class_main.cbSize = sizeof(class_main); 01625 class_main.style = CS_HREDRAW | CS_VREDRAW; 01626 class_main.lpfnWndProc = WINHELP_MainWndProc; 01627 class_main.cbClsExtra = 0; 01628 class_main.cbWndExtra = sizeof(WINHELP_WINDOW *); 01629 class_main.hInstance = Globals.hInstance; 01630 class_main.hIcon = LoadIcon(Globals.hInstance, MAKEINTRESOURCE(IDI_WINHELP)); 01631 class_main.hCursor = LoadCursor(0, IDC_ARROW); 01632 class_main.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); 01633 class_main.lpszMenuName = 0; 01634 class_main.lpszClassName = MAIN_WIN_CLASS_NAME; 01635 class_main.hIconSm = LoadImage(Globals.hInstance, MAKEINTRESOURCE(IDI_WINHELP), IMAGE_ICON, 01636 GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), 01637 LR_SHARED); 01638 01639 class_button_box = class_main; 01640 class_button_box.lpfnWndProc = WINHELP_ButtonBoxWndProc; 01641 class_button_box.cbWndExtra = 0; 01642 class_button_box.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1); 01643 class_button_box.lpszClassName = BUTTON_BOX_WIN_CLASS_NAME; 01644 01645 class_history = class_main; 01646 class_history.lpfnWndProc = WINHELP_HistoryWndProc; 01647 class_history.lpszClassName = HISTORY_WIN_CLASS_NAME; 01648 01649 return (RegisterClassEx(&class_main) && 01650 RegisterClassEx(&class_button_box) && 01651 RegisterClassEx(&class_history)); 01652 } 01653 01654 /*********************************************************************** 01655 * 01656 * WinMain 01657 */ 01658 int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE prev, LPSTR cmdline, int show) 01659 { 01660 MSG msg; 01661 LONG lHash = 0; 01662 HLPFILE* hlpfile; 01663 static CHAR default_wndname[] = "main"; 01664 LPSTR wndname = default_wndname; 01665 WINHELP_DLL* dll; 01666 01667 Globals.hInstance = hInstance; 01668 01669 if (LoadLibrary("riched20.dll") == NULL) 01670 return MessageBox(0, MAKEINTRESOURCE(STID_NO_RICHEDIT), 01671 MAKEINTRESOURCE(STID_WHERROR), MB_OK); 01672 01673 /* Get options */ 01674 while (*cmdline && (*cmdline == ' ' || *cmdline == '-')) 01675 { 01676 CHAR option; 01677 LPCSTR topic_id; 01678 if (*cmdline++ == ' ') continue; 01679 01680 option = *cmdline; 01681 if (option) cmdline++; 01682 while (*cmdline && *cmdline == ' ') cmdline++; 01683 switch (option) 01684 { 01685 case 'i': 01686 case 'I': 01687 topic_id = cmdline; 01688 while (*cmdline && *cmdline != ' ') cmdline++; 01689 if (*cmdline) *cmdline++ = '\0'; 01690 lHash = HLPFILE_Hash(topic_id); 01691 break; 01692 01693 case '3': 01694 case '4': 01695 Globals.wVersion = option - '0'; 01696 break; 01697 01698 case 'x': 01699 show = SW_HIDE; 01700 Globals.isBook = FALSE; 01701 break; 01702 01703 default: 01704 WINE_FIXME("Unsupported cmd line: %s\n", cmdline); 01705 break; 01706 } 01707 } 01708 01709 /* Create primary window */ 01710 if (!WINHELP_RegisterWinClasses()) 01711 { 01712 WINE_FIXME("Couldn't register classes\n"); 01713 return 0; 01714 } 01715 01716 if (*cmdline) 01717 { 01718 char* ptr; 01719 if ((*cmdline == '"') && (ptr = strchr(cmdline+1, '"'))) 01720 { 01721 cmdline++; 01722 *ptr = '\0'; 01723 } 01724 if ((ptr = strchr(cmdline, '>'))) 01725 { 01726 *ptr = '\0'; 01727 wndname = ptr + 1; 01728 } 01729 hlpfile = WINHELP_LookupHelpFile(cmdline); 01730 if (!hlpfile) return 0; 01731 } 01732 else hlpfile = NULL; 01733 WINHELP_OpenHelpWindow(HLPFILE_PageByHash, hlpfile, lHash, 01734 WINHELP_GetWindowInfo(hlpfile, wndname), show); 01735 01736 /* Message loop */ 01737 while ((Globals.win_list || Globals.active_popup) && GetMessage(&msg, 0, 0, 0)) 01738 { 01739 TranslateMessage(&msg); 01740 DispatchMessage(&msg); 01741 } 01742 for (dll = Globals.dlls; dll; dll = dll->next) 01743 { 01744 if (dll->class & DC_INITTERM) dll->handler(DW_TERM, 0, 0); 01745 } 01746 return 0; 01747 } Generated on Sun May 27 2012 04:17:50 for ReactOS by
1.7.6.1
|