winhelp.c 56 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739
  1. /*
  2. * Help Viewer
  3. *
  4. * Copyright 1996 Ulrich Schmid <uschmid@mail.hh.provi.de>
  5. * 2002 Sylvain Petreolle <spetreolle@yahoo.fr>
  6. * 2002, 2008 Eric Pouech <eric.pouech@wanadoo.fr>
  7. * 2004 Ken Belleau <jamez@ivic.qc.ca>
  8. * 2008 Kirill K. Smirnov <lich@math.spbu.ru>
  9. *
  10. * This library is free software; you can redistribute it and/or
  11. * modify it under the terms of the GNU Lesser General Public
  12. * License as published by the Free Software Foundation; either
  13. * version 2.1 of the License, or (at your option) any later version.
  14. *
  15. * This library is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  18. * Lesser General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU Lesser General Public
  21. * License along with this library; if not, write to the Free Software
  22. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  23. */
  24. #include <assert.h>
  25. #include <stdio.h>
  26. #include <string.h>
  27. #include <stdarg.h>
  28. #include <stdlib.h>
  29. #define NONAMELESSUNION
  30. #include "windef.h"
  31. #include "winbase.h"
  32. #include "wingdi.h"
  33. #include "winuser.h"
  34. #include "commdlg.h"
  35. #include "winhelp.h"
  36. #include "winhelp_res.h"
  37. #include "shellapi.h"
  38. #include "richedit.h"
  39. #include "commctrl.h"
  40. #include "wine/debug.h"
  41. WINE_DEFAULT_DEBUG_CHANNEL(winhelp);
  42. WINHELP_GLOBALS Globals = {3, NULL, TRUE, NULL, NULL, NULL, NULL, NULL, {{{NULL,NULL}},0}, NULL};
  43. #define CTL_ID_BUTTON 0x700
  44. #define CTL_ID_TEXT 0x701
  45. /***********************************************************************
  46. *
  47. * WINHELP_InitFonts
  48. */
  49. static void WINHELP_InitFonts(HWND hWnd)
  50. {
  51. WINHELP_WINDOW *win = (WINHELP_WINDOW*) GetWindowLongPtrW(hWnd, 0);
  52. LOGFONTW logfontlist[] = {
  53. {-10, 0, 0, 0, 400, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 32, {'H','e','l','v',0}},
  54. {-12, 0, 0, 0, 700, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 32, {'H','e','l','v',0}},
  55. {-12, 0, 0, 0, 700, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 32, {'H','e','l','v',0}},
  56. {-12, 0, 0, 0, 400, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 32, {'H','e','l','v',0}},
  57. {-12, 0, 0, 0, 700, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 32, {'H','e','l','v',0}},
  58. {-10, 0, 0, 0, 700, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 32, {'H','e','l','v',0}},
  59. { -8, 0, 0, 0, 400, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 32, {'H','e','l','v',0}}};
  60. static HFONT fonts[ARRAY_SIZE(logfontlist)];
  61. static BOOL init = FALSE;
  62. win->fonts_len = ARRAY_SIZE(logfontlist);
  63. win->fonts = fonts;
  64. if (!init)
  65. {
  66. UINT i;
  67. for (i = 0; i < ARRAY_SIZE(logfontlist); i++)
  68. {
  69. fonts[i] = CreateFontIndirectW(&logfontlist[i]);
  70. }
  71. init = TRUE;
  72. }
  73. }
  74. static DWORD CALLBACK WINHELP_RtfStreamIn(DWORD_PTR cookie, BYTE* buff,
  75. LONG cb, LONG* pcb)
  76. {
  77. struct RtfData* rd = (struct RtfData*)cookie;
  78. if (rd->where >= rd->ptr) return 1;
  79. if (rd->where + cb > rd->ptr)
  80. cb = rd->ptr - rd->where;
  81. memcpy(buff, rd->where, cb);
  82. rd->where += cb;
  83. *pcb = cb;
  84. return 0;
  85. }
  86. static void WINHELP_SetupText(HWND hTextWnd, WINHELP_WINDOW* win, ULONG relative)
  87. {
  88. static const WCHAR emptyW[1];
  89. /* At first clear area - needed by EM_POSFROMCHAR/EM_SETSCROLLPOS */
  90. SendMessageW(hTextWnd, WM_SETTEXT, 0, (LPARAM)emptyW);
  91. SendMessageW(hTextWnd, WM_SETREDRAW, FALSE, 0);
  92. SendMessageW(hTextWnd, EM_SETBKGNDCOLOR, 0, (LPARAM)win->info->sr_color);
  93. /* set word-wrap to window size (undocumented) */
  94. SendMessageW(hTextWnd, EM_SETTARGETDEVICE, 0, 0);
  95. if (win->page)
  96. {
  97. struct RtfData rd;
  98. EDITSTREAM es;
  99. unsigned cp = 0;
  100. POINTL ptl;
  101. POINT pt;
  102. if (HLPFILE_BrowsePage(win->page, &rd, win->font_scale, relative))
  103. {
  104. rd.where = rd.data;
  105. es.dwCookie = (DWORD_PTR)&rd;
  106. es.dwError = 0;
  107. es.pfnCallback = WINHELP_RtfStreamIn;
  108. SendMessageW(hTextWnd, EM_STREAMIN, SF_RTF, (LPARAM)&es);
  109. cp = rd.char_pos_rel;
  110. }
  111. /* FIXME: else leaking potentially the rd.first_link chain */
  112. HeapFree(GetProcessHeap(), 0, rd.data);
  113. SendMessageW(hTextWnd, EM_POSFROMCHAR, (WPARAM)&ptl, cp ? cp - 1 : 0);
  114. pt.x = 0; pt.y = ptl.y;
  115. SendMessageW(hTextWnd, EM_SETSCROLLPOS, 0, (LPARAM)&pt);
  116. }
  117. SendMessageW(hTextWnd, WM_SETREDRAW, TRUE, 0);
  118. RedrawWindow(hTextWnd, NULL, NULL, RDW_FRAME|RDW_INVALIDATE);
  119. }
  120. /***********************************************************************
  121. *
  122. * WINHELP_GetOpenFileName
  123. */
  124. BOOL WINHELP_GetOpenFileName(LPSTR lpszFile, int len)
  125. {
  126. OPENFILENAMEA openfilename;
  127. CHAR szDir[MAX_PATH];
  128. CHAR szzFilter[2 * MAX_STRING_LEN + 100];
  129. LPSTR p = szzFilter;
  130. WINE_TRACE("()\n");
  131. LoadStringA(Globals.hInstance, STID_HELP_FILES_HLP, p, MAX_STRING_LEN);
  132. p += strlen(p) + 1;
  133. strcpy(p, "*.hlp");
  134. p += strlen(p) + 1;
  135. LoadStringA(Globals.hInstance, STID_ALL_FILES, p, MAX_STRING_LEN);
  136. p += strlen(p) + 1;
  137. strcpy(p, "*.*");
  138. p += strlen(p) + 1;
  139. *p = '\0';
  140. GetCurrentDirectoryA(sizeof(szDir), szDir);
  141. lpszFile[0]='\0';
  142. openfilename.lStructSize = sizeof(openfilename);
  143. openfilename.hwndOwner = (Globals.active_win ? Globals.active_win->hMainWnd : 0);
  144. openfilename.hInstance = Globals.hInstance;
  145. openfilename.lpstrFilter = szzFilter;
  146. openfilename.lpstrCustomFilter = 0;
  147. openfilename.nMaxCustFilter = 0;
  148. openfilename.nFilterIndex = 1;
  149. openfilename.lpstrFile = lpszFile;
  150. openfilename.nMaxFile = len;
  151. openfilename.lpstrFileTitle = 0;
  152. openfilename.nMaxFileTitle = 0;
  153. openfilename.lpstrInitialDir = szDir;
  154. openfilename.lpstrTitle = 0;
  155. openfilename.Flags = OFN_ENABLESIZING | OFN_HIDEREADONLY | OFN_READONLY;
  156. openfilename.nFileOffset = 0;
  157. openfilename.nFileExtension = 0;
  158. openfilename.lpstrDefExt = 0;
  159. openfilename.lCustData = 0;
  160. openfilename.lpfnHook = 0;
  161. openfilename.lpTemplateName = 0;
  162. return GetOpenFileNameA(&openfilename);
  163. }
  164. /***********************************************************************
  165. *
  166. * WINHELP_MessageBoxIDS_s
  167. */
  168. static INT WINHELP_MessageBoxIDS_s(UINT ids_text, LPCSTR str, UINT ids_title, WORD type)
  169. {
  170. CHAR text[MAX_STRING_LEN];
  171. CHAR newtext[MAX_STRING_LEN + MAX_PATH];
  172. LoadStringA(Globals.hInstance, ids_text, text, sizeof(text));
  173. wsprintfA(newtext, text, str);
  174. return MessageBoxA(0, newtext, MAKEINTRESOURCEA(ids_title), type);
  175. }
  176. /***********************************************************************
  177. *
  178. * WINHELP_LookupHelpFile
  179. */
  180. HLPFILE* WINHELP_LookupHelpFile(LPCSTR lpszFile)
  181. {
  182. HLPFILE* hlpfile;
  183. char szFullName[MAX_PATH];
  184. char szAddPath[MAX_PATH];
  185. char *p;
  186. /*
  187. * NOTE: This is needed by popup windows only.
  188. * In other cases it's not needed but does not hurt though.
  189. */
  190. if (Globals.active_win && Globals.active_win->page && Globals.active_win->page->file)
  191. {
  192. strcpy(szAddPath, Globals.active_win->page->file->lpszPath);
  193. p = strrchr(szAddPath, '\\');
  194. if (p) *p = 0;
  195. }
  196. /*
  197. * FIXME: Should we swap conditions?
  198. */
  199. if (!SearchPathA(NULL, lpszFile, ".hlp", MAX_PATH, szFullName, NULL) &&
  200. !SearchPathA(szAddPath, lpszFile, ".hlp", MAX_PATH, szFullName, NULL))
  201. {
  202. if (WINHELP_MessageBoxIDS_s(STID_FILE_NOT_FOUND_s, lpszFile, STID_WHERROR,
  203. MB_YESNO|MB_ICONQUESTION) != IDYES)
  204. return NULL;
  205. if (!WINHELP_GetOpenFileName(szFullName, MAX_PATH))
  206. return NULL;
  207. }
  208. hlpfile = HLPFILE_ReadHlpFile(szFullName);
  209. if (!hlpfile)
  210. WINHELP_MessageBoxIDS_s(STID_HLPFILE_ERROR_s, lpszFile,
  211. STID_WHERROR, MB_OK|MB_ICONSTOP);
  212. return hlpfile;
  213. }
  214. /******************************************************************
  215. * WINHELP_GetWindowInfo
  216. *
  217. *
  218. */
  219. HLPFILE_WINDOWINFO* WINHELP_GetWindowInfo(HLPFILE* hlpfile, LPCSTR name)
  220. {
  221. static HLPFILE_WINDOWINFO mwi;
  222. unsigned int i;
  223. if (!name || !name[0])
  224. name = Globals.active_win->info->name;
  225. if (hlpfile)
  226. for (i = 0; i < hlpfile->numWindows; i++)
  227. if (!lstrcmpiA(hlpfile->windows[i].name, name))
  228. return &hlpfile->windows[i];
  229. if (strcmp(name, "main") != 0)
  230. {
  231. WINE_FIXME("Couldn't find window info for %s\n", debugstr_a(name));
  232. assert(0);
  233. return NULL;
  234. }
  235. if (!mwi.name[0])
  236. {
  237. strcpy(mwi.type, "primary");
  238. strcpy(mwi.name, "main");
  239. if (hlpfile && hlpfile->lpszTitle[0])
  240. {
  241. char tmp[40];
  242. LoadStringA(Globals.hInstance, STID_WINE_HELP, tmp, sizeof(tmp));
  243. _snprintf(mwi.caption, sizeof(mwi.caption), "%s %s - %s",
  244. hlpfile->lpszTitle, tmp, hlpfile->lpszPath);
  245. }
  246. else
  247. LoadStringA(Globals.hInstance, STID_WINE_HELP, mwi.caption, sizeof(mwi.caption));
  248. mwi.origin.x = mwi.origin.y = mwi.size.cx = mwi.size.cy = CW_USEDEFAULT;
  249. mwi.style = SW_SHOW;
  250. mwi.win_style = WS_OVERLAPPEDWINDOW;
  251. mwi.sr_color = mwi.nsr_color = 0xFFFFFF;
  252. }
  253. return &mwi;
  254. }
  255. /******************************************************************
  256. * HLPFILE_GetPopupWindowInfo
  257. *
  258. *
  259. */
  260. static HLPFILE_WINDOWINFO* WINHELP_GetPopupWindowInfo(HLPFILE* hlpfile,
  261. WINHELP_WINDOW* parent, LPARAM mouse)
  262. {
  263. static HLPFILE_WINDOWINFO wi;
  264. RECT parent_rect;
  265. wi.type[0] = wi.name[0] = wi.caption[0] = '\0';
  266. /* Calculate horizontal size and position of a popup window */
  267. GetWindowRect(parent->hMainWnd, &parent_rect);
  268. wi.size.cx = (parent_rect.right - parent_rect.left) / 2;
  269. wi.size.cy = 10; /* need a non null value, so that borders are taken into account while computing */
  270. wi.origin.x = (short)LOWORD(mouse);
  271. wi.origin.y = (short)HIWORD(mouse);
  272. ClientToScreen(parent->hMainWnd, &wi.origin);
  273. wi.origin.x -= wi.size.cx / 2;
  274. wi.origin.x = min(wi.origin.x, GetSystemMetrics(SM_CXSCREEN) - wi.size.cx);
  275. wi.origin.x = max(wi.origin.x, 0);
  276. wi.style = SW_SHOW;
  277. wi.win_style = WS_POPUP | WS_BORDER;
  278. if (parent->page->file->has_popup_color)
  279. wi.sr_color = parent->page->file->popup_color;
  280. else
  281. wi.sr_color = parent->info->sr_color;
  282. wi.nsr_color = 0xFFFFFF;
  283. return &wi;
  284. }
  285. typedef struct
  286. {
  287. WORD size;
  288. WORD command;
  289. LONG data;
  290. LONG reserved;
  291. WORD ofsFilename;
  292. WORD ofsData;
  293. } WINHELP,*LPWINHELP;
  294. static BOOL WINHELP_HasWorkingWindow(void)
  295. {
  296. if (!Globals.active_win) return FALSE;
  297. if (Globals.active_win->next || Globals.win_list != Globals.active_win) return TRUE;
  298. return Globals.active_win->page != NULL && Globals.active_win->page->file != NULL;
  299. }
  300. /******************************************************************
  301. * WINHELP_HandleCommand
  302. *
  303. *
  304. */
  305. static LRESULT WINHELP_HandleCommand(HWND hSrcWnd, LPARAM lParam)
  306. {
  307. COPYDATASTRUCT* cds = (COPYDATASTRUCT*)lParam;
  308. WINHELP* wh;
  309. if (cds->dwData != 0xA1DE505)
  310. {
  311. WINE_FIXME("Wrong magic number (%08Ix)\n", cds->dwData);
  312. return 0;
  313. }
  314. wh = cds->lpData;
  315. if (wh)
  316. {
  317. char* ptr = (wh->ofsFilename) ? (LPSTR)wh + wh->ofsFilename : NULL;
  318. WINE_TRACE("Got[%u]: cmd=%u data=%08lx fn=%s\n",
  319. wh->size, wh->command, wh->data, debugstr_a(ptr));
  320. switch (wh->command)
  321. {
  322. case HELP_CONTEXT:
  323. if (ptr)
  324. {
  325. MACRO_JumpContext(ptr, "main", wh->data);
  326. }
  327. if (!WINHELP_HasWorkingWindow()) MACRO_Exit();
  328. break;
  329. case HELP_QUIT:
  330. MACRO_Exit();
  331. break;
  332. case HELP_CONTENTS:
  333. if (ptr)
  334. {
  335. MACRO_JumpContents(ptr, "main");
  336. }
  337. if (!WINHELP_HasWorkingWindow()) MACRO_Exit();
  338. break;
  339. case HELP_HELPONHELP:
  340. MACRO_HelpOn();
  341. if (!WINHELP_HasWorkingWindow()) MACRO_Exit();
  342. break;
  343. /* case HELP_SETINDEX: */
  344. case HELP_SETCONTENTS:
  345. if (ptr)
  346. {
  347. MACRO_SetContents(ptr, wh->data);
  348. }
  349. break;
  350. case HELP_CONTEXTPOPUP:
  351. if (ptr)
  352. {
  353. MACRO_PopupContext(ptr, wh->data);
  354. }
  355. break;
  356. /* case HELP_FORCEFILE:*/
  357. /* case HELP_CONTEXTMENU: */
  358. case HELP_FINDER:
  359. /* in fact, should be the topic dialog box */
  360. WINE_FIXME("HELP_FINDER: stub\n");
  361. if (ptr)
  362. {
  363. MACRO_JumpHash(ptr, "main", 0);
  364. }
  365. break;
  366. /* case HELP_WM_HELP: */
  367. /* case HELP_SETPOPUP_POS: */
  368. /* case HELP_KEY: */
  369. /* case HELP_COMMAND: */
  370. /* case HELP_PARTIALKEY: */
  371. /* case HELP_MULTIKEY: */
  372. /* case HELP_SETWINPOS: */
  373. default:
  374. WINE_FIXME("Unhandled command (%x) for remote winhelp control\n", wh->command);
  375. break;
  376. }
  377. }
  378. /* Always return success for now */
  379. return 1;
  380. }
  381. void WINHELP_LayoutMainWindow(WINHELP_WINDOW* win)
  382. {
  383. RECT rect, button_box_rect;
  384. INT text_top = 0;
  385. HWND hButtonBoxWnd = GetDlgItem(win->hMainWnd, CTL_ID_BUTTON);
  386. HWND hTextWnd = GetDlgItem(win->hMainWnd, CTL_ID_TEXT);
  387. GetClientRect(win->hMainWnd, &rect);
  388. /* Update button box and text Window */
  389. SetWindowPos(hButtonBoxWnd, HWND_TOP,
  390. rect.left, rect.top,
  391. rect.right - rect.left,
  392. rect.bottom - rect.top, 0);
  393. if (GetWindowRect(hButtonBoxWnd, &button_box_rect))
  394. text_top = rect.top + button_box_rect.bottom - button_box_rect.top;
  395. SetWindowPos(hTextWnd, HWND_TOP,
  396. rect.left, text_top,
  397. rect.right - rect.left,
  398. rect.bottom - text_top, 0);
  399. }
  400. /******************************************************************
  401. * WINHELP_DeleteButtons
  402. *
  403. */
  404. static void WINHELP_DeleteButtons(WINHELP_WINDOW* win)
  405. {
  406. WINHELP_BUTTON* b;
  407. WINHELP_BUTTON* bp;
  408. for (b = win->first_button; b; b = bp)
  409. {
  410. DestroyWindow(b->hWnd);
  411. bp = b->next;
  412. HeapFree(GetProcessHeap(), 0, b);
  413. }
  414. win->first_button = NULL;
  415. }
  416. /******************************************************************
  417. * WINHELP_DeleteBackSet
  418. *
  419. */
  420. void WINHELP_DeleteBackSet(WINHELP_WINDOW* win)
  421. {
  422. unsigned int i;
  423. for (i = 0; i < win->back.index; i++)
  424. {
  425. HLPFILE_FreeHlpFile(win->back.set[i].page->file);
  426. win->back.set[i].page = NULL;
  427. }
  428. win->back.index = 0;
  429. }
  430. /******************************************************************
  431. * WINHELP_DeletePageLinks
  432. *
  433. */
  434. static void WINHELP_DeletePageLinks(HLPFILE_PAGE* page)
  435. {
  436. HLPFILE_LINK* curr;
  437. HLPFILE_LINK* next;
  438. for (curr = page->first_link; curr; curr = next)
  439. {
  440. next = curr->next;
  441. HeapFree(GetProcessHeap(), 0, curr);
  442. }
  443. }
  444. /***********************************************************************
  445. *
  446. * WINHELP_GrabWindow
  447. */
  448. WINHELP_WINDOW* WINHELP_GrabWindow(WINHELP_WINDOW* win)
  449. {
  450. WINE_TRACE("Grab %p#%d++\n", win, win->ref_count);
  451. win->ref_count++;
  452. return win;
  453. }
  454. /***********************************************************************
  455. *
  456. * WINHELP_ReleaseWindow
  457. */
  458. BOOL WINHELP_ReleaseWindow(WINHELP_WINDOW* win)
  459. {
  460. WINE_TRACE("Release %p#%d--\n", win, win->ref_count);
  461. if (!--win->ref_count)
  462. {
  463. DestroyWindow(win->hMainWnd);
  464. return FALSE;
  465. }
  466. return TRUE;
  467. }
  468. /***********************************************************************
  469. *
  470. * WINHELP_DeleteWindow
  471. */
  472. static void WINHELP_DeleteWindow(WINHELP_WINDOW* win)
  473. {
  474. WINHELP_WINDOW** w;
  475. BOOL bExit;
  476. HWND hTextWnd;
  477. for (w = &Globals.win_list; *w; w = &(*w)->next)
  478. {
  479. if (*w == win)
  480. {
  481. *w = win->next;
  482. break;
  483. }
  484. }
  485. bExit = (Globals.wVersion >= 4 && !lstrcmpiA(win->info->name, "main"));
  486. if (Globals.active_win == win)
  487. {
  488. Globals.active_win = Globals.win_list;
  489. if (Globals.win_list)
  490. SetActiveWindow(Globals.win_list->hMainWnd);
  491. }
  492. if (win == Globals.active_popup)
  493. Globals.active_popup = NULL;
  494. hTextWnd = GetDlgItem(win->hMainWnd, CTL_ID_TEXT);
  495. SetWindowLongPtrA(hTextWnd, GWLP_WNDPROC, (LONG_PTR)win->origRicheditWndProc);
  496. WINHELP_DeleteButtons(win);
  497. if (win->page) WINHELP_DeletePageLinks(win->page);
  498. if (win->hHistoryWnd) DestroyWindow(win->hHistoryWnd);
  499. DeleteObject(win->hBrush);
  500. WINHELP_DeleteBackSet(win);
  501. if (win->page) HLPFILE_FreeHlpFile(win->page->file);
  502. HeapFree(GetProcessHeap(), 0, win);
  503. if (bExit) MACRO_Exit();
  504. if (!Globals.win_list)
  505. PostQuitMessage(0);
  506. }
  507. static char* WINHELP_GetCaption(WINHELP_WNDPAGE* wpage)
  508. {
  509. if (wpage->wininfo->caption[0]) return wpage->wininfo->caption;
  510. return wpage->page->file->lpszTitle;
  511. }
  512. static void WINHELP_RememberPage(WINHELP_WINDOW* win, WINHELP_WNDPAGE* wpage)
  513. {
  514. unsigned num;
  515. if (!Globals.history.index || Globals.history.set[0].page != wpage->page)
  516. {
  517. num = ARRAY_SIZE(Globals.history.set);
  518. /* we're full, remove latest entry */
  519. if (Globals.history.index == num)
  520. {
  521. HLPFILE_FreeHlpFile(Globals.history.set[num - 1].page->file);
  522. Globals.history.index--;
  523. }
  524. memmove(&Globals.history.set[1], &Globals.history.set[0],
  525. Globals.history.index * sizeof(Globals.history.set[0]));
  526. Globals.history.set[0] = *wpage;
  527. Globals.history.index++;
  528. wpage->page->file->wRefCount++;
  529. }
  530. if (win->hHistoryWnd) InvalidateRect(win->hHistoryWnd, NULL, TRUE);
  531. num = ARRAY_SIZE(win->back.set);
  532. if (win->back.index == num)
  533. {
  534. /* we're full, remove latest entry */
  535. HLPFILE_FreeHlpFile(win->back.set[0].page->file);
  536. memmove(&win->back.set[0], &win->back.set[1],
  537. (num - 1) * sizeof(win->back.set[0]));
  538. win->back.index--;
  539. }
  540. win->back.set[win->back.index++] = *wpage;
  541. wpage->page->file->wRefCount++;
  542. }
  543. /***********************************************************************
  544. *
  545. * WINHELP_FindLink
  546. */
  547. static HLPFILE_LINK* WINHELP_FindLink(WINHELP_WINDOW* win, LPARAM pos)
  548. {
  549. HLPFILE_LINK* link;
  550. POINTL mouse_ptl, char_ptl, char_next_ptl;
  551. DWORD cp;
  552. if (!win->page) return NULL;
  553. mouse_ptl.x = (short)LOWORD(pos);
  554. mouse_ptl.y = (short)HIWORD(pos);
  555. cp = SendMessageW(GetDlgItem(win->hMainWnd, CTL_ID_TEXT), EM_CHARFROMPOS,
  556. 0, (LPARAM)&mouse_ptl);
  557. for (link = win->page->first_link; link; link = link->next)
  558. {
  559. if (link->cpMin <= cp && cp <= link->cpMax)
  560. {
  561. /* check whether we're at end of line */
  562. SendMessageW(GetDlgItem(win->hMainWnd, CTL_ID_TEXT), EM_POSFROMCHAR,
  563. (LPARAM)&char_ptl, cp);
  564. SendMessageW(GetDlgItem(win->hMainWnd, CTL_ID_TEXT), EM_POSFROMCHAR,
  565. (LPARAM)&char_next_ptl, cp + 1);
  566. if (link->bHotSpot)
  567. {
  568. HLPFILE_HOTSPOTLINK* hslink = (HLPFILE_HOTSPOTLINK*)link;
  569. if ((mouse_ptl.x < char_ptl.x + hslink->x) ||
  570. (mouse_ptl.x >= char_ptl.x + hslink->x + hslink->width) ||
  571. (mouse_ptl.y < char_ptl.y + hslink->y) ||
  572. (mouse_ptl.y >= char_ptl.y + hslink->y + hslink->height))
  573. continue;
  574. break;
  575. }
  576. if (char_next_ptl.y != char_ptl.y || mouse_ptl.x >= char_next_ptl.x)
  577. link = NULL;
  578. break;
  579. }
  580. }
  581. return link;
  582. }
  583. static LRESULT CALLBACK WINHELP_RicheditWndProc(HWND hWnd, UINT msg,
  584. WPARAM wParam, LPARAM lParam)
  585. {
  586. WINHELP_WINDOW *win = (WINHELP_WINDOW*) GetWindowLongPtrW(GetParent(hWnd), 0);
  587. DWORD messagePos;
  588. POINT pt;
  589. switch(msg)
  590. {
  591. case WM_SETCURSOR:
  592. messagePos = GetMessagePos();
  593. pt.x = (short)LOWORD(messagePos);
  594. pt.y = (short)HIWORD(messagePos);
  595. ScreenToClient(hWnd, &pt);
  596. if (win->page && WINHELP_FindLink(win, MAKELPARAM(pt.x, pt.y)))
  597. {
  598. SetCursor(win->hHandCur);
  599. return 0;
  600. }
  601. /* fall through */
  602. default:
  603. return CallWindowProcA(win->origRicheditWndProc, hWnd, msg, wParam, lParam);
  604. }
  605. }
  606. /***********************************************************************
  607. *
  608. * WINHELP_CreateHelpWindow
  609. */
  610. BOOL WINHELP_CreateHelpWindow(WINHELP_WNDPAGE* wpage, int nCmdShow, BOOL remember)
  611. {
  612. WINHELP_WINDOW* win = NULL;
  613. BOOL bPrimary, bPopup, bReUsed = FALSE;
  614. HICON hIcon;
  615. HWND hTextWnd = NULL;
  616. bPrimary = !lstrcmpiA(wpage->wininfo->name, "main");
  617. bPopup = !bPrimary && (wpage->wininfo->win_style & WS_POPUP);
  618. if (!bPopup)
  619. {
  620. for (win = Globals.win_list; win; win = win->next)
  621. {
  622. if (!lstrcmpiA(win->info->name, wpage->wininfo->name))
  623. {
  624. if (win->page == wpage->page && win->info == wpage->wininfo)
  625. {
  626. /* see #22979, some hlp files have a macro (run at page opening), which
  627. * jumps to the very same page
  628. * Exit gracefully in that case
  629. */
  630. return TRUE;
  631. }
  632. WINHELP_DeleteButtons(win);
  633. bReUsed = TRUE;
  634. SetWindowTextA(win->hMainWnd, WINHELP_GetCaption(wpage));
  635. if (win->info != wpage->wininfo)
  636. {
  637. POINT pt = {0, 0};
  638. SIZE sz = {0, 0};
  639. DWORD flags = SWP_NOSIZE | SWP_NOMOVE;
  640. if (wpage->wininfo->origin.x != CW_USEDEFAULT &&
  641. wpage->wininfo->origin.y != CW_USEDEFAULT)
  642. {
  643. pt = wpage->wininfo->origin;
  644. flags &= ~SWP_NOSIZE;
  645. }
  646. if (wpage->wininfo->size.cx != CW_USEDEFAULT &&
  647. wpage->wininfo->size.cy != CW_USEDEFAULT)
  648. {
  649. sz = wpage->wininfo->size;
  650. flags &= ~SWP_NOMOVE;
  651. }
  652. SetWindowPos(win->hMainWnd, HWND_TOP, pt.x, pt.y, sz.cx, sz.cy, flags);
  653. }
  654. if (wpage->page && win->page && wpage->page->file != win->page->file)
  655. WINHELP_DeleteBackSet(win);
  656. WINHELP_InitFonts(win->hMainWnd);
  657. win->page = wpage->page;
  658. win->info = wpage->wininfo;
  659. hTextWnd = GetDlgItem(win->hMainWnd, CTL_ID_TEXT);
  660. WINHELP_SetupText(hTextWnd, win, wpage->relative);
  661. InvalidateRect(win->hMainWnd, NULL, TRUE);
  662. if (win->hHistoryWnd) InvalidateRect(win->hHistoryWnd, NULL, TRUE);
  663. break;
  664. }
  665. }
  666. }
  667. if (!win)
  668. {
  669. /* Initialize WINHELP_WINDOW struct */
  670. win = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WINHELP_WINDOW));
  671. if (!win) return FALSE;
  672. win->next = Globals.win_list;
  673. Globals.win_list = win;
  674. win->hHandCur = LoadCursorW(0, (LPWSTR)IDC_HAND);
  675. win->back.index = 0;
  676. win->font_scale = 1;
  677. WINHELP_GrabWindow(win);
  678. }
  679. win->page = wpage->page;
  680. win->info = wpage->wininfo;
  681. WINHELP_GrabWindow(win);
  682. if (!bPopup && wpage->page && remember)
  683. {
  684. WINHELP_RememberPage(win, wpage);
  685. }
  686. if (bPopup)
  687. Globals.active_popup = win;
  688. else
  689. Globals.active_win = win;
  690. /* Initialize default pushbuttons */
  691. if (bPrimary && wpage->page)
  692. {
  693. CHAR buffer[MAX_STRING_LEN];
  694. LoadStringA(Globals.hInstance, STID_CONTENTS, buffer, sizeof(buffer));
  695. MACRO_CreateButton("BTN_CONTENTS", buffer, "Contents()");
  696. LoadStringA(Globals.hInstance, STID_INDEX, buffer, sizeof(buffer));
  697. MACRO_CreateButton("BTN_INDEX", buffer, "Finder()");
  698. LoadStringA(Globals.hInstance, STID_BACK, buffer, sizeof(buffer));
  699. MACRO_CreateButton("BTN_BACK", buffer, "Back()");
  700. if (win->back.index <= 1) MACRO_DisableButton("BTN_BACK");
  701. }
  702. if (!bReUsed)
  703. {
  704. win->hMainWnd = CreateWindowExA((bPopup) ? WS_EX_TOOLWINDOW : 0, MAIN_WIN_CLASS_NAME,
  705. WINHELP_GetCaption(wpage),
  706. bPrimary ? WS_OVERLAPPEDWINDOW : wpage->wininfo->win_style,
  707. wpage->wininfo->origin.x, wpage->wininfo->origin.y,
  708. wpage->wininfo->size.cx, wpage->wininfo->size.cy,
  709. bPopup ? Globals.active_win->hMainWnd : NULL,
  710. bPrimary ? LoadMenuW(Globals.hInstance, MAKEINTRESOURCEW(MAIN_MENU)) : 0,
  711. Globals.hInstance, win);
  712. if (!bPopup)
  713. /* Create button box and text Window */
  714. CreateWindowA(BUTTON_BOX_WIN_CLASS_NAME, "", WS_CHILD | WS_VISIBLE,
  715. 0, 0, 0, 0, win->hMainWnd, (HMENU)CTL_ID_BUTTON, Globals.hInstance, NULL);
  716. hTextWnd = CreateWindowA(RICHEDIT_CLASS20A, NULL,
  717. ES_MULTILINE | ES_READONLY | WS_CHILD | WS_HSCROLL | WS_VSCROLL | WS_VISIBLE,
  718. 0, 0, 0, 0, win->hMainWnd, (HMENU)CTL_ID_TEXT, Globals.hInstance, NULL);
  719. SendMessageW(hTextWnd, EM_SETEVENTMASK, 0,
  720. SendMessageW(hTextWnd, EM_GETEVENTMASK, 0, 0) | ENM_MOUSEEVENTS);
  721. win->origRicheditWndProc = (WNDPROC)SetWindowLongPtrA(hTextWnd, GWLP_WNDPROC,
  722. (LONG_PTR)WINHELP_RicheditWndProc);
  723. }
  724. hIcon = (wpage->page) ? wpage->page->file->hIcon : NULL;
  725. if (!hIcon) hIcon = LoadImageW(Globals.hInstance, MAKEINTRESOURCEW(IDI_WINHELP), IMAGE_ICON,
  726. GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_SHARED);
  727. SendMessageW(win->hMainWnd, WM_SETICON, ICON_SMALL, (DWORD_PTR)hIcon);
  728. /* Initialize file specific pushbuttons */
  729. if (!(wpage->wininfo->win_style & WS_POPUP) && wpage->page)
  730. {
  731. HLPFILE_MACRO *macro;
  732. for (macro = wpage->page->file->first_macro; macro; macro = macro->next)
  733. MACRO_ExecuteMacro(win, macro->lpszMacro);
  734. for (macro = wpage->page->first_macro; macro; macro = macro->next)
  735. MACRO_ExecuteMacro(win, macro->lpszMacro);
  736. }
  737. /* See #17681, in some cases, the newly created window is closed by the macros it contains
  738. * (braindead), so deal with this case
  739. */
  740. for (win = Globals.win_list; win; win = win->next)
  741. {
  742. if (!lstrcmpiA(win->info->name, wpage->wininfo->name)) break;
  743. }
  744. if (!win || !WINHELP_ReleaseWindow(win)) return TRUE;
  745. if (bPopup)
  746. {
  747. DWORD mask = SendMessageW(hTextWnd, EM_GETEVENTMASK, 0, 0);
  748. win->font_scale = Globals.active_win->font_scale;
  749. WINHELP_SetupText(hTextWnd, win, wpage->relative);
  750. /* we need the window to be shown for richedit to compute the size */
  751. ShowWindow(win->hMainWnd, nCmdShow);
  752. SendMessageW(hTextWnd, EM_SETEVENTMASK, 0, mask | ENM_REQUESTRESIZE);
  753. SendMessageW(hTextWnd, EM_REQUESTRESIZE, 0, 0);
  754. SendMessageW(hTextWnd, EM_SETEVENTMASK, 0, mask);
  755. }
  756. else
  757. {
  758. WINHELP_SetupText(hTextWnd, win, wpage->relative);
  759. WINHELP_LayoutMainWindow(win);
  760. ShowWindow(win->hMainWnd, nCmdShow);
  761. }
  762. return TRUE;
  763. }
  764. /******************************************************************
  765. * WINHELP_OpenHelpWindow
  766. * Main function to search for a page and display it in a window
  767. */
  768. BOOL WINHELP_OpenHelpWindow(HLPFILE_PAGE* (*lookup)(HLPFILE*, LONG, ULONG*),
  769. HLPFILE* hlpfile, LONG val, HLPFILE_WINDOWINFO* wi,
  770. int nCmdShow)
  771. {
  772. WINHELP_WNDPAGE wpage;
  773. wpage.page = lookup(hlpfile, val, &wpage.relative);
  774. if (wpage.page) wpage.page->file->wRefCount++;
  775. wpage.wininfo = wi;
  776. return WINHELP_CreateHelpWindow(&wpage, nCmdShow, TRUE);
  777. }
  778. /******************************************************************
  779. * WINHELP_HandleTextMouse
  780. *
  781. */
  782. static BOOL WINHELP_HandleTextMouse(WINHELP_WINDOW* win, UINT msg, LPARAM lParam)
  783. {
  784. HLPFILE* hlpfile;
  785. HLPFILE_LINK* link;
  786. BOOL ret = FALSE;
  787. switch (msg)
  788. {
  789. case WM_LBUTTONDOWN:
  790. if ((link = WINHELP_FindLink(win, lParam)))
  791. {
  792. HLPFILE_WINDOWINFO* wi;
  793. switch (link->cookie)
  794. {
  795. case hlp_link_link:
  796. if ((hlpfile = WINHELP_LookupHelpFile(link->string)))
  797. {
  798. if (link->window == -1)
  799. {
  800. wi = win->info;
  801. if (wi->win_style & WS_POPUP) wi = Globals.active_win->info;
  802. }
  803. else if (link->window < hlpfile->numWindows)
  804. wi = &hlpfile->windows[link->window];
  805. else
  806. {
  807. WINE_WARN("link to window %d/%d\n", link->window, hlpfile->numWindows);
  808. break;
  809. }
  810. WINHELP_OpenHelpWindow(HLPFILE_PageByHash, hlpfile, link->hash, wi, SW_NORMAL);
  811. }
  812. break;
  813. case hlp_link_popup:
  814. if ((hlpfile = WINHELP_LookupHelpFile(link->string)))
  815. WINHELP_OpenHelpWindow(HLPFILE_PageByHash, hlpfile, link->hash,
  816. WINHELP_GetPopupWindowInfo(hlpfile, win, lParam),
  817. SW_NORMAL);
  818. break;
  819. case hlp_link_macro:
  820. MACRO_ExecuteMacro(win, link->string);
  821. break;
  822. default:
  823. WINE_FIXME("Unknown link cookie %d\n", link->cookie);
  824. }
  825. ret = TRUE;
  826. }
  827. break;
  828. }
  829. return ret;
  830. }
  831. /***********************************************************************
  832. *
  833. * WINHELP_CheckPopup
  834. */
  835. static BOOL WINHELP_CheckPopup(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, LRESULT* lret)
  836. {
  837. WINHELP_WINDOW* popup;
  838. if (!Globals.active_popup) return FALSE;
  839. switch (msg)
  840. {
  841. case WM_NOTIFY:
  842. {
  843. MSGFILTER* msgf = (MSGFILTER*)lParam;
  844. if (msgf->nmhdr.code == EN_MSGFILTER)
  845. {
  846. if (!WINHELP_CheckPopup(hWnd, msgf->msg, msgf->wParam, msgf->lParam, NULL))
  847. return FALSE;
  848. if (lret) *lret = 1;
  849. return TRUE;
  850. }
  851. }
  852. break;
  853. case WM_ACTIVATE:
  854. if (LOWORD(wParam) != WA_INACTIVE || (HWND)lParam == Globals.active_win->hMainWnd ||
  855. (HWND)lParam == Globals.active_popup->hMainWnd ||
  856. GetWindow((HWND)lParam, GW_OWNER) == Globals.active_win->hMainWnd)
  857. break;
  858. /* fall through */
  859. case WM_LBUTTONDOWN:
  860. if (msg == WM_LBUTTONDOWN)
  861. WINHELP_HandleTextMouse(Globals.active_popup, msg, lParam);
  862. /* fall through */
  863. case WM_MBUTTONDOWN:
  864. case WM_RBUTTONDOWN:
  865. case WM_NCLBUTTONDOWN:
  866. case WM_NCMBUTTONDOWN:
  867. case WM_NCRBUTTONDOWN:
  868. popup = Globals.active_popup;
  869. Globals.active_popup = NULL;
  870. WINHELP_ReleaseWindow(popup);
  871. if (lret) *lret = 1;
  872. return TRUE;
  873. }
  874. return FALSE;
  875. }
  876. /***********************************************************************
  877. *
  878. * WINHELP_ButtonWndProc
  879. */
  880. static LRESULT CALLBACK WINHELP_ButtonWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
  881. {
  882. if (WINHELP_CheckPopup(hWnd, msg, wParam, lParam, NULL)) return 0;
  883. if (msg == WM_KEYDOWN)
  884. {
  885. switch (wParam)
  886. {
  887. case VK_UP:
  888. case VK_DOWN:
  889. case VK_PRIOR:
  890. case VK_NEXT:
  891. case VK_ESCAPE:
  892. return SendMessageA(GetParent(hWnd), msg, wParam, lParam);
  893. }
  894. }
  895. return CallWindowProcA(Globals.button_proc, hWnd, msg, wParam, lParam);
  896. }
  897. /***********************************************************************
  898. *
  899. * WINHELP_ButtonBoxWndProc
  900. */
  901. static LRESULT CALLBACK WINHELP_ButtonBoxWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
  902. {
  903. WINDOWPOS *winpos;
  904. WINHELP_WINDOW *win;
  905. WINHELP_BUTTON *button;
  906. SIZE button_size;
  907. INT x, y;
  908. if (WINHELP_CheckPopup(hWnd, msg, wParam, lParam, NULL)) return 0L;
  909. switch (msg)
  910. {
  911. case WM_WINDOWPOSCHANGING:
  912. winpos = (WINDOWPOS*) lParam;
  913. win = (WINHELP_WINDOW*) GetWindowLongPtrW(GetParent(hWnd), 0);
  914. /* Update buttons */
  915. button_size.cx = 0;
  916. button_size.cy = 0;
  917. for (button = win->first_button; button; button = button->next)
  918. {
  919. HDC hDc;
  920. SIZE textsize;
  921. if (!button->hWnd)
  922. {
  923. button->hWnd = CreateWindowA(STRING_BUTTON, button->lpszName,
  924. WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
  925. 0, 0, 0, 0,
  926. hWnd, (HMENU) button->wParam,
  927. Globals.hInstance, 0);
  928. if (button->hWnd)
  929. {
  930. if (Globals.button_proc == NULL)
  931. {
  932. NONCLIENTMETRICSW ncm;
  933. Globals.button_proc = (WNDPROC) GetWindowLongPtrA(button->hWnd, GWLP_WNDPROC);
  934. ncm.cbSize = sizeof(NONCLIENTMETRICSW);
  935. SystemParametersInfoW(SPI_GETNONCLIENTMETRICS,
  936. sizeof(NONCLIENTMETRICSW), &ncm, 0);
  937. Globals.hButtonFont = CreateFontIndirectW(&ncm.lfMenuFont);
  938. }
  939. SetWindowLongPtrA(button->hWnd, GWLP_WNDPROC, (LONG_PTR) WINHELP_ButtonWndProc);
  940. if (Globals.hButtonFont)
  941. SendMessageW(button->hWnd, WM_SETFONT, (WPARAM)Globals.hButtonFont, TRUE);
  942. }
  943. }
  944. hDc = GetDC(button->hWnd);
  945. GetTextExtentPointA(hDc, button->lpszName, strlen(button->lpszName), &textsize);
  946. ReleaseDC(button->hWnd, hDc);
  947. button_size.cx = max(button_size.cx, textsize.cx + BUTTON_CX);
  948. button_size.cy = max(button_size.cy, textsize.cy + BUTTON_CY);
  949. }
  950. x = 0;
  951. y = 0;
  952. for (button = win->first_button; button; button = button->next)
  953. {
  954. SetWindowPos(button->hWnd, HWND_TOP, x, y, button_size.cx, button_size.cy, 0);
  955. if (x + 2 * button_size.cx <= winpos->cx)
  956. x += button_size.cx;
  957. else
  958. x = 0, y += button_size.cy;
  959. }
  960. winpos->cy = y + (x ? button_size.cy : 0);
  961. break;
  962. case WM_COMMAND:
  963. SendMessageW(GetParent(hWnd), msg, wParam, lParam);
  964. break;
  965. case WM_KEYDOWN:
  966. switch (wParam)
  967. {
  968. case VK_UP:
  969. case VK_DOWN:
  970. case VK_PRIOR:
  971. case VK_NEXT:
  972. case VK_ESCAPE:
  973. return SendMessageA(GetParent(hWnd), msg, wParam, lParam);
  974. }
  975. break;
  976. }
  977. return DefWindowProcA(hWnd, msg, wParam, lParam);
  978. }
  979. /******************************************************************
  980. * WINHELP_HistoryWndProc
  981. *
  982. *
  983. */
  984. static LRESULT CALLBACK WINHELP_HistoryWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
  985. {
  986. WINHELP_WINDOW* win;
  987. PAINTSTRUCT ps;
  988. HDC hDc;
  989. TEXTMETRICW tm;
  990. unsigned int i;
  991. RECT r;
  992. switch (msg)
  993. {
  994. case WM_NCCREATE:
  995. win = (WINHELP_WINDOW*)((LPCREATESTRUCTA)lParam)->lpCreateParams;
  996. SetWindowLongPtrW(hWnd, 0, (ULONG_PTR)win);
  997. win->hHistoryWnd = hWnd;
  998. break;
  999. case WM_CREATE:
  1000. hDc = GetDC(hWnd);
  1001. GetTextMetricsW(hDc, &tm);
  1002. GetWindowRect(hWnd, &r);
  1003. r.right = r.left + 30 * tm.tmAveCharWidth;
  1004. r.bottom = r.top + ARRAY_SIZE(Globals.history.set) * tm.tmHeight;
  1005. AdjustWindowRect(&r, GetWindowLongW(hWnd, GWL_STYLE), FALSE);
  1006. if (r.left < 0) {r.right -= r.left; r.left = 0;}
  1007. if (r.top < 0) {r.bottom -= r.top; r.top = 0;}
  1008. MoveWindow(hWnd, r.left, r.top, r.right, r.bottom, TRUE);
  1009. ReleaseDC(hWnd, hDc);
  1010. break;
  1011. case WM_LBUTTONDOWN:
  1012. hDc = GetDC(hWnd);
  1013. GetTextMetricsW(hDc, &tm);
  1014. i = HIWORD(lParam) / tm.tmHeight;
  1015. if (i < Globals.history.index)
  1016. WINHELP_CreateHelpWindow(&Globals.history.set[i], SW_SHOW, TRUE);
  1017. ReleaseDC(hWnd, hDc);
  1018. break;
  1019. case WM_PAINT:
  1020. hDc = BeginPaint(hWnd, &ps);
  1021. GetTextMetricsW(hDc, &tm);
  1022. for (i = 0; i < Globals.history.index; i++)
  1023. {
  1024. if (Globals.history.set[i].page->file == Globals.active_win->page->file)
  1025. {
  1026. TextOutA(hDc, 0, i * tm.tmHeight,
  1027. Globals.history.set[i].page->lpszTitle,
  1028. strlen(Globals.history.set[i].page->lpszTitle));
  1029. }
  1030. else
  1031. {
  1032. char buffer[1024];
  1033. const char* ptr1;
  1034. const char* ptr2;
  1035. unsigned len;
  1036. ptr1 = strrchr(Globals.history.set[i].page->file->lpszPath, '\\');
  1037. if (!ptr1) ptr1 = Globals.history.set[i].page->file->lpszPath;
  1038. else ptr1++;
  1039. ptr2 = strrchr(ptr1, '.');
  1040. len = ptr2 ? ptr2 - ptr1 : strlen(ptr1);
  1041. if (len > sizeof(buffer)) len = sizeof(buffer);
  1042. memcpy(buffer, ptr1, len);
  1043. if (len < sizeof(buffer)) buffer[len++] = ':';
  1044. lstrcpynA(&buffer[len], Globals.history.set[i].page->lpszTitle, sizeof(buffer) - len);
  1045. TextOutA(hDc, 0, i * tm.tmHeight, buffer, strlen(buffer));
  1046. }
  1047. }
  1048. EndPaint(hWnd, &ps);
  1049. break;
  1050. case WM_DESTROY:
  1051. win = (WINHELP_WINDOW*) GetWindowLongPtrW(hWnd, 0);
  1052. if (hWnd == win->hHistoryWnd)
  1053. win->hHistoryWnd = 0;
  1054. break;
  1055. }
  1056. return DefWindowProcA(hWnd, msg, wParam, lParam);
  1057. }
  1058. /**************************************************************************
  1059. * cb_KWBTree
  1060. *
  1061. * HLPFILE_BPTreeCallback enumeration function for '|KWBTREE' internal file.
  1062. *
  1063. */
  1064. static void cb_KWBTree(void *p, void **next, void *cookie)
  1065. {
  1066. HWND hListWnd = cookie;
  1067. int count;
  1068. WINE_TRACE("Adding %s to search list\n", debugstr_a((char *)p));
  1069. SendMessageA(hListWnd, LB_INSERTSTRING, -1, (LPARAM)p);
  1070. count = SendMessageW(hListWnd, LB_GETCOUNT, 0, 0);
  1071. SendMessageW(hListWnd, LB_SETITEMDATA, count-1, (LPARAM)p);
  1072. *next = (char*)p + strlen((char*)p) + 7;
  1073. }
  1074. struct index_data
  1075. {
  1076. HLPFILE* hlpfile;
  1077. BOOL jump;
  1078. ULONG offset;
  1079. };
  1080. /**************************************************************************
  1081. * WINHELP_IndexDlgProc
  1082. *
  1083. */
  1084. static INT_PTR CALLBACK WINHELP_IndexDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
  1085. {
  1086. static struct index_data* id;
  1087. int sel;
  1088. switch (msg)
  1089. {
  1090. case WM_INITDIALOG:
  1091. id = (struct index_data*)((PROPSHEETPAGEA*)lParam)->lParam;
  1092. HLPFILE_BPTreeEnum(id->hlpfile->kwbtree, cb_KWBTree,
  1093. GetDlgItem(hWnd, IDC_INDEXLIST));
  1094. id->jump = FALSE;
  1095. id->offset = 1;
  1096. return TRUE;
  1097. case WM_COMMAND:
  1098. switch (HIWORD(wParam))
  1099. {
  1100. case LBN_DBLCLK:
  1101. if (LOWORD(wParam) == IDC_INDEXLIST)
  1102. SendMessageW(GetParent(hWnd), PSM_PRESSBUTTON, PSBTN_OK, 0);
  1103. break;
  1104. }
  1105. break;
  1106. case WM_NOTIFY:
  1107. switch (((NMHDR*)lParam)->code)
  1108. {
  1109. case PSN_APPLY:
  1110. sel = SendDlgItemMessageW(hWnd, IDC_INDEXLIST, LB_GETCURSEL, 0, 0);
  1111. if (sel != LB_ERR)
  1112. {
  1113. BYTE *p;
  1114. int count;
  1115. p = (BYTE*)SendDlgItemMessageW(hWnd, IDC_INDEXLIST, LB_GETITEMDATA, sel, 0);
  1116. count = *(short*)((char *)p + strlen((char *)p) + 1);
  1117. if (count > 1)
  1118. {
  1119. MessageBoxA(hWnd, "count > 1 not supported yet", "Error", MB_OK | MB_ICONSTOP);
  1120. SetWindowLongPtrW(hWnd, DWLP_MSGRESULT, PSNRET_INVALID);
  1121. return TRUE;
  1122. }
  1123. id->offset = *(ULONG*)((char *)p + strlen((char *)p) + 3);
  1124. id->offset = *(long*)(id->hlpfile->kwdata + id->offset + 9);
  1125. if (id->offset == 0xFFFFFFFF)
  1126. {
  1127. MessageBoxA(hWnd, "macro keywords not supported yet", "Error", MB_OK | MB_ICONSTOP);
  1128. SetWindowLongPtrW(hWnd, DWLP_MSGRESULT, PSNRET_INVALID);
  1129. return TRUE;
  1130. }
  1131. id->jump = TRUE;
  1132. SetWindowLongPtrW(hWnd, DWLP_MSGRESULT, PSNRET_NOERROR);
  1133. }
  1134. return TRUE;
  1135. default:
  1136. return FALSE;
  1137. }
  1138. break;
  1139. default:
  1140. break;
  1141. }
  1142. return FALSE;
  1143. }
  1144. /**************************************************************************
  1145. * WINHELP_SearchDlgProc
  1146. *
  1147. */
  1148. static INT_PTR CALLBACK WINHELP_SearchDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
  1149. {
  1150. switch (msg)
  1151. {
  1152. case WM_INITDIALOG:
  1153. return TRUE;
  1154. case WM_NOTIFY:
  1155. switch (((NMHDR*)lParam)->code)
  1156. {
  1157. case PSN_APPLY:
  1158. SetWindowLongPtrW(hWnd, DWLP_MSGRESULT, PSNRET_NOERROR);
  1159. return TRUE;
  1160. default:
  1161. return FALSE;
  1162. }
  1163. break;
  1164. default:
  1165. break;
  1166. }
  1167. return FALSE;
  1168. }
  1169. /***********************************************************************
  1170. *
  1171. * WINHELP_MainWndProc
  1172. */
  1173. static LRESULT CALLBACK WINHELP_MainWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
  1174. {
  1175. WINHELP_WINDOW *win;
  1176. WINHELP_BUTTON *button;
  1177. HWND hTextWnd;
  1178. LRESULT ret;
  1179. if (WINHELP_CheckPopup(hWnd, msg, wParam, lParam, &ret)) return ret;
  1180. switch (msg)
  1181. {
  1182. case WM_NCCREATE:
  1183. win = (WINHELP_WINDOW*) ((LPCREATESTRUCTA) lParam)->lpCreateParams;
  1184. SetWindowLongPtrW(hWnd, 0, (ULONG_PTR) win);
  1185. if (!win->page && Globals.isBook)
  1186. PostMessageW(hWnd, WM_COMMAND, MNID_FILE_OPEN, 0);
  1187. win->hMainWnd = hWnd;
  1188. break;
  1189. case WM_WINDOWPOSCHANGED:
  1190. WINHELP_LayoutMainWindow((WINHELP_WINDOW*) GetWindowLongPtrW(hWnd, 0));
  1191. break;
  1192. case WM_COMMAND:
  1193. win = (WINHELP_WINDOW*) GetWindowLongPtrW(hWnd, 0);
  1194. switch (LOWORD(wParam))
  1195. {
  1196. /* Menu FILE */
  1197. case MNID_FILE_OPEN: MACRO_FileOpen(); break;
  1198. case MNID_FILE_PRINT: MACRO_Print(); break;
  1199. case MNID_FILE_SETUP: MACRO_PrinterSetup(); break;
  1200. case MNID_FILE_EXIT: MACRO_Exit(); break;
  1201. /* Menu EDIT */
  1202. case MNID_EDIT_COPYDLG:
  1203. SendDlgItemMessageW(hWnd, CTL_ID_TEXT, WM_COPY, 0, 0);
  1204. break;
  1205. case MNID_EDIT_ANNOTATE:MACRO_Annotate(); break;
  1206. /* Menu Bookmark */
  1207. case MNID_BKMK_DEFINE: MACRO_BookmarkDefine(); break;
  1208. /* Menu Help */
  1209. case MNID_HELP_HELPON: MACRO_HelpOn(); break;
  1210. case MNID_HELP_HELPTOP: MACRO_HelpOnTop(); break;
  1211. case MNID_HELP_ABOUT: MACRO_About(); break;
  1212. /* Context help */
  1213. case MNID_CTXT_ANNOTATE:MACRO_Annotate(); break;
  1214. case MNID_CTXT_COPY: MACRO_CopyDialog(); break;
  1215. case MNID_CTXT_PRINT: MACRO_Print(); break;
  1216. case MNID_OPTS_HISTORY: MACRO_History(); break;
  1217. case MNID_OPTS_FONTS_SMALL:
  1218. case MNID_CTXT_FONTS_SMALL:
  1219. win = (WINHELP_WINDOW*) GetWindowLongPtrW(hWnd, 0);
  1220. if (win->font_scale != 0)
  1221. {
  1222. win->font_scale = 0;
  1223. WINHELP_SetupText(GetDlgItem(hWnd, CTL_ID_TEXT), win, 0 /* FIXME */);
  1224. }
  1225. break;
  1226. case MNID_OPTS_FONTS_NORMAL:
  1227. case MNID_CTXT_FONTS_NORMAL:
  1228. win = (WINHELP_WINDOW*) GetWindowLongPtrW(hWnd, 0);
  1229. if (win->font_scale != 1)
  1230. {
  1231. win->font_scale = 1;
  1232. WINHELP_SetupText(GetDlgItem(hWnd, CTL_ID_TEXT), win, 0 /* FIXME */);
  1233. }
  1234. break;
  1235. case MNID_OPTS_FONTS_LARGE:
  1236. case MNID_CTXT_FONTS_LARGE:
  1237. win = (WINHELP_WINDOW*) GetWindowLongPtrW(hWnd, 0);
  1238. if (win->font_scale != 2)
  1239. {
  1240. win->font_scale = 2;
  1241. WINHELP_SetupText(GetDlgItem(hWnd, CTL_ID_TEXT), win, 0 /* FIXME */);
  1242. }
  1243. break;
  1244. default:
  1245. /* Buttons */
  1246. for (button = win->first_button; button; button = button->next)
  1247. if (wParam == button->wParam) break;
  1248. if (button)
  1249. MACRO_ExecuteMacro(win, button->lpszMacro);
  1250. else if (!HIWORD(wParam))
  1251. MessageBoxW(0, MAKEINTRESOURCEW(STID_NOT_IMPLEMENTED),
  1252. MAKEINTRESOURCEW(STID_WHERROR), MB_OK);
  1253. break;
  1254. }
  1255. break;
  1256. /* EPP case WM_DESTROY: */
  1257. /* EPP if (Globals.hPopupWnd) DestroyWindow(Globals.hPopupWnd); */
  1258. /* EPP break; */
  1259. case WM_COPYDATA:
  1260. return WINHELP_HandleCommand((HWND)wParam, lParam);
  1261. case WM_CHAR:
  1262. if (wParam == 3)
  1263. {
  1264. SendDlgItemMessageW(hWnd, CTL_ID_TEXT, WM_COPY, 0, 0);
  1265. return 0;
  1266. }
  1267. break;
  1268. case WM_KEYDOWN:
  1269. win = (WINHELP_WINDOW*) GetWindowLongPtrW(hWnd, 0);
  1270. hTextWnd = GetDlgItem(win->hMainWnd, CTL_ID_TEXT);
  1271. switch (wParam)
  1272. {
  1273. case VK_UP:
  1274. SendMessageW(hTextWnd, EM_SCROLL, SB_LINEUP, 0);
  1275. return 0;
  1276. case VK_DOWN:
  1277. SendMessageW(hTextWnd, EM_SCROLL, SB_LINEDOWN, 0);
  1278. return 0;
  1279. case VK_PRIOR:
  1280. SendMessageW(hTextWnd, EM_SCROLL, SB_PAGEUP, 0);
  1281. return 0;
  1282. case VK_NEXT:
  1283. SendMessageW(hTextWnd, EM_SCROLL, SB_PAGEDOWN, 0);
  1284. return 0;
  1285. case VK_ESCAPE:
  1286. MACRO_Exit();
  1287. return 0;
  1288. }
  1289. break;
  1290. case WM_NOTIFY:
  1291. if (wParam == CTL_ID_TEXT)
  1292. {
  1293. RECT rc;
  1294. switch (((NMHDR*)lParam)->code)
  1295. {
  1296. case EN_MSGFILTER:
  1297. {
  1298. const MSGFILTER* msgf = (const MSGFILTER*)lParam;
  1299. switch (msgf->msg)
  1300. {
  1301. case WM_KEYUP:
  1302. if (msgf->wParam == VK_ESCAPE)
  1303. WINHELP_ReleaseWindow((WINHELP_WINDOW*)GetWindowLongPtrW(hWnd, 0));
  1304. break;
  1305. case WM_RBUTTONDOWN:
  1306. {
  1307. HMENU hMenu;
  1308. POINT pt;
  1309. win = (WINHELP_WINDOW*) GetWindowLongPtrW(hWnd, 0);
  1310. hMenu = LoadMenuW(Globals.hInstance, MAKEINTRESOURCEW(CONTEXT_MENU));
  1311. switch (win->font_scale)
  1312. {
  1313. case 0:
  1314. CheckMenuItem(hMenu, MNID_CTXT_FONTS_SMALL,
  1315. MF_BYCOMMAND|MF_CHECKED);
  1316. break;
  1317. default:
  1318. WINE_FIXME("Unsupported %d\n", win->font_scale);
  1319. /* fall through */
  1320. case 1:
  1321. CheckMenuItem(hMenu, MNID_CTXT_FONTS_NORMAL,
  1322. MF_BYCOMMAND|MF_CHECKED);
  1323. break;
  1324. case 2:
  1325. CheckMenuItem(hMenu, MNID_CTXT_FONTS_LARGE,
  1326. MF_BYCOMMAND|MF_CHECKED);
  1327. break;
  1328. }
  1329. pt.x = (int)(short)LOWORD(msgf->lParam);
  1330. pt.y = (int)(short)HIWORD(msgf->lParam);
  1331. ClientToScreen(msgf->nmhdr.hwndFrom, &pt);
  1332. TrackPopupMenu(GetSubMenu(hMenu, 0), TPM_LEFTALIGN|TPM_TOPALIGN,
  1333. pt.x, pt.y, 0, hWnd, NULL);
  1334. DestroyMenu(hMenu);
  1335. }
  1336. break;
  1337. default:
  1338. return WINHELP_HandleTextMouse((WINHELP_WINDOW*)GetWindowLongPtrW(hWnd, 0),
  1339. msgf->msg, msgf->lParam);
  1340. }
  1341. }
  1342. break;
  1343. case EN_REQUESTRESIZE:
  1344. rc = ((REQRESIZE*)lParam)->rc;
  1345. win = (WINHELP_WINDOW*) GetWindowLongPtrW(hWnd, 0);
  1346. AdjustWindowRect(&rc, GetWindowLongW(win->hMainWnd, GWL_STYLE),
  1347. FALSE);
  1348. SetWindowPos(win->hMainWnd, HWND_TOP, 0, 0,
  1349. rc.right - rc.left, rc.bottom - rc.top,
  1350. SWP_NOMOVE | SWP_NOZORDER);
  1351. WINHELP_LayoutMainWindow(win);
  1352. break;
  1353. }
  1354. }
  1355. break;
  1356. case WM_INITMENUPOPUP:
  1357. win = (WINHELP_WINDOW*) GetWindowLongPtrW(hWnd, 0);
  1358. CheckMenuItem((HMENU)wParam, MNID_OPTS_FONTS_SMALL,
  1359. (win->font_scale == 0) ? MF_CHECKED : MF_UNCHECKED);
  1360. CheckMenuItem((HMENU)wParam, MNID_OPTS_FONTS_NORMAL,
  1361. (win->font_scale == 1) ? MF_CHECKED : MF_UNCHECKED);
  1362. CheckMenuItem((HMENU)wParam, MNID_OPTS_FONTS_LARGE,
  1363. (win->font_scale == 2) ? MF_CHECKED : MF_UNCHECKED);
  1364. break;
  1365. case WM_DESTROY:
  1366. win = (WINHELP_WINDOW*) GetWindowLongPtrW(hWnd, 0);
  1367. WINHELP_DeleteWindow(win);
  1368. break;
  1369. }
  1370. return DefWindowProcA(hWnd, msg, wParam, lParam);
  1371. }
  1372. /**************************************************************************
  1373. * WINHELP_CreateIndexWindow
  1374. *
  1375. * Displays a dialog with keywords of current help file.
  1376. *
  1377. */
  1378. BOOL WINHELP_CreateIndexWindow(BOOL is_search)
  1379. {
  1380. HPROPSHEETPAGE psPage[3];
  1381. PROPSHEETPAGEA psp;
  1382. PROPSHEETHEADERA psHead;
  1383. struct index_data id;
  1384. char buf[256];
  1385. if (Globals.active_win && Globals.active_win->page && Globals.active_win->page->file)
  1386. id.hlpfile = Globals.active_win->page->file;
  1387. else
  1388. return FALSE;
  1389. if (id.hlpfile->kwbtree == NULL)
  1390. {
  1391. WINE_TRACE("No index provided\n");
  1392. return FALSE;
  1393. }
  1394. InitCommonControls();
  1395. id.jump = FALSE;
  1396. memset(&psp, 0, sizeof(psp));
  1397. psp.dwSize = sizeof(psp);
  1398. psp.dwFlags = 0;
  1399. psp.hInstance = Globals.hInstance;
  1400. psp.u.pszTemplate = MAKEINTRESOURCEA(IDD_INDEX);
  1401. psp.lParam = (LPARAM)&id;
  1402. psp.pfnDlgProc = WINHELP_IndexDlgProc;
  1403. psPage[0] = CreatePropertySheetPageA(&psp);
  1404. psp.u.pszTemplate = MAKEINTRESOURCEA(IDD_SEARCH);
  1405. psp.lParam = (LPARAM)&id;
  1406. psp.pfnDlgProc = WINHELP_SearchDlgProc;
  1407. psPage[1] = CreatePropertySheetPageA(&psp);
  1408. memset(&psHead, 0, sizeof(psHead));
  1409. psHead.dwSize = sizeof(psHead);
  1410. LoadStringA(Globals.hInstance, STID_PSH_INDEX, buf, sizeof(buf));
  1411. strcat(buf, Globals.active_win->info->caption);
  1412. psHead.pszCaption = buf;
  1413. psHead.nPages = 2;
  1414. psHead.u2.nStartPage = is_search ? 1 : 0;
  1415. psHead.hwndParent = Globals.active_win->hMainWnd;
  1416. psHead.u3.phpage = psPage;
  1417. psHead.dwFlags = PSH_NOAPPLYNOW;
  1418. PropertySheetA(&psHead);
  1419. if (id.jump)
  1420. {
  1421. WINE_TRACE("got %ld as an offset\n", id.offset);
  1422. WINHELP_OpenHelpWindow(HLPFILE_PageByOffset, id.hlpfile, id.offset,
  1423. Globals.active_win->info, SW_NORMAL);
  1424. }
  1425. return TRUE;
  1426. }
  1427. /***********************************************************************
  1428. *
  1429. * RegisterWinClasses
  1430. */
  1431. static BOOL WINHELP_RegisterWinClasses(void)
  1432. {
  1433. WNDCLASSEXA class_main, class_button_box, class_history;
  1434. class_main.cbSize = sizeof(class_main);
  1435. class_main.style = CS_HREDRAW | CS_VREDRAW;
  1436. class_main.lpfnWndProc = WINHELP_MainWndProc;
  1437. class_main.cbClsExtra = 0;
  1438. class_main.cbWndExtra = sizeof(WINHELP_WINDOW *);
  1439. class_main.hInstance = Globals.hInstance;
  1440. class_main.hIcon = LoadIconW(Globals.hInstance, MAKEINTRESOURCEW(IDI_WINHELP));
  1441. class_main.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
  1442. class_main.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
  1443. class_main.lpszMenuName = 0;
  1444. class_main.lpszClassName = MAIN_WIN_CLASS_NAME;
  1445. class_main.hIconSm = LoadImageW(Globals.hInstance, MAKEINTRESOURCEW(IDI_WINHELP), IMAGE_ICON,
  1446. GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON),
  1447. LR_SHARED);
  1448. class_button_box = class_main;
  1449. class_button_box.lpfnWndProc = WINHELP_ButtonBoxWndProc;
  1450. class_button_box.cbWndExtra = 0;
  1451. class_button_box.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
  1452. class_button_box.lpszClassName = BUTTON_BOX_WIN_CLASS_NAME;
  1453. class_history = class_main;
  1454. class_history.lpfnWndProc = WINHELP_HistoryWndProc;
  1455. class_history.lpszClassName = HISTORY_WIN_CLASS_NAME;
  1456. return (RegisterClassExA(&class_main) &&
  1457. RegisterClassExA(&class_button_box) &&
  1458. RegisterClassExA(&class_history));
  1459. }
  1460. /***********************************************************************
  1461. *
  1462. * WinMain
  1463. */
  1464. int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE prev, LPSTR cmdline, int show)
  1465. {
  1466. MSG msg;
  1467. LONG lHash = 0;
  1468. HLPFILE* hlpfile;
  1469. static CHAR default_wndname[] = "main";
  1470. LPSTR wndname = default_wndname;
  1471. WINHELP_DLL* dll;
  1472. HACCEL hAccel;
  1473. Globals.hInstance = hInstance;
  1474. if (LoadLibraryA("riched20.dll") == NULL)
  1475. return MessageBoxW(0, MAKEINTRESOURCEW(STID_NO_RICHEDIT),
  1476. MAKEINTRESOURCEW(STID_WHERROR), MB_OK);
  1477. /* Get options */
  1478. while (*cmdline && (*cmdline == ' ' || *cmdline == '-'))
  1479. {
  1480. CHAR option;
  1481. LPCSTR topic_id;
  1482. if (*cmdline++ == ' ') continue;
  1483. option = *cmdline;
  1484. if (option) cmdline++;
  1485. while (*cmdline == ' ') cmdline++;
  1486. switch (option)
  1487. {
  1488. case 'i':
  1489. case 'I':
  1490. topic_id = cmdline;
  1491. while (*cmdline && *cmdline != ' ') cmdline++;
  1492. if (*cmdline) *cmdline++ = '\0';
  1493. lHash = HLPFILE_Hash(topic_id);
  1494. break;
  1495. case '3':
  1496. case '4':
  1497. Globals.wVersion = option - '0';
  1498. break;
  1499. case 'x':
  1500. show = SW_HIDE;
  1501. Globals.isBook = FALSE;
  1502. break;
  1503. default:
  1504. WINE_FIXME("Unsupported cmd line: %s\n", debugstr_a(cmdline));
  1505. break;
  1506. }
  1507. }
  1508. /* Create primary window */
  1509. if (!WINHELP_RegisterWinClasses())
  1510. {
  1511. WINE_FIXME("Couldn't register classes\n");
  1512. return 0;
  1513. }
  1514. if (*cmdline)
  1515. {
  1516. char* ptr;
  1517. if ((*cmdline == '"') && (ptr = strchr(cmdline+1, '"')))
  1518. {
  1519. cmdline++;
  1520. *ptr = '\0';
  1521. }
  1522. if ((ptr = strchr(cmdline, '>')))
  1523. {
  1524. *ptr = '\0';
  1525. wndname = ptr + 1;
  1526. }
  1527. hlpfile = WINHELP_LookupHelpFile(cmdline);
  1528. if (!hlpfile) return 0;
  1529. }
  1530. else hlpfile = NULL;
  1531. WINHELP_OpenHelpWindow(HLPFILE_PageByHash, hlpfile, lHash,
  1532. WINHELP_GetWindowInfo(hlpfile, wndname), show);
  1533. /* Message loop */
  1534. hAccel = LoadAcceleratorsW(hInstance, MAKEINTRESOURCEW(MAIN_ACCEL));
  1535. while ((Globals.win_list || Globals.active_popup) && GetMessageW(&msg, 0, 0, 0))
  1536. {
  1537. HWND hWnd = Globals.active_win ? Globals.active_win->hMainWnd : NULL;
  1538. if (!TranslateAcceleratorW(hWnd, hAccel, &msg))
  1539. {
  1540. TranslateMessage(&msg);
  1541. DispatchMessageW(&msg);
  1542. }
  1543. }
  1544. for (dll = Globals.dlls; dll; dll = dll->next)
  1545. {
  1546. if (dll->class & DC_INITTERM) dll->handler(DW_TERM, 0, 0);
  1547. }
  1548. return 0;
  1549. }