Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3717 lines
105 KiB

  1. // Copyright (C) 1996-1997 Microsoft Corporation. All rights reserved.
  2. #include "header.h"
  3. #include "secwin.h"
  4. #include "strtable.h"
  5. #include "hha_strtable.h"
  6. #include "htmlhelp.h"
  7. #include <commctrl.h>
  8. #include "sitemap.h" // ReplaceEscapes
  9. #include <shlobj.h> // CSIDL_X defs
  10. // global window type array.
  11. #include "gwintype.h"
  12. #include "cstr.h"
  13. #ifndef _DEBUG
  14. #undef THIS_FILE
  15. static const char THIS_FILE[] = __FILE__;
  16. #endif
  17. #ifndef _DEBUG
  18. #pragma optimize("a", on)
  19. #endif
  20. #define PT_TO_PIXELS(hdc, pt) MulDiv(-(pt), GetDeviceCaps(hdc, LOGPIXELSY), 72)
  21. static POINT GetTextSize(HDC hdc, PCSTR qchBuf, int iCount);
  22. static POINT GetTextSizeW(HDC hdc, WCHAR *qchBuf, int iCount);
  23. BOOL IsDigitW(WCHAR ch) { return (ch >= L'0' && ch <= 'L9'); }
  24. int IEColorToWin32Color( PCWSTR pwsz )
  25. {
  26. // input: "#rrggbb"
  27. // output: int in hex form of 0xbbggrr
  28. char sz[9];
  29. strcpy( sz, "0x" );
  30. // get blue
  31. WideCharToMultiByte( CP_ACP, 0, pwsz+5, 2, &(sz[2]), 2, NULL, NULL );
  32. // get green
  33. WideCharToMultiByte( CP_ACP, 0, pwsz+3, 2, &(sz[4]), 2, NULL, NULL );
  34. // get red
  35. WideCharToMultiByte( CP_ACP, 0, pwsz+1, 2, &(sz[6]), 2, NULL, NULL );
  36. // null terminate the string
  37. sz[8] = 0;
  38. // convert it
  39. return Atoi( sz );
  40. }
  41. //=--------------------------------------------------------------------------=
  42. // MakeWideFromAnsi
  43. //=--------------------------------------------------------------------------=
  44. // given a string, make a BSTR out of it.
  45. //
  46. // Parameters:
  47. // LPSTR - [in]
  48. // BYTE - [in]
  49. //
  50. // Output:
  51. // LPWSTR - needs to be cast to final desired result
  52. //
  53. // Notes:
  54. //
  55. LPWSTR MakeWideStrFromAnsi(LPSTR psz, BYTE bType)
  56. {
  57. LPWSTR pwsz;
  58. int i;
  59. ASSERT(psz)
  60. // compute the length of the required BSTR
  61. i = MultiByteToWideChar(CP_ACP, 0, psz, -1, NULL, 0);
  62. if (i <= 0)
  63. return NULL;
  64. // allocate the widestr
  65. switch (bType) {
  66. case STR_BSTR:
  67. // -1 since it'll add it's own space for a NULL terminator
  68. pwsz = (LPWSTR) SysAllocStringLen(NULL, i - 1);
  69. break;
  70. case STR_OLESTR:
  71. pwsz = (LPWSTR) CoTaskMemAlloc(i * sizeof(WCHAR));
  72. break;
  73. default:
  74. FAIL("Bogus String Type.");
  75. }
  76. if (!pwsz)
  77. return NULL;
  78. MultiByteToWideChar(CP_ACP, 0, psz, -1, pwsz, i);
  79. pwsz[i - 1] = 0;
  80. return pwsz;
  81. }
  82. LPWSTR MakeWideStr(LPSTR psz, UINT codepage)
  83. {
  84. LPWSTR pwsz;
  85. int i;
  86. ASSERT(psz)
  87. // compute the length of the required BSTR
  88. i = MultiByteToWideChar(codepage, 0, psz, -1, NULL, 0);
  89. if (i <= 0)
  90. return NULL;
  91. ++i;
  92. pwsz = (WCHAR *) malloc(i * sizeof(WCHAR));
  93. if (!pwsz)
  94. return NULL;
  95. MultiByteToWideChar(codepage, 0, psz, -1, pwsz, i);
  96. return pwsz;
  97. }
  98. //=--------------------------------------------------------------------------=
  99. // MakeWideStrFromResId
  100. //=--------------------------------------------------------------------------=
  101. // given a resource ID, load it, and allocate a wide string for it.
  102. //
  103. // Parameters:
  104. // WORD - [in] resource id.
  105. // BYTE - [in] type of string desired.
  106. //
  107. // Output:
  108. // LPWSTR - needs to be cast to desired string type.
  109. //
  110. // Notes:
  111. //
  112. LPWSTR MakeWideStrFromResourceId (WORD wId, BYTE bType)
  113. {
  114. int i;
  115. char szTmp[512];
  116. // load the string from the resources.
  117. //
  118. i = LoadString(_Module.GetResourceInstance(), wId, szTmp, 512);
  119. if (!i)
  120. return NULL;
  121. return MakeWideStrFromAnsi(szTmp, bType);
  122. }
  123. //=--------------------------------------------------------------------------=
  124. // MakeWideStrFromWide
  125. //=--------------------------------------------------------------------------=
  126. // given a wide string, make a new wide string with it of the given type.
  127. //
  128. // Parameters:
  129. // LPWSTR - [in] current wide str.
  130. // BYTE - [in] desired type of string.
  131. //
  132. // Output:
  133. // LPWSTR
  134. //
  135. // Notes:
  136. //
  137. LPWSTR MakeWideStrFromWide
  138. (
  139. LPWSTR pwsz,
  140. BYTE bType
  141. )
  142. {
  143. LPWSTR pwszTmp;
  144. int i;
  145. if (!pwsz) return NULL;
  146. // just copy the string, depending on what type they want.
  147. //
  148. switch (bType) {
  149. case STR_OLESTR:
  150. i = lstrlenW(pwsz);
  151. pwszTmp = (LPWSTR)CoTaskMemAlloc((i * sizeof(WCHAR)) + sizeof(WCHAR));
  152. if (!pwszTmp) return NULL;
  153. memcpy(pwszTmp, pwsz, (sizeof(WCHAR) * i) + sizeof(WCHAR));
  154. break;
  155. case STR_BSTR:
  156. pwszTmp = (LPWSTR)SysAllocString(pwsz);
  157. break;
  158. }
  159. return pwszTmp;
  160. }
  161. //=--------------------------------------------------------------------------=
  162. // StringFromGuidA
  163. //=--------------------------------------------------------------------------=
  164. // returns an ANSI string from a CLSID or GUID
  165. //
  166. // Parameters:
  167. // REFIID - [in] clsid to make string out of.
  168. // LPSTR - [in] buffer in which to place resultant GUID.
  169. //
  170. // Output:
  171. // int - number of chars written out.
  172. //
  173. // Notes:
  174. //
  175. int StringFromGuidA
  176. (
  177. REFIID riid,
  178. LPSTR pszBuf
  179. )
  180. {
  181. return wsprintf((char *)pszBuf, "{%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}", riid.Data1,
  182. riid.Data2, riid.Data3, riid.Data4[0], riid.Data4[1], riid.Data4[2],
  183. riid.Data4[3], riid.Data4[4], riid.Data4[5], riid.Data4[6], riid.Data4[7]);
  184. }
  185. //=--------------------------------------------------------------------------=
  186. // RegisterUnknownObject
  187. //=--------------------------------------------------------------------------=
  188. // registers a simple CoCreatable object. nothing terribly serious.
  189. // we add the following information to the registry:
  190. //
  191. // HKEY_CLASSES_ROOT\CLSID\<CLSID> = <ObjectName> Object
  192. // HKEY_CLASSES_ROOT\CLSID\<CLSID>\InprocServer32 = <path to local server>
  193. //
  194. // Parameters:
  195. // LPCSTR - [in] Object Name
  196. // REFCLSID - [in] CLSID of the object
  197. //
  198. // Output:
  199. // BOOL - FALSE means couldn't register it all
  200. BOOL RegisterUnknownObject(LPCSTR pszObjectName, REFCLSID riidObject)
  201. {
  202. HKEY hk = NULL, hkSub = NULL;
  203. char szGuidStr[GUID_STR_LEN];
  204. DWORD dwPathLen, dwDummy;
  205. char szScratch[MAX_PATH];
  206. long l;
  207. // clean out any garbage
  208. UnregisterUnknownObject(riidObject);
  209. // HKEY_CLASSES_ROOT\CLSID\<CLSID> = <ObjectName> Object
  210. // HKEY_CLASSES_ROOT\CLSID\<CLSID>\InprocServer32 = <path to local server>
  211. // HKEY_CLASSES_ROOT\CLSID\<CLSID>\InprocServer32 @ThreadingModel = Apartment
  212. //
  213. if (!StringFromGuidA(riidObject, szGuidStr)) goto CleanUp;
  214. wsprintf(szScratch, "CLSID\\%s", szGuidStr);
  215. l = RegCreateKeyEx(HKEY_CLASSES_ROOT, szScratch, 0, "", REG_OPTION_NON_VOLATILE,
  216. KEY_READ | KEY_WRITE, NULL, &hk, &dwDummy);
  217. CLEANUP_ON_ERROR(l);
  218. wsprintf(szScratch, "%s Object", pszObjectName);
  219. l = RegSetValueEx(hk, NULL, 0, REG_SZ, (BYTE *)szScratch, (ULONG)strlen(szScratch) + 1);
  220. CLEANUP_ON_ERROR(l);
  221. l = RegCreateKeyEx(hk, "InprocServer32", 0, "", REG_OPTION_NON_VOLATILE,
  222. KEY_READ | KEY_WRITE, NULL, &hkSub, &dwDummy);
  223. CLEANUP_ON_ERROR(l);
  224. dwPathLen = GetModuleFileName(_Module.GetModuleInstance(), szScratch, sizeof(szScratch));
  225. if (!dwPathLen)
  226. goto CleanUp;
  227. l = RegSetValueEx(hkSub, NULL, 0, REG_SZ, (BYTE *)szScratch, dwPathLen + 1);
  228. CLEANUP_ON_ERROR(l);
  229. l = RegSetValueEx(hkSub, "ThreadingModel", 0, REG_SZ, (BYTE *)"Apartment", sizeof("Apartment"));
  230. CLEANUP_ON_ERROR(l);
  231. RegCloseKey(hkSub);
  232. RegCloseKey(hk);
  233. return TRUE;
  234. CleanUp:
  235. if (hk)
  236. RegCloseKey(hk);
  237. if (hkSub)
  238. RegCloseKey(hkSub);
  239. return FALSE;
  240. }
  241. //=--------------------------------------------------------------------------=
  242. // RegisterAutomationObject
  243. //=--------------------------------------------------------------------------=
  244. // given a little bit of information about an automation object, go and put it
  245. // in the registry.
  246. // we add the following information in addition to that set up in
  247. // RegisterUnknownObject:
  248. //
  249. //
  250. // HKEY_CLASSES_ROOT\<LibraryName>.<ObjectName> = <ObjectName> Object
  251. // HKEY_CLASSES_ROOT\<LibraryName>.<ObjectName>\CLSID = <CLSID>
  252. // HKEY_CLASSES_ROOT\<LibraryName>.<ObjectName>\CurVer = <ObjectName>.Object.<VersionNumber>
  253. //
  254. // HKEY_CLASSES_ROOT\<LibraryName>.<ObjectName>.<VersionNumber> = <ObjectName> Object
  255. // HKEY_CLASSES_ROOT\<LibraryName>.<ObjectName>.<VersionNumber>\CLSID = <CLSID>
  256. //
  257. // HKEY_CLASSES_ROOT\CLSID\<CLSID>\TypeLib = <LibidOfTypeLibrary>
  258. // HKEY_CLASSES_ROOT\CLSID\<CLSID>\ProgID = <LibraryName>.<ObjectName>.<VersionNumber>
  259. // HKEY_CLASSES_ROOT\CLSID\<CLSID>\VersionIndependentProgID = <LibraryName>.<ObjectName>
  260. //
  261. // Parameters:
  262. // LPCSTR - [in] Library Name
  263. // LPCSTR - [in] Object Name
  264. // long - [in] Version Number
  265. // REFCLSID - [in] LIBID of type library
  266. // REFCLSID - [in] CLSID of the object
  267. //
  268. // Output:
  269. // BOOL - FALSE means not all of it was registered
  270. BOOL RegisterAutomationObject
  271. (
  272. LPCSTR pszLibName,
  273. LPCSTR pszObjectName,
  274. long lVersion,
  275. REFCLSID riidLibrary,
  276. REFCLSID riidObject
  277. )
  278. {
  279. HKEY hk = NULL, hkSub = NULL;
  280. char szGuidStr[GUID_STR_LEN];
  281. char szScratch[MAX_PATH];
  282. long l;
  283. DWORD dwDummy;
  284. // first register the simple Unknown stuff.
  285. //
  286. if (!RegisterUnknownObject(pszObjectName, riidObject)) return FALSE;
  287. // HKEY_CLASSES_ROOT\<LibraryName>.<ObjectName> = <ObjectName> Object
  288. // HKEY_CLASSES_ROOT\<LibraryName>.<ObjectName>\CLSID = <CLSID>
  289. // HKEY_CLASSES_ROOT\<LibraryName>.<ObjectName>\CurVer = <ObjectName>.Object.<VersionNumber>
  290. //
  291. strcpy(szScratch, pszLibName);
  292. strcat(szScratch, ".");
  293. strcat(szScratch, pszObjectName);
  294. l = RegCreateKeyEx(HKEY_CLASSES_ROOT, szScratch, 0L, "",
  295. REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE,
  296. NULL, &hk, &dwDummy);
  297. CLEANUP_ON_ERROR(l);
  298. wsprintf(szScratch, "%s Object", pszObjectName);
  299. l = RegSetValueEx(hk, NULL, 0L, REG_SZ, (BYTE *)szScratch, (ULONG)strlen(szScratch)+1);
  300. CLEANUP_ON_ERROR(l);
  301. l = RegCreateKeyEx(hk, "CLSID", 0L, "", REG_OPTION_NON_VOLATILE,
  302. KEY_READ | KEY_WRITE, NULL, &hkSub, &dwDummy);
  303. CLEANUP_ON_ERROR(l);
  304. if (!StringFromGuidA(riidObject, szGuidStr))
  305. goto CleanUp;
  306. l = RegSetValueEx(hkSub, NULL, 0L, REG_SZ, (BYTE *)szGuidStr, (ULONG)strlen(szGuidStr) + 1);
  307. CLEANUP_ON_ERROR(l);
  308. RegCloseKey(hkSub);
  309. l = RegCreateKeyEx(hk, "CurVer", 0, "", REG_OPTION_NON_VOLATILE,
  310. KEY_READ | KEY_WRITE, NULL, &hkSub, &dwDummy);
  311. CLEANUP_ON_ERROR(l);
  312. wsprintf(szScratch, "%s.%s.%ld", pszLibName, pszObjectName, lVersion);
  313. l = RegSetValueEx(hkSub, NULL, 0, REG_SZ, (BYTE *)szScratch, (ULONG)strlen(szScratch) + 1);
  314. CLEANUP_ON_ERROR(l);
  315. RegCloseKey(hkSub);
  316. RegCloseKey(hk);
  317. // HKEY_CLASSES_ROOT\<LibraryName>.<ObjectName>.<VersionNumber> = <ObjectName> Object
  318. // HKEY_CLASSES_ROOT\<LibraryName>.<ObjectName>.<VersionNumber>\CLSID = <CLSID>
  319. //
  320. l = RegCreateKeyEx(HKEY_CLASSES_ROOT, szScratch, 0, "", REG_OPTION_NON_VOLATILE,
  321. KEY_READ | KEY_WRITE, NULL, &hk, &dwDummy);
  322. CLEANUP_ON_ERROR(l);
  323. wsprintf(szScratch, "%s Object", pszObjectName);
  324. l = RegSetValueEx(hk, NULL, 0, REG_SZ, (BYTE *)szScratch, (ULONG)strlen(szScratch) + 1);
  325. CLEANUP_ON_ERROR(l);
  326. l = RegCreateKeyEx(hk, "CLSID", 0, "", REG_OPTION_NON_VOLATILE,
  327. KEY_READ | KEY_WRITE, NULL, &hkSub, &dwDummy);
  328. CLEANUP_ON_ERROR(l);
  329. l = RegSetValueEx(hkSub, NULL, 0, REG_SZ, (BYTE *)szGuidStr, (ULONG)strlen(szGuidStr) + 1);
  330. CLEANUP_ON_ERROR(l);
  331. RegCloseKey(hkSub);
  332. RegCloseKey(hk);
  333. // HKEY_CLASSES_ROOT\CLSID\<CLSID>\ProgID = <LibraryName>.<ObjectName>.<VersionNumber>
  334. // HKEY_CLASSES_ROOT\CLSID\<CLSID>\VersionIndependentProgID = <LibraryName>.<ObjectName>
  335. // HKEY_CLASSES_ROOT\CLSID\<CLSID>\TypeLib = <LibidOfTypeLibrary>
  336. //
  337. if (!StringFromGuidA(riidObject, szGuidStr)) goto CleanUp;
  338. wsprintf(szScratch, "CLSID\\%s", szGuidStr);
  339. l = RegCreateKeyEx(HKEY_CLASSES_ROOT, szScratch, 0, "", REG_OPTION_NON_VOLATILE,
  340. KEY_READ|KEY_WRITE, NULL, &hk, &dwDummy);
  341. CLEANUP_ON_ERROR(l);
  342. l = RegCreateKeyEx(hk, "VersionIndependentProgID", 0, "", REG_OPTION_NON_VOLATILE,
  343. KEY_READ | KEY_WRITE, NULL, &hkSub, &dwDummy);
  344. CLEANUP_ON_ERROR(l);
  345. wsprintf(szScratch, "%s.%s", pszLibName, pszObjectName);
  346. l = RegSetValueEx(hkSub, NULL, 0, REG_SZ, (BYTE *)szScratch, (ULONG)strlen(szScratch) + 1);
  347. CLEANUP_ON_ERROR(l);
  348. RegCloseKey(hkSub);
  349. l = RegCreateKeyEx(hk, "ProgID", 0, "", REG_OPTION_NON_VOLATILE,
  350. KEY_READ | KEY_WRITE, NULL, &hkSub, &dwDummy);
  351. CLEANUP_ON_ERROR(l);
  352. wsprintf(szScratch, "%s.%s.%ld", pszLibName, pszObjectName, lVersion);
  353. l = RegSetValueEx(hkSub, NULL, 0, REG_SZ, (BYTE *)szScratch, (ULONG)strlen(szScratch) + 1);
  354. CLEANUP_ON_ERROR(l);
  355. RegCloseKey(hkSub);
  356. l = RegCreateKeyEx(hk, "TypeLib", 0, "", REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE,
  357. NULL, &hkSub, &dwDummy);
  358. if (!StringFromGuidA(riidLibrary, szGuidStr)) goto CleanUp;
  359. l = RegSetValueEx(hkSub, NULL, 0, REG_SZ, (BYTE *)szGuidStr, (ULONG)strlen(szGuidStr) + 1);
  360. CLEANUP_ON_ERROR(l);
  361. RegCloseKey(hkSub);
  362. RegCloseKey(hk);
  363. return TRUE;
  364. CleanUp:
  365. if (hk) RegCloseKey(hkSub);
  366. if (hk) RegCloseKey(hk);
  367. return FALSE;
  368. }
  369. //=--------------------------------------------------------------------------=
  370. // RegisterControlObject.
  371. //=--------------------------------------------------------------------------=
  372. // in addition to writing out automation object information, this function
  373. // writes out some values specific to a control.
  374. //
  375. // What we add here:
  376. //
  377. // HKEY_CLASSES_ROOT\CLSID\<CLSID>\Control
  378. // HKEY_CLASSES_ROOT\CLSID\<CLSID>\MiscStatus\1 = <MISCSTATUSBITS>
  379. // HKEY_CLASSES_ROOT\CLSID\<CLSID>\ToolboxBitmap32 = <PATH TO BMP>
  380. // HKEY_CLASSES_ROOT\CLSID\<CLSID>\Version = <VERSION>
  381. //
  382. // Parameters:
  383. // LPCSTR - [in] Library Name
  384. // LPCSTR - [in] Object Name
  385. // long - [in] Version Number
  386. // REFCLSID - [in] LIBID of type library
  387. // REFCLSID - [in] CLSID of the object
  388. // DWORD - [in] misc status flags for ctl
  389. // WORD - [in] toolbox id for control
  390. //
  391. // Output:
  392. // BOOL
  393. //
  394. // Notes:
  395. // - not the most terribly efficient routine.
  396. //
  397. BOOL RegisterControlObject
  398. (
  399. LPCSTR pszLibName,
  400. LPCSTR pszObjectName,
  401. long lVersion,
  402. REFCLSID riidLibrary,
  403. REFCLSID riidObject,
  404. DWORD dwMiscStatus,
  405. WORD wToolboxBitmapId
  406. )
  407. {
  408. HKEY hk, hkSub = NULL, hkSub2 = NULL;
  409. char szTmp[MAX_PATH];
  410. char szGuidStr[GUID_STR_LEN];
  411. DWORD dwDummy;
  412. LONG l;
  413. // first register all the automation information for this sucker.
  414. //
  415. if (!RegisterAutomationObject(pszLibName, pszObjectName, lVersion, riidLibrary, riidObject)) return FALSE;
  416. // then go and register the control specific stuff.
  417. //
  418. StringFromGuidA(riidObject, szGuidStr);
  419. wsprintf(szTmp, "CLSID\\%s", szGuidStr);
  420. l = RegOpenKeyEx(HKEY_CLASSES_ROOT, szTmp, 0, KEY_ALL_ACCESS, &hk);
  421. if (l != ERROR_SUCCESS) return FALSE;
  422. // create the control flag.
  423. //
  424. l = RegCreateKeyEx(hk, "Control", 0, "", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkSub, &dwDummy);
  425. CLEANUP_ON_ERROR(l);
  426. // now set up the MiscStatus Bits...
  427. //
  428. RegCloseKey(hkSub);
  429. hkSub = NULL;
  430. l = RegCreateKeyEx(hk, "MiscStatus", 0, "", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkSub, &dwDummy);
  431. CLEANUP_ON_ERROR(l);
  432. szTmp[0] = '0';
  433. szTmp[1] = '\0';
  434. l = RegSetValueEx(hkSub, NULL, 0, REG_SZ, (BYTE *)szTmp, 2);
  435. CLEANUP_ON_ERROR(l);
  436. l = RegCreateKeyEx(hkSub, "1", 0, "", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkSub2, &dwDummy);
  437. CLEANUP_ON_ERROR(l);
  438. wsprintf(szTmp, "%d", dwMiscStatus);
  439. l = RegSetValueEx(hkSub2, NULL, 0, REG_SZ, (BYTE *)szTmp, (ULONG)strlen(szTmp) + 1);
  440. RegCloseKey(hkSub2);
  441. CLEANUP_ON_ERROR(l);
  442. RegCloseKey(hkSub);
  443. // now set up the toolbox bitmap
  444. //
  445. GetModuleFileName(_Module.GetModuleInstance(), szTmp, MAX_PATH);
  446. wsprintf(szGuidStr, ", %d", wToolboxBitmapId);
  447. strcat(szTmp, szGuidStr);
  448. l = RegCreateKeyEx(hk, "ToolboxBitmap32", 0, "", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkSub, &dwDummy);
  449. CLEANUP_ON_ERROR(l);
  450. l = RegSetValueEx(hkSub, NULL, 0, REG_SZ, (BYTE *)szTmp, (ULONG)strlen(szTmp) + 1);
  451. CLEANUP_ON_ERROR(l);
  452. // now set up the version information
  453. //
  454. RegCloseKey(hkSub);
  455. l = RegCreateKeyEx(hk, "Version", 0, "", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkSub, &dwDummy);
  456. CLEANUP_ON_ERROR(l);
  457. wsprintf(szTmp, "%ld.0", lVersion);
  458. l = RegSetValueEx(hkSub, NULL, 0, REG_SZ, (BYTE *)szTmp, (ULONG)strlen(szTmp) + 1);
  459. CleanUp:
  460. if (hk)
  461. RegCloseKey(hk);
  462. if (hkSub)
  463. RegCloseKey(hkSub);
  464. return (l == ERROR_SUCCESS) ? TRUE : FALSE;
  465. }
  466. //=--------------------------------------------------------------------------=
  467. // UnregisterUnknownObject
  468. //=--------------------------------------------------------------------------=
  469. // cleans up all the stuff that RegisterUnknownObject puts in the
  470. // registry.
  471. //
  472. // Parameters:
  473. // REFCLSID - [in] CLSID of the object
  474. //
  475. // Output:
  476. // BOOL - FALSE means not all of it was registered
  477. //
  478. // Notes:
  479. // - WARNING: this routine will blow away all other keys under the CLSID
  480. // for this object. mildly anti-social, but likely not a problem.
  481. //
  482. BOOL UnregisterUnknownObject
  483. (
  484. REFCLSID riidObject
  485. )
  486. {
  487. char szScratch[MAX_PATH];
  488. HKEY hk;
  489. BOOL f;
  490. long l;
  491. // delete everybody of the form
  492. // HKEY_CLASSES_ROOT\CLSID\<CLSID> [\] *
  493. //
  494. if (!StringFromGuidA(riidObject, szScratch))
  495. return FALSE;
  496. l = RegOpenKeyEx(HKEY_CLASSES_ROOT, "CLSID", 0, KEY_ALL_ACCESS, &hk);
  497. if (l != ERROR_SUCCESS) return FALSE;
  498. f = DeleteKeyAndSubKeys(hk, szScratch);
  499. RegCloseKey(hk);
  500. return f;
  501. }
  502. //=--------------------------------------------------------------------------=
  503. // UnregisterAutomationObject
  504. //=--------------------------------------------------------------------------=
  505. // unregisters an automation object, including all of it's unknown object
  506. // information.
  507. //
  508. // Parameters:
  509. // LPCSTR - [in] Library Name
  510. // LPCSTR - [in] Object Name
  511. // long - [in] Version Number
  512. // REFCLSID - [in] CLSID of the object
  513. //
  514. // Output:
  515. // BOOL - FALSE means couldn't get it all unregistered.
  516. //
  517. // Notes:
  518. //
  519. BOOL UnregisterAutomationObject
  520. (
  521. LPCSTR pszLibName,
  522. LPCSTR pszObjectName,
  523. long lVersion,
  524. REFCLSID riidObject
  525. )
  526. {
  527. char szScratch[MAX_PATH];
  528. BOOL f;
  529. // first thing -- unregister Unknown information
  530. //
  531. f = UnregisterUnknownObject(riidObject);
  532. if (!f) return FALSE;
  533. // delete everybody of the form:
  534. // HKEY_CLASSES_ROOT\<LibraryName>.<ObjectName> [\] *
  535. //
  536. wsprintf(szScratch, "%s.%s", pszLibName, pszObjectName);
  537. f = DeleteKeyAndSubKeys(HKEY_CLASSES_ROOT, szScratch);
  538. if (!f) return FALSE;
  539. // delete everybody of the form
  540. // HKEY_CLASSES_ROOT\<LibraryName>.<ObjectName>.<VersionNumber> [\] *
  541. //
  542. wsprintf(szScratch, "%s.%s.%ld", pszLibName, pszObjectName, lVersion);
  543. f = DeleteKeyAndSubKeys(HKEY_CLASSES_ROOT, szScratch);
  544. if (!f) return FALSE;
  545. return TRUE;
  546. }
  547. //=--------------------------------------------------------------------------=
  548. // UnregisterTypeLibrary
  549. //=--------------------------------------------------------------------------=
  550. // blows away the type library keys for a given libid.
  551. //
  552. // Parameters:
  553. // REFCLSID - [in] libid to blow away.
  554. //
  555. // Output:
  556. // BOOL - TRUE OK, FALSE bad.
  557. //
  558. // Notes:
  559. // - WARNING: this function just blows away the entire type library section,
  560. // including all localized versions of the type library. mildly anti-
  561. // social, but not killer.
  562. //
  563. BOOL UnregisterTypeLibrary
  564. (
  565. REFCLSID riidLibrary
  566. )
  567. {
  568. HKEY hk;
  569. char szScratch[GUID_STR_LEN];
  570. long l;
  571. BOOL f;
  572. // convert the libid into a string.
  573. //
  574. if (!StringFromGuidA(riidLibrary, szScratch))
  575. return FALSE;
  576. l = RegOpenKeyEx(HKEY_CLASSES_ROOT, "TypeLib", 0, KEY_ALL_ACCESS, &hk);
  577. if (l != ERROR_SUCCESS) return FALSE;
  578. f = DeleteKeyAndSubKeys(hk, szScratch);
  579. RegCloseKey(hk);
  580. return f;
  581. }
  582. //=--------------------------------------------------------------------------=
  583. // DeleteKeyAndSubKeys
  584. //=--------------------------------------------------------------------------=
  585. // delete's a key and all of it's subkeys.
  586. //
  587. // Parameters:
  588. // HKEY - [in] delete the descendant specified
  589. // LPSTR - [in] i'm the descendant specified
  590. //
  591. // Output:
  592. // BOOL - TRUE OK, FALSE baaaad.
  593. //
  594. // Notes:
  595. // - I don't feel too bad about implementing this recursively, since the
  596. // depth isn't likely to get all the great.
  597. // - Despite the win32 docs claiming it does, RegDeleteKey doesn't seem to
  598. // work with sub-keys under windows 95.
  599. //
  600. BOOL DeleteKeyAndSubKeys
  601. (
  602. HKEY hkIn,
  603. LPSTR pszSubKey
  604. )
  605. {
  606. HKEY hk;
  607. char szTmp[MAX_PATH];
  608. DWORD dwTmpSize;
  609. long l;
  610. BOOL f;
  611. int x;
  612. l = RegOpenKeyEx(hkIn, pszSubKey, 0, KEY_ALL_ACCESS, &hk);
  613. if (l != ERROR_SUCCESS) return FALSE;
  614. // loop through all subkeys, blowing them away.
  615. //
  616. f = TRUE;
  617. x = 0;
  618. while (f) {
  619. dwTmpSize = MAX_PATH;
  620. l = RegEnumKeyEx(hk, x, szTmp, &dwTmpSize, 0, NULL, NULL, NULL);
  621. if (l != ERROR_SUCCESS) break;
  622. f = DeleteKeyAndSubKeys(hk, szTmp);
  623. x++;
  624. }
  625. // there are no subkeys left, [or we'll just generate an error and return FALSE].
  626. // let's go blow this dude away.
  627. //
  628. RegCloseKey(hk);
  629. l = RegDeleteKey(hkIn, pszSubKey);
  630. return (l == ERROR_SUCCESS) ? TRUE : FALSE;
  631. }
  632. //=--------------------------------------------------------------------------=
  633. // Conversion Routines
  634. //=--------------------------------------------------------------------------=
  635. // the following stuff is stuff used for the various conversion routines.
  636. //
  637. #define HIMETRIC_PER_INCH 2540
  638. #define MAP_PIX_TO_LOGHIM(x,ppli) ( (HIMETRIC_PER_INCH*(x) + ((ppli)>>1)) / (ppli) )
  639. #define MAP_LOGHIM_TO_PIX(x,ppli) ( ((ppli)*(x) + HIMETRIC_PER_INCH/2) / HIMETRIC_PER_INCH )
  640. static int s_iXppli; // Pixels per logical inch along width
  641. static int s_iYppli; // Pixels per logical inch along height
  642. static BYTE s_fGotScreenMetrics; // Are above valid?
  643. //=--------------------------------------------------------------------------=
  644. // GetScreenMetrics
  645. //=--------------------------------------------------------------------------=
  646. // private function we call to set up various metrics the conversion routines
  647. // will use.
  648. //
  649. // Notes:
  650. // BUGBUG: 26-Sep-1997 [ralphw] This will fail miserably if the user changes
  651. // screen resolutions. Doah!
  652. static void GetScreenMetrics (void)
  653. {
  654. if (s_fGotScreenMetrics)
  655. return;
  656. // we want the metrics for the screen
  657. HDC hdc = CreateIC("DISPLAY", NULL, NULL, NULL);
  658. ASSERT(hdc);
  659. s_iXppli = GetDeviceCaps(hdc, LOGPIXELSX);
  660. s_iYppli = GetDeviceCaps(hdc, LOGPIXELSY);
  661. DeleteDC( hdc );
  662. s_fGotScreenMetrics = TRUE;
  663. }
  664. //=--------------------------------------------------------------------------=
  665. // HiMetricToPixel
  666. //=--------------------------------------------------------------------------=
  667. // converts from himetric to Pixels.
  668. //
  669. // Parameters:
  670. // const SIZEL * - [in] dudes in himetric
  671. // SIZEL * - [out] size in pixels.
  672. //
  673. // Notes:
  674. //
  675. void HiMetricToPixel(const SIZEL * lpSizeInHiMetric, SIZE* lpSizeInPix)
  676. {
  677. GetScreenMetrics();
  678. // We got logical HIMETRIC along the display, convert them to pixel units
  679. lpSizeInPix->cx = MAP_LOGHIM_TO_PIX(lpSizeInHiMetric->cx, s_iXppli);
  680. lpSizeInPix->cy = MAP_LOGHIM_TO_PIX(lpSizeInHiMetric->cy, s_iYppli);
  681. }
  682. //=--------------------------------------------------------------------------=
  683. // PixelToHiMetric
  684. //=--------------------------------------------------------------------------=
  685. // converts from pixels to himetric.
  686. //
  687. // Parameters:
  688. // const SIZEL * - [in] size in pixels
  689. // SIZEL * - [out] size in himetric
  690. void PixelToHiMetric(const SIZEL * lpSizeInPix, LPSIZEL lpSizeInHiMetric)
  691. {
  692. GetScreenMetrics();
  693. // We got pixel units, convert them to logical HIMETRIC along the display
  694. lpSizeInHiMetric->cx = MAP_PIX_TO_LOGHIM(lpSizeInPix->cx, s_iXppli);
  695. lpSizeInHiMetric->cy = MAP_PIX_TO_LOGHIM(lpSizeInPix->cy, s_iYppli);
  696. }
  697. //=--------------------------------------------------------------------------=
  698. // _MakePath
  699. //=--------------------------------------------------------------------------=
  700. // little helper routine for RegisterLocalizedTypeLibs and GetResourceHandle.
  701. // not terrilby efficient or smart, but it's registration code, so we don't
  702. // really care.
  703. //
  704. // Notes:
  705. //
  706. void _MakePath
  707. (
  708. LPSTR pszFull,
  709. const char * pszName,
  710. LPSTR pszOut
  711. )
  712. {
  713. LPSTR psz;
  714. LPSTR pszLast;
  715. strcpy(pszOut, pszFull);
  716. psz = pszLast = pszOut;
  717. while (*psz) {
  718. if (*psz == '\\')
  719. pszLast = AnsiNext(psz);
  720. psz = AnsiNext(psz);
  721. }
  722. // got the last \ character, so just go and replace the name.
  723. //
  724. strcpy(pszLast, pszName);
  725. }
  726. /***************************************************************************
  727. FUNCTION: GetStringResource
  728. PURPOSE: Copy a string resource to a buffer, returning a pointer
  729. to that buffer
  730. PARAMETERS:
  731. idString -- resource id
  732. RETURNS: Pointer to the string containing the buffer
  733. COMMENTS:
  734. Note that the same buffer is used each time. You will need to
  735. duplicate the returned pointer if you need to call this function
  736. again before the previous value is no longer needed.
  737. ***************************************************************************/
  738. PCSTR GetStringResource(int idString)
  739. {
  740. static TCHAR pszStringBuf[MAX_STRING_RESOURCE_LEN + 1];
  741. pszStringBuf[0] = 0;
  742. // special case W2K
  743. //
  744. // The purpose of this code is to get the resource string in Unicode
  745. // and then convert to ANSI using the UI codepage when running under W2K.
  746. //
  747. // The narrow GetStringResource() API fails under MUI configurations
  748. // due to it using the default system locale rather than the UI locale
  749. // for the conversion to ANSI.
  750. //
  751. if(g_bWinNT5)
  752. {
  753. const WCHAR *pswString = GetStringResourceW(idString);
  754. static char pszAnsiStringBuf[MAX_STRING_RESOURCE_LEN + 1];
  755. if(pswString)
  756. {
  757. DWORD cp = CodePageFromLCID(MAKELCID(_Module.m_Language.GetUiLanguage(),SORT_DEFAULT));
  758. pszAnsiStringBuf[0] = 0;
  759. WideCharToMultiByte (cp, 0, pswString, -1, pszAnsiStringBuf, sizeof(pszAnsiStringBuf), NULL, NULL);
  760. return pszAnsiStringBuf;
  761. }
  762. else
  763. return pszStringBuf;
  764. }
  765. if (LoadString(_Module.GetResourceInstance(), idString, pszStringBuf, MAX_STRING_RESOURCE_LEN) == 0) {
  766. #ifdef _DEBUG
  767. wsprintf(pszStringBuf, "invalid string id #%u", idString);
  768. MsgBox(pszStringBuf);
  769. #endif
  770. pszStringBuf[0] = '\0';
  771. }
  772. return (PCSTR) pszStringBuf;
  773. }
  774. /***************************************************************************
  775. FUNCTION: GetStringResource
  776. PURPOSE: Copy a string resource to a buffer, returning a pointer
  777. to that buffer
  778. PARAMETERS:
  779. idString -- resource id
  780. hInstance -- resource instance
  781. RETURNS: Pointer to the string containing the buffer
  782. COMMENTS:
  783. Note that the same buffer is used each time. You will need to
  784. duplicate the returned pointer if you need to call this function
  785. again before the previous value is no longer needed.
  786. ***************************************************************************/
  787. PCSTR GetStringResource(int idString, HINSTANCE hInstance)
  788. {
  789. static TCHAR pszStringBuf[MAX_STRING_RESOURCE_LEN + 1];
  790. pszStringBuf[0] = 0;
  791. // special case W2K
  792. //
  793. // The purpose of this code is to get the resource string in Unicode
  794. // and then convert to ANSI using the UI codepage when running under W2K.
  795. //
  796. // The narrow GetStringResource() API fails under MUI configurations
  797. // due to it using the default system locale rather than the UI locale
  798. // for the conversion to ANSI.
  799. //
  800. if(g_bWinNT5)
  801. {
  802. const WCHAR *pswString = GetStringResourceW(idString, hInstance);
  803. static char pszAnsiStringBuf[MAX_STRING_RESOURCE_LEN + 1];
  804. if(pswString)
  805. {
  806. DWORD cp = CodePageFromLCID(MAKELCID(_Module.m_Language.GetUiLanguage(),SORT_DEFAULT));
  807. pszAnsiStringBuf[0] = 0;
  808. WideCharToMultiByte (cp, 0, pswString, -1, pszAnsiStringBuf, sizeof(pszAnsiStringBuf), NULL, NULL);
  809. return pszAnsiStringBuf;
  810. }
  811. else
  812. return pszStringBuf;
  813. }
  814. if (LoadString(hInstance, idString, pszStringBuf, MAX_STRING_RESOURCE_LEN) == 0) {
  815. #ifdef _DEBUG
  816. wsprintf(pszStringBuf, "invalid string id #%u", idString);
  817. MsgBox(pszStringBuf);
  818. #endif
  819. pszStringBuf[0] = '\0';
  820. }
  821. return (PCSTR) pszStringBuf;
  822. }
  823. PCWSTR GetStringResourceW(int idString)
  824. {
  825. static WCHAR pszStringBuf[MAX_STRING_RESOURCE_LEN + 1];
  826. if (0 == ::LoadStringW(_Module.GetResourceInstance(), idString, pszStringBuf, MAX_STRING_RESOURCE_LEN))
  827. {
  828. if (ERROR_CALL_NOT_IMPLEMENTED == ::GetLastError())
  829. {
  830. PCSTR pszA = GetStringResource(idString);
  831. MultiByteToWideChar(CP_ACP, 0, pszA, -1, pszStringBuf, MAX_STRING_RESOURCE_LEN);
  832. }
  833. else
  834. {
  835. ASSERT(0); // bad string id, probably
  836. pszStringBuf[0] = '\0';
  837. }
  838. }
  839. return (PCWSTR) pszStringBuf;
  840. }
  841. // GetStringResourceW
  842. //
  843. PCWSTR GetStringResourceW(int idString, HINSTANCE hInstance)
  844. {
  845. static WCHAR pszStringBuf[MAX_STRING_RESOURCE_LEN + 1];
  846. if (0 == ::LoadStringW(hInstance, idString, pszStringBuf, MAX_STRING_RESOURCE_LEN))
  847. {
  848. if (ERROR_CALL_NOT_IMPLEMENTED == ::GetLastError())
  849. {
  850. PCSTR pszA = GetStringResource(idString, hInstance);
  851. MultiByteToWideChar(CP_ACP, 0, pszA, -1, pszStringBuf, MAX_STRING_RESOURCE_LEN);
  852. }
  853. else
  854. {
  855. ASSERT(0); // bad string id, probably
  856. pszStringBuf[0] = '\0';
  857. }
  858. }
  859. return (PCWSTR) pszStringBuf;
  860. }
  861. /***************************************************************************
  862. FUNCTION: Atoi
  863. PURPOSE: Convert string to an integer
  864. PARAMETERS:
  865. psz
  866. RETURNS:
  867. COMMENTS:
  868. Taken from C runtime code -- this code makes no function calls, and
  869. assumes there is no such thing as a DBCS number. It will read either
  870. decimal or hex (preceeded with an 0x)
  871. MODIFICATION DATES:
  872. 04-Dec-1997 [ralphw]
  873. 15-Aug-1997 [ralphw] Support hex digits
  874. ***************************************************************************/
  875. int FASTCALL Atoi(PCSTR psz)
  876. {
  877. // skip whitespace
  878. while (*psz == ' ' || *psz == '\t')
  879. ++psz;
  880. if (!*psz)
  881. return 0;
  882. int c = (int) (unsigned char) *psz++;
  883. int sign = c; // save sign indication
  884. if (c == '-' || c == '+')
  885. c = (int) (unsigned char) *psz++; // skip sign
  886. int total = 0;
  887. if (c == '0' && psz[0] == 'x') {
  888. psz++; // skip over the 'x'
  889. c = (int) (unsigned char) *psz++; // skip sign
  890. for (;;) {
  891. if (c >= '0' && c <= '9') {
  892. total = 16 * total + (c - '0');
  893. c = (int)(unsigned char)*psz++;
  894. }
  895. else if (c >= 'a' && c <= 'f') {
  896. total = 16 * total + ((c - 'a') + 10);
  897. c = (int)(unsigned char)*psz++;
  898. }
  899. else if (c >= 'A' && c <= 'F') {
  900. total = 16 * total + ((c - 'A') + 10);
  901. c = (int)(unsigned char)*psz++;
  902. }
  903. else {
  904. if (sign == '-')
  905. return -total;
  906. else
  907. return total;
  908. }
  909. }
  910. }
  911. while (c >= '0' && c <= '9') {
  912. total = 10 * total + (c - '0');
  913. c = (int)(unsigned char)*psz++;
  914. }
  915. if (sign == '-')
  916. return -total;
  917. else
  918. return total;
  919. }
  920. void OOM(void)
  921. {
  922. #ifdef _DEBUG
  923. ASSERT_COMMENT(FALSE, "Out of memory.");
  924. #else
  925. char szMsg[256];
  926. LoadString(_Module.GetResourceInstance(), IDS_OOM, szMsg, sizeof(szMsg));
  927. // Task modal to allow other applications to run. Note that this will
  928. // disable the caller's windows.
  929. MessageBox(GetActiveWindow(), szMsg, "", MB_OK | MB_TASKMODAL | MB_ICONHAND);
  930. ExitProcess((UINT) -1);
  931. #endif
  932. }
  933. int MsgBox(int idString, UINT nType)
  934. {
  935. if(g_bWinNT5)
  936. {
  937. WCHAR *pszString;
  938. WCHAR wcString[(MAX_STRING_RESOURCE_LEN + 1) + MAX_PATH + 64];
  939. WCHAR wcTitle[(MAX_STRING_RESOURCE_LEN + 1) + MAX_PATH + 64];
  940. wcTitle[0] = 0;
  941. pszString = (WCHAR *) GetStringResourceW(idString);
  942. if(!pszString)
  943. {
  944. #ifdef _DEBUG
  945. char szMsg[(MAX_STRING_RESOURCE_LEN + 1) + MAX_PATH + 64];
  946. wsprintf(szMsg, "invalid string id #%u", idString);
  947. DBWIN(szMsg);
  948. #endif
  949. return 0;
  950. }
  951. else
  952. wcscpy(wcString,pszString);
  953. char *pszTitle = _Resource.MsgBoxTitle();
  954. if(pszTitle)
  955. {
  956. DWORD cp = CodePageFromLCID(MAKELCID(_Module.m_Language.GetUiLanguage(),SORT_DEFAULT));
  957. MultiByteToWideChar(cp, 0, pszTitle, -1, wcTitle, sizeof(wcTitle));
  958. }
  959. else
  960. return 0;
  961. return MessageBoxW(GetActiveWindow(), wcString, wcTitle, nType | g_fuBiDiMessageBox);
  962. }
  963. else
  964. {
  965. CStr pszTemp = (char *) GetStringResource(idString);
  966. if(!pszTemp.psz)
  967. {
  968. #ifdef _DEBUG
  969. char szMsg[(MAX_STRING_RESOURCE_LEN + 1) + MAX_PATH + 64];
  970. wsprintf(szMsg, "invalid string id #%u", idString);
  971. DBWIN(szMsg);
  972. #endif
  973. return 0;
  974. }
  975. return MessageBox(GetActiveWindow(), pszTemp, _Resource.MsgBoxTitle(), nType | g_fuBiDiMessageBox);
  976. }
  977. }
  978. int MsgBox(PCSTR pszMsg, UINT nType)
  979. {
  980. return MessageBox(GetActiveWindow(), pszMsg, _Resource.MsgBoxTitle(), nType | g_fuBiDiMessageBox);
  981. }
  982. int MsgBox(int idFormatString, PCSTR pszSubString, UINT nType)
  983. {
  984. CStr csz(idFormatString, pszSubString);
  985. return MessageBox(GetActiveWindow(), csz.psz, _Resource.MsgBoxTitle(), nType);
  986. }
  987. void AddTrailingBackslash(PSTR psz)
  988. {
  989. int sPos;
  990. if (psz != NULL && *psz != '\0') {
  991. if (g_fDBCSSystem) {
  992. PSTR pszEnd = psz + strlen(psz);
  993. if (*(CharPrev(psz, pszEnd)) != '\\' &&
  994. *(CharPrev(psz, pszEnd)) != '/' &&
  995. *(CharPrev(psz, pszEnd)) != ':') {
  996. *pszEnd++ = '\\';
  997. *pszEnd++ = '\0';
  998. }
  999. }
  1000. else {
  1001. sPos = (int)strlen(psz) - 1;
  1002. if (psz[sPos] != '\\' && psz[sPos] != '/' && psz[sPos] != ':') {
  1003. psz[sPos + 1] = '\\';
  1004. psz[sPos + 2] = '\0';
  1005. }
  1006. }
  1007. }
  1008. }
  1009. #if 0
  1010. /***************************************************************************
  1011. FUNCTION: StrChr
  1012. PURPOSE: DBCS-capable version of strchr
  1013. PARAMETERS:
  1014. pszString
  1015. ch
  1016. RETURNS: pointer to the character
  1017. COMMENTS: This can NOT find a DBCS character. It can only be used to
  1018. find a SBCS character imbedded in a DBCS character string.
  1019. MODIFICATION DATES:
  1020. 29-Jul-1994 [ralphw]
  1021. ***************************************************************************/
  1022. extern "C" PSTR StrChr(PCSTR pszString, char ch)
  1023. {
  1024. if (!g_fDBCSSystem)
  1025. return strchr(pszString, ch);
  1026. while (*pszString) {
  1027. while (IsDBCSLeadByte(*pszString))
  1028. pszString += 2;
  1029. if (*pszString == ch)
  1030. return (PSTR) pszString;
  1031. else if (!*pszString)
  1032. return NULL;
  1033. pszString++;
  1034. }
  1035. return NULL;
  1036. }
  1037. #endif
  1038. extern "C" PSTR StrRChr(PCSTR pszString, char ch)
  1039. {
  1040. PSTR psz = StrChr(pszString, ch);
  1041. PSTR pszLast;
  1042. if (!psz)
  1043. return NULL;
  1044. do {
  1045. pszLast = psz;
  1046. psz = StrChr(pszLast + 1, ch);
  1047. } while (psz);
  1048. return pszLast;
  1049. }
  1050. extern "C" PSTR FirstNonSpace(PCSTR psz)
  1051. {
  1052. // note, for various bits of code to work throughout the HH project,
  1053. // this function cannot return NULL if the first non-space does not exist,
  1054. // instead the caller may count on this function returning non-NULL and
  1055. // thus we need to pass back a pointer to the terminating NULL character
  1056. // instead of simply a NULL value.
  1057. if( !psz /*|| !*psz*/ )
  1058. return NULL;
  1059. if (g_fDBCSSystem) {
  1060. while (!IsDBCSLeadByte(*psz) && (*psz == ' ' || *psz == '\t'))
  1061. psz++;
  1062. return (PSTR) psz;
  1063. }
  1064. while(*psz == ' ' || *psz == '\t')
  1065. psz++;
  1066. return (PSTR) psz;
  1067. }
  1068. WCHAR *FirstNonSpaceW(WCHAR *psz)
  1069. {
  1070. // note, for various bits of code to work throughout the HH project,
  1071. // this function cannot return NULL if the first non-space does not exist,
  1072. // instead the caller may count on this function returning non-NULL and
  1073. // thus we need to pass back a pointer to the terminating NULL character
  1074. // instead of simply a NULL value.
  1075. if( !psz /*|| !*psz*/ )
  1076. return NULL;
  1077. while(*psz == L' ' || *psz == L'\t')
  1078. psz++;
  1079. return psz;
  1080. }
  1081. PSTR SzTrimSz(PSTR pszOrg)
  1082. {
  1083. if (!pszOrg)
  1084. return NULL;
  1085. // Skip over leading whitespace
  1086. if (g_fDBCSSystem) {
  1087. PSTR psz = pszOrg;
  1088. while (!IsDBCSLeadByte(*psz) && IsSpace(*psz))
  1089. psz++;
  1090. if (psz != pszOrg)
  1091. strcpy(pszOrg, psz);
  1092. }
  1093. else if (IsSpace(*pszOrg))
  1094. strcpy(pszOrg, FirstNonSpace(pszOrg));
  1095. RemoveTrailingSpaces(pszOrg);
  1096. return pszOrg;
  1097. }
  1098. void RemoveTrailingSpaces(PSTR pszString)
  1099. {
  1100. if (!g_fDBCSSystem) {
  1101. PSTR psz = pszString + strlen(pszString) - 1;
  1102. while (IsSpace(*psz)) {
  1103. if (--psz <= pszString) {
  1104. *pszString = '\0';
  1105. return;
  1106. }
  1107. }
  1108. psz[1] = '\0';
  1109. }
  1110. else {
  1111. /*
  1112. * Removing trailing spaces in DBCS requires stepping through
  1113. * from the beginning of the string since we can't know if a
  1114. * trailing space is really a space or the second byte of a lead
  1115. * byte.
  1116. */
  1117. PSTR psz = pszString + strlen(pszString) - 1;
  1118. while (IsSpace(*psz) && psz > pszString + 2 &&
  1119. !IsDBCSLeadByte(psz[-1])) {
  1120. if (--psz <= pszString) {
  1121. *pszString = '\0';
  1122. return;
  1123. }
  1124. }
  1125. psz[1] = '\0';
  1126. }
  1127. }
  1128. /***************************************************************************
  1129. FUNCTION: GetLeftOfEquals
  1130. PURPOSE: Allocate a string and copy everything to the left of the
  1131. equal character to that string. If there is no equal character,
  1132. return NULL.
  1133. PARAMETERS:
  1134. pszString -- note that we do actually modify this string, but we
  1135. restore it before returning, hence we use PCSTR
  1136. so the compiler thinks it is unmodified.
  1137. RETURNS: Allocated memory or NULL
  1138. COMMENTS:
  1139. DBCS enabled. A backslash character may be used to escape (ignore)
  1140. the equals character.
  1141. MODIFICATION DATES:
  1142. 07-Jul-1997 [ralphw]
  1143. ***************************************************************************/
  1144. PSTR GetLeftOfEquals(PCSTR pszString)
  1145. {
  1146. PSTR pszEqual = (PSTR) FindEqCharacter(pszString);
  1147. if (!pszEqual)
  1148. return NULL;
  1149. *pszEqual = '\0';
  1150. PSTR pszLeft = (PSTR) lcStrDup(pszString);
  1151. RemoveTrailingSpaces(pszLeft);
  1152. *pszEqual = '=';
  1153. return pszLeft;
  1154. }
  1155. /***************************************************************************
  1156. FUNCTION: FindEqCharacter
  1157. PURPOSE: Return a pointer to the '=' character in a line
  1158. PARAMETERS:
  1159. pszLine
  1160. RETURNS: Pointer to '=' or NULL if there is no '='
  1161. COMMENTS:
  1162. We DO modify pszLine in spite of it's being marked as PCSTR, but
  1163. we always put it back the way we found it before returning. So, you
  1164. can't use this function on a string stored in a code segment.
  1165. MODIFICATION DATES:
  1166. 10-Jul-1997 [ralphw]
  1167. ***************************************************************************/
  1168. PCSTR FindEqCharacter(PCSTR pszLine)
  1169. {
  1170. PSTR pszEqual = (PSTR) pszLine;
  1171. for (;;) {
  1172. pszEqual = StrChr(pszEqual, '=');
  1173. if (!pszEqual)
  1174. return NULL;
  1175. *pszEqual = '\0';
  1176. /*
  1177. * We need to find out if the previous character was a backslash.
  1178. * You can't back up in a DBCS string, so we just start from the
  1179. * first and search for the last backslash. Don't be fooled into
  1180. * thinking CharPrev() will do the trick -- it will, but by doing
  1181. * the same thing we do here more efficiently (start from the
  1182. * beginning of the string).
  1183. */
  1184. PSTR pszBackSlash = StrRChr(pszLine, '\\');
  1185. if (pszBackSlash && pszBackSlash == (pszEqual - 1)) {
  1186. *pszEqual = '='; // put the character back
  1187. pszEqual++;
  1188. continue; // keep looking;
  1189. }
  1190. *pszEqual = '='; // put the character back
  1191. return pszEqual;
  1192. }
  1193. }
  1194. /***************************************************************************
  1195. FUNCTION: Itoa
  1196. PURPOSE: Convert a positive interger to a base 10 string
  1197. PARAMETERS:
  1198. val
  1199. pszDst
  1200. RETURNS:
  1201. COMMENTS:
  1202. Taken from C runtime code, modified for speed and size
  1203. MODIFICATION DATES:
  1204. 04-Dec-1997 [ralphw]
  1205. ***************************************************************************/
  1206. void FASTCALL Itoa(int val, PSTR pszDst)
  1207. {
  1208. if (val < 0) {
  1209. *pszDst++ = '-';
  1210. val = abs(val);
  1211. }
  1212. PSTR firstdig = pszDst; // save pointer to first digit
  1213. do {
  1214. *pszDst++ = ((char) (val % 10)) + '0';
  1215. val /= 10; // get next digit
  1216. } while (val > 0);
  1217. /*
  1218. * We now have the digit of the number in the buffer, but in reverse
  1219. * order. Thus we reverse them now.
  1220. */
  1221. *pszDst-- = '\0'; // terminate string; p points to last digit
  1222. do {
  1223. char temp = *pszDst;
  1224. *pszDst = *firstdig;
  1225. *firstdig = temp; // swap *p and *firstdig
  1226. --pszDst;
  1227. ++firstdig; // advance to next two digits
  1228. } while (firstdig < pszDst); // repeat until halfway
  1229. }
  1230. #if 0
  1231. /***************************************************************************
  1232. FUNCTION: stristr
  1233. PURPOSE: Case-insensitive search for a sub string in a main string
  1234. PARAMETERS:
  1235. pszMain
  1236. pszSub
  1237. RETURNS:
  1238. COMMENTS:
  1239. Not tested
  1240. MODIFICATION DATES:
  1241. 28-Mar-1994 [ralphw]
  1242. ***************************************************************************/
  1243. // REVIEW: should replace this with a version that doesn't use CompareString,
  1244. // since this function is typically used to parse sitemap files -- the object
  1245. // names of a sitemap file will always be in english.
  1246. extern "C"
  1247. PSTR stristr(PCSTR pszMain, PCSTR pszSub)
  1248. {
  1249. if (!pszMain || !pszSub)
  1250. return NULL;
  1251. PSTR pszCur = (PSTR) pszMain;
  1252. char ch = ToLower(*pszSub);
  1253. int cb = strlen(pszSub);
  1254. if (g_fDBCSSystem) {
  1255. for (;;) {
  1256. while (ToLower(*pszCur) != ch && *pszCur)
  1257. pszCur = CharNext(pszCur);
  1258. if (!*pszCur)
  1259. return NULL;
  1260. if (CompareString(g_lcidSystem, NORM_IGNORECASE,
  1261. pszCur, cb, pszSub, cb) == 2)
  1262. return pszCur;
  1263. pszCur = CharNext(pszCur);
  1264. }
  1265. }
  1266. else {
  1267. for (;;) {
  1268. while (ToLower(*pszCur) != ch && *pszCur)
  1269. pszCur++;
  1270. if (!*pszCur)
  1271. return NULL;
  1272. if (CompareString(g_lcidSystem, NORM_IGNORECASE,
  1273. pszCur, cb, pszSub, cb) == 2)
  1274. return pszCur;
  1275. pszCur++;
  1276. }
  1277. }
  1278. }
  1279. #endif
  1280. // NOTE: this only works with Unicode strings
  1281. BOOL IsSamePrefix(PCWSTR pwszMainIn, PCWSTR pwszSubIn, int cchPrefix)
  1282. {
  1283. if( !pwszMainIn || !pwszSubIn )
  1284. return FALSE;
  1285. const WCHAR* pwszMain = pwszMainIn;
  1286. const WCHAR* pwszSub = pwszSubIn;
  1287. if( cchPrefix == -1 )
  1288. cchPrefix = lstrlenW(pwszSub);
  1289. // convert both to lowercase and then compare the first few characters
  1290. // in pwszSub to pwszMain
  1291. while( cchPrefix-- ) {
  1292. // if we hit the end of the strings, quit and return
  1293. // TRUE if both NULL or FALSE otherwise
  1294. if( !(*pwszSub) || !(*pwszMain) ) {
  1295. if( (*pwszSub) == (*pwszMain) )
  1296. return TRUE;
  1297. else
  1298. return FALSE;
  1299. }
  1300. WCHAR wchSub = *(pwszSub++);
  1301. WCHAR wchMain = *(pwszMain++);
  1302. CharLowerW( &wchSub );
  1303. CharLowerW( &wchMain );
  1304. // if not the same then quit and return FALSE
  1305. if( wchSub != wchMain )
  1306. return FALSE;
  1307. }
  1308. return TRUE;
  1309. }
  1310. // NOTE: this only works with ANSI strings
  1311. BOOL IsSamePrefix(PCSTR pszMain, PCSTR pszSub, int cbPrefix)
  1312. {
  1313. if (!pszMain || !pszSub)
  1314. return FALSE;
  1315. if (cbPrefix == -1)
  1316. cbPrefix = (int)strlen(pszSub);
  1317. int f, l;
  1318. while (cbPrefix--) {
  1319. if (((f = (BYTE) (*(pszMain++))) >= 'A') && (f <= 'Z'))
  1320. f -= 'A' - 'a';
  1321. if (((l = (BYTE) (*(pszSub++))) >= 'A') && (l <= 'Z'))
  1322. l -= 'A' - 'a';
  1323. if (f != l)
  1324. return FALSE;
  1325. else if (!f)
  1326. return (f == l);
  1327. }
  1328. return TRUE;
  1329. }
  1330. #ifndef _DEBUG
  1331. #pragma optimize("t", on)
  1332. #endif
  1333. int FASTCALL CompareIntPointers(const void *pval1, const void *pval2)
  1334. {
  1335. #ifdef _DEBUG
  1336. int val1 = *(int*) pval1;
  1337. int val2 = *(int*) pval2;
  1338. #endif
  1339. return *(int*) pval1 - *(int*) pval2;
  1340. }
  1341. /*
  1342. * this parameter defines the cutoff between using quick sort and insertion
  1343. * sort for arrays; arrays with lengths shorter or equal to the below value
  1344. * use insertion sort
  1345. */
  1346. #define CUTOFF 8 // testing shows that this is good value
  1347. void INLINE Swap(void* pb1, void* pb2, UINT width)
  1348. {
  1349. BYTE tmp[256];
  1350. ASSERT(width < sizeof(tmp));
  1351. CopyMemory(tmp, pb1, width);
  1352. CopyMemory(pb1, pb2, width);
  1353. CopyMemory(pb2, tmp, width);
  1354. }
  1355. static void InsertionSort(char *lo, char *hi, unsigned width,
  1356. int (FASTCALL *compare)(const void *, const void *))
  1357. {
  1358. char *p, *max;
  1359. /*
  1360. * Note: in assertions below, i and j are alway inside original bound
  1361. * of array to sort.
  1362. */
  1363. while (hi > lo) {
  1364. /* A[i] <= A[j] for i <= j, j > hi */
  1365. max = lo;
  1366. for (p = lo + width; p <= hi; p += width) {
  1367. /* A[i] <= A[max] for lo <= i < p */
  1368. if (compare(p, max) > 0) {
  1369. max = p;
  1370. }
  1371. /* A[i] <= A[max] for lo <= i <= p */
  1372. }
  1373. /* A[i] <= A[max] for lo <= i <= hi */
  1374. Swap(max, hi, width);
  1375. /* A[i] <= A[hi] for i <= hi, so A[i] <= A[j] for i <= j, j >= hi */
  1376. hi -= width;
  1377. // A[i] <= A[j] for i <= j, j > hi, loop top condition established
  1378. }
  1379. /* A[i] <= A[j] for i <= j, j > lo, which implies A[i] <= A[j] for i < j,
  1380. so array is sorted */
  1381. }
  1382. void QSort(void *pbase, UINT num, UINT width,
  1383. int (FASTCALL *compare)(const void *, const void *))
  1384. {
  1385. char *lo, *hi; // ends of sub-array currently sorting
  1386. char *mid; // points to middle of subarray
  1387. char *loguy, *higuy; // traveling pointers for partition step
  1388. unsigned size; // size of the sub-array
  1389. char *lostk[30], *histk[30];
  1390. int stkptr; // stack for saving sub-array to be processed
  1391. /* Note: the number of stack entries required is no more than
  1392. 1 + log2(size), so 30 is sufficient for any array */
  1393. if (num < 2 || width == 0)
  1394. return; // nothing to do
  1395. stkptr = 0; // initialize stack
  1396. lo = (char*) pbase;
  1397. hi = (char *) pbase + width * (num-1); // initialize limits
  1398. /* this entry point is for pseudo-recursion calling: setting
  1399. lo and hi and jumping to here is like recursion, but stkptr is
  1400. prserved, locals aren't, so we preserve stuff on the stack */
  1401. recurse:
  1402. size = (unsigned)((hi - lo) / width + 1); // number of el's to sort
  1403. // below a certain size, it is faster to use a O(n^2) sorting method
  1404. if (size <= CUTOFF) {
  1405. InsertionSort(lo, hi, width, compare);
  1406. }
  1407. else {
  1408. /*
  1409. * First we pick a partititioning element. The efficiency of the
  1410. * algorithm demands that we find one that is approximately the
  1411. * median of the values, but also that we select one fast. Using the
  1412. * first one produces bad performace if the array is already sorted,
  1413. * so we use the middle one, which would require a very wierdly
  1414. * arranged array for worst case performance. Testing shows that a
  1415. * median-of-three algorithm does not, in general, increase
  1416. * performance.
  1417. */
  1418. mid = lo + (size / 2) * width; // find middle element
  1419. Swap(mid, lo, width); // swap it to beginning of array
  1420. /*
  1421. * We now wish to partition the array into three pieces, one
  1422. * consisiting of elements <= partition element, one of elements
  1423. * equal to the parition element, and one of element >= to it. This
  1424. * is done below; comments indicate conditions established at every
  1425. * step.
  1426. */
  1427. loguy = lo;
  1428. higuy = hi + width;
  1429. /*
  1430. * Note that higuy decreases and loguy increases on every
  1431. * iteration, so loop must terminate.
  1432. */
  1433. for (;;) {
  1434. /* lo <= loguy < hi, lo < higuy <= hi + 1,
  1435. A[i] <= A[lo] for lo <= i <= loguy,
  1436. A[i] >= A[lo] for higuy <= i <= hi */
  1437. do {
  1438. loguy += width;
  1439. } while (loguy <= hi && compare(loguy, lo) <= 0);
  1440. /* lo < loguy <= hi+1, A[i] <= A[lo] for lo <= i < loguy,
  1441. either loguy > hi or A[loguy] > A[lo] */
  1442. do {
  1443. higuy -= width;
  1444. } while (higuy > lo && compare(higuy, lo) >= 0);
  1445. /* lo-1 <= higuy <= hi, A[i] >= A[lo] for higuy < i <= hi,
  1446. either higuy <= lo or A[higuy] < A[lo] */
  1447. if (higuy < loguy)
  1448. break;
  1449. /* if loguy > hi or higuy <= lo, then we would have exited, so
  1450. A[loguy] > A[lo], A[higuy] < A[lo],
  1451. loguy < hi, highy > lo */
  1452. Swap(loguy, higuy, width);
  1453. /* A[loguy] < A[lo], A[higuy] > A[lo]; so condition at top
  1454. of loop is re-established */
  1455. }
  1456. /* A[i] >= A[lo] for higuy < i <= hi,
  1457. A[i] <= A[lo] for lo <= i < loguy,
  1458. higuy < loguy, lo <= higuy <= hi
  1459. implying:
  1460. A[i] >= A[lo] for loguy <= i <= hi,
  1461. A[i] <= A[lo] for lo <= i <= higuy,
  1462. A[i] = A[lo] for higuy < i < loguy */
  1463. Swap(lo, higuy, width); // put partition element in place
  1464. /* OK, now we have the following:
  1465. A[i] >= A[higuy] for loguy <= i <= hi,
  1466. A[i] <= A[higuy] for lo <= i < higuy
  1467. A[i] = A[lo] for higuy <= i < loguy */
  1468. /* We've finished the partition, now we want to sort the subarrays
  1469. [lo, higuy-1] and [loguy, hi].
  1470. We do the smaller one first to minimize stack usage.
  1471. We only sort arrays of length 2 or more.*/
  1472. if ( higuy - 1 - lo >= hi - loguy ) {
  1473. if (lo + width < higuy) {
  1474. lostk[stkptr] = lo;
  1475. histk[stkptr] = higuy - width;
  1476. ++stkptr;
  1477. } // save big recursion for later
  1478. if (loguy < hi) {
  1479. lo = loguy;
  1480. goto recurse; // do small recursion
  1481. }
  1482. }
  1483. else {
  1484. if (loguy < hi) {
  1485. lostk[stkptr] = loguy;
  1486. histk[stkptr] = hi;
  1487. ++stkptr; // save big recursion for later
  1488. }
  1489. if (lo + width < higuy) {
  1490. hi = higuy - width;
  1491. goto recurse; // do small recursion
  1492. }
  1493. }
  1494. }
  1495. /*
  1496. * We have sorted the array, except for any pending sorts on the
  1497. * stack. Check if there are any, and do them.
  1498. */
  1499. --stkptr;
  1500. if (stkptr >= 0) {
  1501. lo = lostk[stkptr];
  1502. hi = histk[stkptr];
  1503. goto recurse; // pop subarray from stack
  1504. }
  1505. else
  1506. return; // all subarrays done
  1507. }
  1508. // C Runtime stuff
  1509. int __cdecl _purecall()
  1510. {
  1511. #ifdef _DEBUG
  1512. DebugBreak();
  1513. #endif
  1514. return 0;
  1515. }
  1516. /***************************************************************************
  1517. FUNCTION: MoveClientWindow
  1518. PURPOSE: Moves a child window using screen coordinates
  1519. PARAMETERS:
  1520. hwndParent
  1521. hwndChild
  1522. prc - rectangle containing coordinates
  1523. fRedraw
  1524. RETURNS:
  1525. COMMENTS:
  1526. This function is similar to MoveWindow, only it expects the
  1527. coordinates to be in screen coordinates rather then client
  1528. coordinates. This makes it possible to use functions like
  1529. GetWindowRect() and use the values directly.
  1530. MODIFICATION DATES:
  1531. 25-Feb-1992 [ralphw]
  1532. ***************************************************************************/
  1533. BOOL MoveClientWindow(HWND hwndParent, HWND hwndChild, const RECT *prc, BOOL fRedraw)
  1534. {
  1535. POINT pt;
  1536. pt.x = pt.y = 0;
  1537. ScreenToClient(hwndParent, &pt);
  1538. return SetWindowPos(hwndChild, NULL, prc->left + pt.x, prc->top + pt.y,
  1539. RECT_WIDTH(prc), RECT_HEIGHT(prc),
  1540. (fRedraw ? (SWP_NOZORDER | SWP_NOACTIVATE) :
  1541. (SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW)));
  1542. }
  1543. HWND FindTopLevelWindow(HWND hwnd)
  1544. {
  1545. HWND hwndParent = hwnd;
  1546. while (IsValidWindow(hwndParent)) {
  1547. char szClass[256];
  1548. GetClassName(hwndParent, szClass, sizeof(szClass));
  1549. if (IsSamePrefix(szClass, "IEFrame", -2) ||
  1550. IsSamePrefix(szClass, txtHtmlHelpWindowClass, -2))
  1551. return hwndParent;
  1552. hwndParent = GetParent(hwndParent);
  1553. }
  1554. return hwnd; // no parent found
  1555. }
  1556. void ConvertBackSlashToForwardSlash(PSTR pszUrl)
  1557. {
  1558. PSTR psz;
  1559. if ( !(psz = pszUrl) )
  1560. return;
  1561. //
  1562. // <mc>
  1563. // I added the code to terminate the loop when we encounter a '#' char because that designates
  1564. // an anchor name or reference. We cannot modify this part of the URL without breaking the link.
  1565. // We have to respect the way the anchor is marked up in the HTM. I made this fix for bug#2058
  1566. // 12-15-97.
  1567. // </mc>
  1568. //
  1569. while (*psz && *psz != '#' )
  1570. {
  1571. if ( *psz == '\\' )
  1572. *psz = '/';
  1573. psz = AnsiNext(psz);
  1574. }
  1575. }
  1576. //////////////////////////////////////////////////////////////////////////
  1577. //
  1578. // GetParentSize
  1579. //
  1580. /*
  1581. This function is used by the navigation panes to get the size of the
  1582. area with which they have to work.
  1583. */
  1584. HWND GetParentSize(RECT* prcParent, HWND hwndParent, int padding, int navpos)
  1585. {
  1586. GetClientRect(hwndParent, prcParent);
  1587. if (padding)
  1588. {
  1589. InflateRect(prcParent, -padding, -padding);
  1590. }
  1591. char szClass[256];
  1592. GetClassName(hwndParent, szClass, sizeof(szClass)); // NOTE: The tab control is note the parent of the panes. The Navigation window is.
  1593. if (IsSamePrefix(szClass, WC_TABCONTROL, -2))
  1594. {
  1595. // Get the dimensions of a tab.
  1596. RECT rectTab ;
  1597. TabCtrl_GetItemRect(hwndParent, 0, &rectTab) ;
  1598. int RowCount = TabCtrl_GetRowCount( hwndParent );
  1599. switch (navpos) {
  1600. case HHWIN_NAVTAB_TOP:
  1601. prcParent->top += RECT_HEIGHT(rectTab)*RowCount;
  1602. break;
  1603. case HHWIN_NAVTAB_LEFT:
  1604. prcParent->left += RECT_WIDTH(rectTab);
  1605. InflateRect(prcParent, 0, 2); // need less space top/bottom
  1606. break;
  1607. case HHWIN_NAVTAB_BOTTOM:
  1608. prcParent->bottom -= RECT_HEIGHT(rectTab)*RowCount;
  1609. break;
  1610. }
  1611. // The following is used by the index and search tabs.
  1612. // I think that there has to be a better way.
  1613. hwndParent = GetParent(hwndParent);
  1614. }
  1615. else if (padding)
  1616. {
  1617. //InflateRect(prcParent, padding, padding);
  1618. // If there is no tab control, we need to add some space to clear the top edge.
  1619. prcParent->top += GetSystemMetrics(SM_CYSIZEFRAME)*2 ; //TODO: Centralize.
  1620. }
  1621. return hwndParent ;
  1622. }
  1623. // pszFont == "facename, pointsize, charset, color and attributes"
  1624. //
  1625. // color or attributes: 0x??? == specifies a standard win32 COLORREF DWORD == 0xbbggrr
  1626. // #??? == specifies an IE color in the form #rrggbb.
  1627. //
  1628. HFONT CreateUserFont(PCSTR pszFont, COLORREF* pclrFont, HDC hDC, INT charset)
  1629. {
  1630. LOGFONT logfont;
  1631. ZERO_STRUCTURE(logfont);
  1632. logfont.lfWeight = FW_NORMAL;
  1633. logfont.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
  1634. logfont.lfCharSet = 0xff; // lfCharSet is unsigned (don't use -1).
  1635. if( pclrFont )
  1636. *pclrFont = CLR_INVALID;
  1637. // facename[, point size[, charset[, color[, BOLD | ITALIC | UNDERLINE]]]]
  1638. CStr cszFont(pszFont); // make a copy so that we can change it
  1639. PSTR pszComma = StrChr(cszFont, ',');
  1640. int ptSize = 12;
  1641. if (pszComma){
  1642. *pszComma = '\0'; // So the facename is isolated
  1643. pszComma = FirstNonSpace(pszComma + 1); // get the point size
  1644. if (IsDigit(*pszComma))
  1645. ptSize = Atoi(pszComma);
  1646. pszComma = StrChr(pszComma, ',');
  1647. if (pszComma) {
  1648. pszComma = FirstNonSpace(pszComma + 1); // get the charset
  1649. if (IsDigit(*pszComma))
  1650. logfont.lfCharSet = (BYTE)Atoi(pszComma);
  1651. pszComma = StrChr(pszComma, ',');
  1652. if (pszComma) { // get color or attribs
  1653. // Get the font attributes first
  1654. pszComma = FirstNonSpace(pszComma + 1);
  1655. if (stristr(pszComma, "BOLD"))
  1656. logfont.lfWeight = FW_BOLD;
  1657. if (stristr(pszComma, "ITALIC"))
  1658. logfont.lfItalic = TRUE;
  1659. if (stristr(pszComma, "UNDERLINE"))
  1660. logfont.lfUnderline = TRUE;
  1661. // may be a color value instead, if so, save the color
  1662. // an repeat this check go fetch the attributes
  1663. if( stristr( pszComma, "#" ) ) { // IE color
  1664. //*(pszComma+7) = 0;
  1665. // IE Color
  1666. CWStr pwszColor = pszComma;
  1667. if( pclrFont )
  1668. *pclrFont = IEColorToWin32Color( pwszColor.pw );
  1669. }
  1670. else if( stristr( pszComma, "0x" ) || stristr( pszComma, "0X" ) ) {
  1671. //*(pszComma+8) = 0;
  1672. // Win32 Color
  1673. if( pclrFont )
  1674. *pclrFont = Atoi( pszComma );
  1675. }
  1676. }
  1677. }
  1678. }
  1679. lstrcpyn(logfont.lfFaceName, cszFont, LF_FACESIZE);
  1680. // REVIEW: we could special-case some common font names to get the
  1681. // correct font family for logfont.lfPitchAndFamily
  1682. logfont.lfOutPrecision = OUT_DEFAULT_PRECIS;
  1683. logfont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
  1684. logfont.lfQuality = DEFAULT_QUALITY;
  1685. // Deal with charset...
  1686. //
  1687. if ( charset != -1 )
  1688. logfont.lfCharSet = (BYTE)charset;
  1689. else
  1690. {
  1691. if ( logfont.lfCharSet == 0xff)
  1692. {
  1693. if (isSameString(cszFont, "Symbol") || isSameString(cszFont, "WingDings"))
  1694. logfont.lfCharSet = SYMBOL_CHARSET;
  1695. else
  1696. {
  1697. HWND hwndDesktop = GetDesktopWindow();
  1698. HDC hdc = GetDC(hwndDesktop);
  1699. if (hdc) {
  1700. TEXTMETRIC tm;
  1701. GetTextMetrics(hdc, &tm);
  1702. logfont.lfCharSet = tm.tmCharSet;
  1703. ReleaseDC(hwndDesktop, hdc);
  1704. }
  1705. else
  1706. logfont.lfCharSet = ANSI_CHARSET; // REVIEW: should use the current system charset
  1707. }
  1708. }
  1709. }
  1710. // fix for Whistler bug #8123
  1711. //
  1712. if(PRIMARYLANGID(LANGIDFROMLCID(GetSystemDefaultLCID())) == LANG_THAI && g_bWinNT5 && ptSize < 11)
  1713. ptSize = 11;
  1714. LONG dyHeight;
  1715. if (! hDC )
  1716. {
  1717. hDC = CreateIC("DISPLAY", NULL, NULL, NULL);
  1718. dyHeight = MulDiv(GetDeviceCaps(hDC, LOGPIXELSY), ptSize * 2, 144);
  1719. DeleteDC(hDC);
  1720. }
  1721. else
  1722. dyHeight = MulDiv(GetDeviceCaps(hDC, LOGPIXELSY), ptSize * 2, 144);
  1723. logfont.lfHeight = -dyHeight;
  1724. return CreateFontIndirect(&logfont);
  1725. }
  1726. // pszFont == "facename, pointsize, charset, color and attributes"
  1727. //
  1728. // color or attributes: 0x??? == specifies a standard win32 COLORREF DWORD == 0xbbggrr
  1729. // #??? == specifies an IE color in the form #rrggbb.
  1730. //
  1731. HFONT CreateUserFontW(WCHAR *pwzFont, COLORREF* pclrFont, HDC hDC, INT charset)
  1732. {
  1733. LOGFONTW logfont;
  1734. ZERO_STRUCTURE(logfont);
  1735. logfont.lfWeight = FW_NORMAL;
  1736. logfont.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
  1737. logfont.lfCharSet = -1;
  1738. if( pclrFont )
  1739. *pclrFont = CLR_INVALID;
  1740. // facename[, point size[, charset[, color[, BOLD | ITALIC | UNDERLINE]]]]
  1741. WCHAR *cwzFont = _wcsdup(pwzFont); // make a copy so that we can change it
  1742. WCHAR *pwzComma = wcschr(cwzFont, L',');
  1743. int ptSize = 12;
  1744. if (pwzComma){
  1745. *pwzComma = '\0'; // So the facename is isolated
  1746. pwzComma = FirstNonSpaceW(pwzComma + 1); // get the point size
  1747. if (IsDigitW(*pwzComma))
  1748. ptSize = _wtoi(pwzComma);
  1749. pwzComma = wcschr(pwzComma, L',');
  1750. if (pwzComma)
  1751. {
  1752. pwzComma = FirstNonSpaceW(pwzComma + 1); // get the charset
  1753. if (IsDigitW(*pwzComma))
  1754. logfont.lfCharSet = (BYTE)_wtoi(pwzComma);
  1755. pwzComma = wcschr(pwzComma, L',');
  1756. if (pwzComma)
  1757. { // get color or attribs
  1758. // Get the font attributes first
  1759. pwzComma = FirstNonSpaceW(pwzComma + 1);
  1760. if (wcsstr(pwzComma, L"BOLD"))
  1761. logfont.lfWeight = FW_BOLD;
  1762. if (wcsstr(pwzComma, L"ITALIC"))
  1763. logfont.lfItalic = TRUE;
  1764. if (wcsstr(pwzComma, L"UNDERLINE"))
  1765. logfont.lfUnderline = TRUE;
  1766. // may be a color value instead, if so, save the color
  1767. // an repeat this check go fetch the attributes
  1768. if( wcsstr( pwzComma, L"#" ) ) { // IE color
  1769. //*(pszComma+7) = 0;
  1770. // IE Color
  1771. *pclrFont = IEColorToWin32Color( pwzComma);
  1772. }
  1773. else if( wcsstr( pwzComma, L"0x" ) || wcsstr( pwzComma, L"0X" ) )
  1774. {
  1775. //*(pszComma+8) = 0;
  1776. // Win32 Color
  1777. if( pclrFont )
  1778. *pclrFont = _wtoi( pwzComma );
  1779. }
  1780. }
  1781. }
  1782. }
  1783. wcsncpy(logfont.lfFaceName, cwzFont, LF_FACESIZE);
  1784. // REVIEW: we could special-case some common font names to get the
  1785. // correct font family for logfont.lfPitchAndFamily
  1786. logfont.lfOutPrecision = OUT_DEFAULT_PRECIS;
  1787. logfont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
  1788. logfont.lfQuality = DEFAULT_QUALITY;
  1789. // Deal with charset...
  1790. //
  1791. if ( charset != -1 )
  1792. logfont.lfCharSet = (BYTE)charset;
  1793. else
  1794. {
  1795. if ( logfont.lfCharSet == -1 )
  1796. {
  1797. if (!wcsicmp(cwzFont, L"Symbol") || !wcsicmp(cwzFont, L"WingDings"))
  1798. logfont.lfCharSet = SYMBOL_CHARSET;
  1799. else
  1800. {
  1801. HWND hwndDesktop = GetDesktopWindow();
  1802. HDC hdc = GetDC(hwndDesktop);
  1803. if (hdc) {
  1804. TEXTMETRIC tm;
  1805. GetTextMetrics(hdc, &tm);
  1806. logfont.lfCharSet = tm.tmCharSet;
  1807. ReleaseDC(hwndDesktop, hdc);
  1808. }
  1809. else
  1810. logfont.lfCharSet = ANSI_CHARSET; // REVIEW: should use the current system charset
  1811. }
  1812. }
  1813. }
  1814. LONG dyHeight;
  1815. if (! hDC )
  1816. {
  1817. hDC = CreateIC("DISPLAY", NULL, NULL, NULL);
  1818. dyHeight = MulDiv(GetDeviceCaps(hDC, LOGPIXELSY), ptSize * 2, 144);
  1819. DeleteDC(hDC);
  1820. }
  1821. else
  1822. dyHeight = MulDiv(GetDeviceCaps(hDC, LOGPIXELSY), ptSize * 2, 144);
  1823. logfont.lfHeight = -dyHeight;
  1824. free(cwzFont);
  1825. return CreateFontIndirectW(&logfont);
  1826. }
  1827. /***************************************************************************
  1828. FUNCTION: CreateFolder
  1829. PURPOSE: Create a directory, even if it means creating several
  1830. subdirectories
  1831. PARAMETERS:
  1832. pszPath
  1833. RETURNS:
  1834. COMMENTS:
  1835. MODIFICATION DATES:
  1836. 31-Oct-1996 [ralphw]
  1837. ***************************************************************************/
  1838. BOOL CreateFolder(PCSTR pszPath)
  1839. {
  1840. CStr cszPath(pszPath); // copy it so that we can change it
  1841. if (CreateDirectory(cszPath, NULL))
  1842. return TRUE;
  1843. PSTR psz = StrRChr(cszPath, CH_BACKSLASH);
  1844. if (!psz) {
  1845. psz = StrRChr(cszPath, '/');
  1846. if (!psz)
  1847. return FALSE;
  1848. }
  1849. *psz = '\0';
  1850. BOOL fResult = CreateFolder(cszPath);
  1851. *psz = CH_BACKSLASH;
  1852. return CreateDirectory(cszPath, NULL);
  1853. }
  1854. BOOL GetHighContrastFlag(void)
  1855. {
  1856. HIGHCONTRAST highcontrast;
  1857. highcontrast.cbSize = sizeof(highcontrast);
  1858. if (SystemParametersInfo(SPI_GETHIGHCONTRAST,
  1859. sizeof(highcontrast),
  1860. &highcontrast, FALSE)) {
  1861. return (highcontrast.dwFlags & HCF_HIGHCONTRASTON);
  1862. }
  1863. else
  1864. return FALSE;
  1865. }
  1866. #if 0
  1867. BOOL IsValidString(LPCWSTR lpsz, int nLength)
  1868. {
  1869. if (lpsz == NULL)
  1870. return FALSE;
  1871. return ::IsBadStringPtrW(lpsz, nLength) == 0;
  1872. }
  1873. BOOL IsValidString(LPCSTR lpsz, int nLength)
  1874. {
  1875. if (lpsz == NULL)
  1876. return FALSE;
  1877. return ::IsBadStringPtrA(lpsz, nLength) == 0;
  1878. }
  1879. BOOL IsValidAddress(const void* lp, UINT nBytes, BOOL bReadWrite)
  1880. {
  1881. // simple version using Win-32 APIs for pointer validation.
  1882. return (lp != NULL && !IsBadReadPtr(lp, nBytes) &&
  1883. (!bReadWrite || !IsBadWritePtr((LPVOID)lp, nBytes)));
  1884. }
  1885. #endif
  1886. void ConvertSpacesToEscapes(PCSTR pszSrc, CStr* pcszDst)
  1887. {
  1888. int cbAlloc = pcszDst->SizeAlloc();
  1889. if (!cbAlloc)
  1890. pcszDst->ReSize(cbAlloc = (int)(strlen(pszSrc) + 128));
  1891. int dstPos = 0;
  1892. if (!pszSrc) {
  1893. *pcszDst = "";
  1894. return;
  1895. }
  1896. int cbSrc = (int)strlen(pszSrc);
  1897. while (*pszSrc) {
  1898. if (*pszSrc == ' ') {
  1899. if ((size_t) cbAlloc - dstPos <= 4)
  1900. pcszDst->ReSize(cbAlloc += 128);
  1901. strcpy(pcszDst->psz + dstPos, "%20");
  1902. dstPos += (int)strlen("%20");
  1903. pszSrc++;
  1904. }
  1905. else
  1906. pcszDst->psz[dstPos++] = *pszSrc++;
  1907. if (cbAlloc <= dstPos)
  1908. pcszDst->ReSize(cbAlloc += 128);
  1909. }
  1910. pcszDst->psz[dstPos] = '\0';
  1911. }
  1912. static const char txtItsExtension[] = ".its";
  1913. /***************************************************************************
  1914. FUNCTION: IsCompiledURL
  1915. PURPOSE: Determines if a specified URL represents one of our compiled
  1916. files.
  1917. PARAMETERS:
  1918. pszURL - URL to check
  1919. RETURNS:
  1920. TRUE if so, otherwise FALSE.
  1921. COMMENTS:
  1922. Unlike IsCompiledHtmlFile, this function does not have any side
  1923. effects--the way God intended all IsX functions to be!
  1924. MODIFICATION DATES:
  1925. 02-Jan-1998 [paulti]
  1926. ***************************************************************************/
  1927. BOOL IsCompiledURL( PCSTR pszURL )
  1928. {
  1929. // Check to see if the pszURL is prefixed with the moniker information.
  1930. if( IsSamePrefix(pszURL, txtMkStore, (int)strlen(txtMkStore) - 1) ||
  1931. IsSamePrefix(pszURL, txtMsItsMoniker, (int)strlen(txtMsItsMoniker) - 1) ||
  1932. IsSamePrefix(pszURL, txtItsMoniker, (int)strlen(txtItsMoniker) - 1)) {
  1933. return TRUE;
  1934. }
  1935. // TODO: do we want to verify this further? We could do an existence
  1936. // check or make sure the URL is formulated correctly. However,
  1937. // doing such will just introduce more overhead.
  1938. return FALSE;
  1939. }
  1940. /***************************************************************************
  1941. FUNCTION: GetURLType
  1942. PURPOSE: Determines what type of URL we have.
  1943. PARAMETERS:
  1944. pszURL - URL to check
  1945. RETURNS:
  1946. HH_URL_PREFIX_LESS if of the form: my.chm::/my.htm
  1947. HH_URL_UNQUALIFIED if of the form: mk@MSITStore:my.chm::/my.htm
  1948. HH_URL_QUALIFIED if of the form: mk@MSITStore:c:\my.chm::/my.htm
  1949. HH_URL_JAVASCRIPT if of the form: javascript:...
  1950. HH_URL_UNKNOWN if of an unknown form (just pass these along)
  1951. COMMENTS:
  1952. The unknown URL type is basically a non-HTML Help URL that
  1953. should remain unprocessed!
  1954. MODIFICATION DATES:
  1955. 11-Jun-1998 [paulti] created
  1956. 29-Oct-1998 [paulti] added ms-its:http://some.server.com/... check
  1957. 18-Nov-1998 [paulti] added //255.255.255.255 check
  1958. ***************************************************************************/
  1959. UINT GetURLType( PCSTR pszURL )
  1960. {
  1961. // bail out if we are passed a NULL value
  1962. if( !pszURL || !*pszURL )
  1963. return HH_URL_UNKNOWN;
  1964. // check if it is a javascript
  1965. if( !StrNCmpI(pszURL, "javascript:", 11) )
  1966. return HH_URL_JAVASCRIPT;
  1967. UINT uiReturn = HH_URL_UNKNOWN;
  1968. // check if the URL contains a ".chm" string
  1969. PSTR pszExt = NULL;
  1970. if( (uiReturn == HH_URL_UNKNOWN) && (pszExt = stristr(pszURL, txtDefExtension)) ) {
  1971. PSTR pszChm = (PSTR) pszURL;
  1972. uiReturn = HH_URL_UNQUALIFIED;
  1973. // Check to see if the pszURL is prefixed with the moniker information.
  1974. // if it is then we will call is this a unqualified URL (and will prove
  1975. // if it is really qualified later).
  1976. if( IsSamePrefix(pszURL, txtMkStore, (int)strlen(txtMkStore) - 1) )
  1977. pszChm += strlen(txtMkStore);
  1978. else if ( IsSamePrefix(pszURL, txtMsItsMoniker, (int)strlen(txtMsItsMoniker) - 1) )
  1979. pszChm += strlen(txtMsItsMoniker);
  1980. else if ( IsSamePrefix(pszURL, txtItsMoniker, (int)strlen(txtItsMoniker) - 1))
  1981. pszChm += strlen(txtItsMoniker);
  1982. else
  1983. uiReturn = HH_URL_PREFIX_LESS;
  1984. // if prefix less lets make sure it really is just prefixed with
  1985. // a simple chm filename instead of some other bizarre URL that does
  1986. // contain .chm somewhere in the middle
  1987. if( uiReturn == HH_URL_PREFIX_LESS ) {
  1988. PSTR psz = (PSTR) pszURL;
  1989. while( psz != pszExt ) {
  1990. if( *psz == ':' || *psz == '\\' || *psz == '/' ) {
  1991. uiReturn = HH_URL_UNKNOWN;
  1992. break;
  1993. }
  1994. psz++;
  1995. }
  1996. }
  1997. // if unqualified, check if it is really qualified or not
  1998. // if it begins with "X:" or "\\" then it is qualified
  1999. // if it is not qualified but contains a '/' or a '\' and the .chm
  2000. // extention then it is unknown (probably of the for:"
  2001. // ms-its:http://some.server.com/some/file.chm::some.stream.htm
  2002. if( uiReturn == HH_URL_UNQUALIFIED ) {
  2003. PSTR psz = (PSTR) ((DWORD_PTR)pszChm+1);
  2004. if( *psz == ':' || *psz == '\\' || *psz == '/' ) {
  2005. // make sure it is not of the type:
  2006. // ms-its:\\172.30.161.112\shared\boof\oops.chm::/source/Adam_nt.html
  2007. // if it is, call it unknown
  2008. BOOL bTCPIPServer = FALSE;
  2009. for( psz++; psz && *psz != '\\' && *psz != '/'; psz++ ) {
  2010. if( isdigit( *psz ) )
  2011. bTCPIPServer = TRUE;
  2012. else if( *psz == '.' )
  2013. bTCPIPServer = TRUE;
  2014. else {
  2015. bTCPIPServer = FALSE;
  2016. break;
  2017. }
  2018. }
  2019. if( bTCPIPServer ) {
  2020. uiReturn = HH_URL_UNKNOWN;
  2021. }
  2022. else {
  2023. uiReturn = HH_URL_QUALIFIED;
  2024. }
  2025. }
  2026. else {
  2027. // seek to the first slash/backslash--if .chm is after this then
  2028. // we have an unknown type possibly of the form:
  2029. // ms-its:http://some.server.com/some/file.chm::some.stream.htm
  2030. PSTR pszSlash = strstr( psz, "/" );
  2031. if( !pszSlash )
  2032. pszSlash = strstr( psz, "\\" );
  2033. if( pszSlash && (pszSlash <= pszExt) ) {
  2034. uiReturn = HH_URL_UNKNOWN;
  2035. }
  2036. }
  2037. }
  2038. }
  2039. return uiReturn;
  2040. }
  2041. /***************************************************************************
  2042. FUNCTION: IsCompiledHtmlFile
  2043. PURPOSE: Determines if a compiled HTML file is specified. If
  2044. pcszFile is specified, and pszFile does not begin with a
  2045. moniker, then we find the compiled HTML file before
  2046. returning.
  2047. PARAMETERS:
  2048. pszFile
  2049. pcszFile --- If this parameter is null, we don't attempt to find.
  2050. RETURNS:
  2051. COMMENTS:
  2052. MODIFICATION DATES:
  2053. 03-Jun-1997 [ralphw]
  2054. ***************************************************************************/
  2055. BOOL IsCompiledHtmlFile(PCSTR pszFile, CStr* pcszFile)
  2056. {
  2057. //--- Check to see if the pszFile is prefixed with the moniker information.
  2058. if ( IsCompiledURL(pszFile) ) {
  2059. if (pcszFile)
  2060. *pcszFile = pszFile;
  2061. return TRUE;
  2062. }
  2063. //--- Look for the chm::topic separator.
  2064. PCSTR pszSep = stristr(pszFile, txtDoubleColonSep);
  2065. if (!pszSep)
  2066. {
  2067. // The separator has not been found.
  2068. if (stristr(pszFile, txtDefExtension) || stristr(pszFile, txtItsExtension))
  2069. pszSep = pszFile;
  2070. else
  2071. return FALSE; // not a compiled file if no separator
  2072. }
  2073. // If pcszFile is NULL, don't go look for the file.
  2074. if (!pcszFile)
  2075. return TRUE; // don't find it, just say it's compiled
  2076. //NOTE: We always return true. Whether we find the file or not.
  2077. // Remove the topic from the filename, before we find the file.
  2078. CStr cszFindFile(pszFile);
  2079. if (pszSep > pszFile)
  2080. cszFindFile.psz[pszSep - pszFile] = '\0'; // remove separator
  2081. //--- Find the file.
  2082. if (FindThisFile(NULL, cszFindFile, &cszFindFile, FALSE)) {
  2083. // Add on the moniker information. FindThisFile doesn't do this.
  2084. char szSep[MAX_PATH];
  2085. strcpy(szSep, pszSep); // in case pszFile == *pcszFile
  2086. *pcszFile = (g_bMsItsMonikerSupport ? txtMsItsMoniker : txtMkStore);
  2087. *pcszFile += cszFindFile.psz;
  2088. if (pszSep > pszFile)
  2089. *pcszFile += szSep;
  2090. return TRUE;
  2091. }
  2092. else
  2093. *pcszFile = pszFile;
  2094. // If we get here, it's a compiled file, but we don't know where it is
  2095. return TRUE; // we can't find the file, so let IE try to find it
  2096. }
  2097. /***************************************************************************
  2098. FUNCTION: IsCollectionFile
  2099. PURPOSE: Determines if a input file is a collection
  2100. PARAMETERS:
  2101. pszName -- original name
  2102. RETURNS:
  2103. TRUE if file is a collection
  2104. MODIFICATION DATES:
  2105. 29-Jul-1997 [dondr]
  2106. ***************************************************************************/
  2107. BOOL IsCollectionFile(PCSTR pszName)
  2108. {
  2109. if (stristr(pszName, txtCollectionExtension))
  2110. return TRUE;
  2111. return FALSE;
  2112. }
  2113. /***************************************************************************
  2114. FUNCTION: GetCompiledName
  2115. PURPOSE: Parse out just the compiled file name (and path)
  2116. E.g. "its:c:\foo.chm::/bar.htm" becomes "c:\foo.chm"
  2117. Note, we must convert any and all escape sequences like %20 as well [paulti]
  2118. PARAMETERS:
  2119. pszName -- original name
  2120. pcsz -- CStr to store result
  2121. RETURNS:
  2122. Pointer to any filename after a '::' separator in the
  2123. original string (pszName);
  2124. MODIFICATION DATES:
  2125. 10-Jun-1997 [ralphw]
  2126. ***************************************************************************/
  2127. PCSTR GetCompiledName(PCSTR pszName, CStr* pcsz)
  2128. {
  2129. ASSERT(pcsz != NULL) ;
  2130. if( !pszName )
  2131. return NULL;
  2132. if (IsSamePrefix(pszName, txtMkStore))
  2133. pszName += strlen(txtMkStore);
  2134. else if (IsSamePrefix(pszName, txtMsItsMoniker))
  2135. pszName += strlen(txtMsItsMoniker);
  2136. else if (IsSamePrefix(pszName, txtItsMoniker))
  2137. pszName += strlen(txtItsMoniker);
  2138. *pcsz = pszName;
  2139. PSTR pszSep = strstr(*pcsz, txtDoubleColonSep);
  2140. if (pszSep) {
  2141. *pszSep = '\0';
  2142. ReplaceEscapes(pcsz->psz, pcsz->psz, ESCAPE_URL); // remove escapes
  2143. return (strstr(pszName, txtDoubleColonSep) + 2);
  2144. }
  2145. return NULL;
  2146. }
  2147. /***************************************************************************
  2148. FUNCTION: NormalizeFileName
  2149. PURPOSE: Take a filename to a CHM or COL and create a definitive
  2150. name for the file. For a CHM file, this is the moniker.
  2151. For a COL, its the moniker to the master CHM.
  2152. PARAMETERS:
  2153. cszFileName -- Modifies the name passed in.
  2154. RETURNS:
  2155. true - success
  2156. false - failure.
  2157. MODIFICATION DATES:
  2158. 27-Apr-98 [dalero]
  2159. ***************************************************************************/
  2160. bool
  2161. NormalizeFileName(CStr& cszFileName)
  2162. {
  2163. // We shouldn't be getting any http files. This isn't incorrect. I'm just testing my assumptions.
  2164. ASSERT(!IsHttp(cszFileName)) ;
  2165. if (IsCollectionFile(cszFileName)) // Is this a collection?
  2166. {
  2167. //...Much of this was borrowed from OnDisplayTopic...
  2168. // Get the master chm file name.
  2169. GetCompiledName(cszFileName, &cszFileName); // pszFilePortion is everything is cszFile after the '::', in other words the topic path.
  2170. if (!FindThisFile(NULL, cszFileName, &cszFileName, FALSE))
  2171. {
  2172. //TODO: Move error message into FindThisFile.
  2173. //g_LastError.Set(HH_E_FILENOTFOUND) ;
  2174. return false;
  2175. }
  2176. CHmData* phmData;
  2177. CExCollection* pCollection = GetCurrentCollection(NULL, (PCSTR)cszFileName);
  2178. if ( pCollection )
  2179. phmData = pCollection->m_phmData;
  2180. if (phmData == NULL)
  2181. {
  2182. //g_LastError.Set(HH_E_INVALIDHELPFILE) ; // TODO: FindCurFileData should set this.
  2183. return false;
  2184. }
  2185. else
  2186. {
  2187. // Get the name of the master chm.
  2188. cszFileName = phmData->GetCompiledFile();
  2189. }
  2190. }
  2191. // Find the file and get all the moniker information.
  2192. if (IsCompiledHtmlFile(cszFileName, &cszFileName))
  2193. {
  2194. // Remove any filename tacked onto the end.
  2195. PSTR pszSep = strstr(cszFileName.psz, txtDoubleColonSep);
  2196. if (pszSep)
  2197. {
  2198. *pszSep = '\0';
  2199. }
  2200. return true;
  2201. }
  2202. else
  2203. {
  2204. return false ;
  2205. }
  2206. }
  2207. /***************************************************************************
  2208. FUNCTION: GetButtonDimensions
  2209. PURPOSE: Get the width/height of the button
  2210. PARAMETERS:
  2211. hwnd
  2212. psz
  2213. RETURNS:
  2214. COMMENTS:
  2215. MODIFICATION DATES:
  2216. 04-Feb-1993 [ralphw]
  2217. ***************************************************************************/
  2218. #define CXBUTTONEXTRA 16 // spacing between text and button
  2219. #define CYBUTTONEXTRA 7
  2220. DWORD GetButtonDimensions(HWND hwnd, HFONT hFont, PCSTR psz)
  2221. {
  2222. HDC hdc = GetDC(hwnd);
  2223. DWORD dwRet;
  2224. POINT pt;
  2225. if (hdc == NULL)
  2226. return 0L;
  2227. // Select in the new font. The dialog may not have done this.
  2228. HFONT hOldFont = NULL ;
  2229. if (hFont)
  2230. {
  2231. hOldFont = (HFONT)SelectObject(hdc, hFont) ;
  2232. }
  2233. // Get the size of the text.
  2234. pt = GetTextSize(hdc, psz, (int)strlen(psz));
  2235. dwRet = MAKELONG(pt.x, pt.y) +
  2236. MAKELONG(CXBUTTONEXTRA, CYBUTTONEXTRA);
  2237. // Cleanup.
  2238. if (hOldFont)
  2239. {
  2240. SelectObject(hdc, hOldFont) ;
  2241. }
  2242. ReleaseDC(hwnd, hdc);
  2243. return dwRet;
  2244. }
  2245. //////////////////////////////////////////////////////////////////////////
  2246. //
  2247. // GetStaticDimensions - used by simple search tab. max_len should include
  2248. // any space needed between the static text and buttons on the left or right.
  2249. //
  2250. DWORD GetStaticDimensions(HWND hwnd, HFONT hFont, PCSTR psz, int max_len )
  2251. {
  2252. DWORD dwRet;
  2253. POINT pt;
  2254. int rows;
  2255. HDC hdc = GetDC(hwnd);
  2256. if ( hdc == NULL )
  2257. return 0L;
  2258. // Select in the new font. The dialog may not have done this.
  2259. HFONT hOldFont = NULL ;
  2260. if (hFont)
  2261. {
  2262. hOldFont = (HFONT)SelectObject(hdc, hFont) ;
  2263. }
  2264. // Get the text extent.
  2265. pt = GetTextSize(hdc, psz, (int)strlen(psz) );
  2266. rows = pt.x/(max_len ? max_len : 1);
  2267. if ( pt.x%(max_len ? max_len : 1) > 0 )
  2268. rows++;
  2269. pt.y *= rows;
  2270. dwRet = MAKELONG(pt.x, pt.y);
  2271. // Cleanup.
  2272. if (hOldFont)
  2273. {
  2274. SelectObject(hdc, hOldFont) ;
  2275. }
  2276. ReleaseDC(hwnd, hdc);
  2277. return dwRet;
  2278. }
  2279. //////////////////////////////////////////////////////////////////////////
  2280. //
  2281. // GetStaticDimensions - used by simple search tab. max_len should include
  2282. // any space needed between the static text and buttons on the left or right.
  2283. //
  2284. DWORD GetStaticDimensionsW(HWND hwnd, HFONT hFont, WCHAR *psz, int max_len )
  2285. {
  2286. DWORD dwRet;
  2287. POINT pt;
  2288. int rows;
  2289. HDC hdc = GetDC(hwnd);
  2290. if ( hdc == NULL )
  2291. return 0L;
  2292. // Select in the new font. The dialog may not have done this.
  2293. HFONT hOldFont = NULL ;
  2294. if (hFont)
  2295. {
  2296. hOldFont = (HFONT)SelectObject(hdc, hFont) ;
  2297. }
  2298. // Get the text extent.
  2299. pt = GetTextSizeW(hdc, psz, wcslen(psz) );
  2300. rows = pt.x/(max_len ? max_len : 1);
  2301. if ( pt.x%(max_len ? max_len : 1) > 0 )
  2302. rows++;
  2303. pt.y *= rows;
  2304. dwRet = MAKELONG(pt.x, pt.y);
  2305. // Cleanup.
  2306. if (hOldFont)
  2307. {
  2308. SelectObject(hdc, hOldFont) ;
  2309. }
  2310. ReleaseDC(hwnd, hdc);
  2311. return dwRet;
  2312. }
  2313. static POINT GetTextSize(HDC hdc, PCSTR qchBuf, int iCount)
  2314. {
  2315. POINT ptRet;
  2316. SIZE size;
  2317. GetTextExtentPoint32(hdc, qchBuf, iCount, &size);
  2318. ptRet.x = size.cx;
  2319. ptRet.y = size.cy;
  2320. return ptRet;
  2321. }
  2322. static POINT GetTextSizeW(HDC hdc, WCHAR *qchBuf, int iCount)
  2323. {
  2324. POINT ptRet;
  2325. SIZE size;
  2326. GetTextExtentPoint32W(hdc, qchBuf, iCount, &size);
  2327. ptRet.x = size.cx;
  2328. ptRet.y = size.cy;
  2329. return ptRet;
  2330. }
  2331. DWORD CreatePath(char *szPath)
  2332. {
  2333. char szTmp[MAX_PATH],*p,*q,szTmp2[MAX_PATH];
  2334. DWORD dwErr;
  2335. strcpy(szTmp2,szPath);
  2336. memset(szTmp,0,sizeof(szTmp));
  2337. q = szTmp2;
  2338. p = szTmp;
  2339. while (*q)
  2340. {
  2341. if (*q == '/' || *q == '\\')
  2342. {
  2343. if (szTmp[1] == ':' && strlen(szTmp) <= 3)
  2344. {
  2345. if(IsDBCSLeadByte(*q))
  2346. {
  2347. *p++ = *q++;
  2348. if(*q)
  2349. *p++ = *q++;
  2350. }
  2351. else
  2352. *p++ = *q++;
  2353. continue;
  2354. }
  2355. if (!::CreateDirectory(szTmp,0))
  2356. {
  2357. if ( (dwErr = GetLastError()) != ERROR_ALREADY_EXISTS)
  2358. return(dwErr);
  2359. }
  2360. }
  2361. if(IsDBCSLeadByte(*q))
  2362. {
  2363. *p++ = *q++;
  2364. if(*q)
  2365. *p++ = *q++;
  2366. }
  2367. else
  2368. *p++ = *q++;
  2369. }
  2370. if (!::CreateDirectory(szTmp,0))
  2371. {
  2372. if ((dwErr = GetLastError()) != ERROR_ALREADY_EXISTS)
  2373. return(dwErr);
  2374. }
  2375. return(FALSE);
  2376. }
  2377. BOOL IsFile( LPCSTR lpszPathname )
  2378. {
  2379. DWORD dwAttribs = GetFileAttributes( lpszPathname );
  2380. if( dwAttribs != (DWORD) -1 )
  2381. if( (dwAttribs & FILE_ATTRIBUTE_DIRECTORY) == 0 )
  2382. return TRUE;
  2383. return FALSE;
  2384. }
  2385. BOOL IsDirectory( LPCSTR lpszPathname )
  2386. {
  2387. DWORD dwAttribs = GetFileAttributes( lpszPathname );
  2388. if( dwAttribs != (DWORD) -1 )
  2389. if( dwAttribs & FILE_ATTRIBUTE_DIRECTORY )
  2390. return TRUE;
  2391. return FALSE;
  2392. }
  2393. /***
  2394. *SplitPath() - split a path name into its individual components
  2395. *
  2396. *Purpose:
  2397. * to split a path name into its individual components
  2398. *
  2399. *Entry:
  2400. * path - pointer to path name to be parsed
  2401. * drive - pointer to buffer for drive component, if any
  2402. * dir - pointer to buffer for subdirectory component, if any
  2403. * fname - pointer to buffer for file base name component, if any
  2404. * ext - pointer to buffer for file name extension component, if any
  2405. *
  2406. *Exit:
  2407. * drive - pointer to drive string. Includes ':' if a drive was given.
  2408. * dir - pointer to subdirectory string. Includes leading and trailing
  2409. * '/' or '\', if any.
  2410. * fname - pointer to file base name
  2411. * ext - pointer to file extension, if any. Includes leading '.'.
  2412. *
  2413. *Exceptions:
  2414. *
  2415. *******************************************************************************/
  2416. void __cdecl SplitPath (
  2417. const char *path,
  2418. char *drive,
  2419. char *dir,
  2420. char *fname,
  2421. char *ext
  2422. )
  2423. {
  2424. char *p;
  2425. char *last_slash = NULL, *dot = NULL;
  2426. unsigned len;
  2427. /* we assume that the path argument has the following form, where any
  2428. * or all of the components may be missing.
  2429. *
  2430. * <drive><dir><fname><ext>
  2431. *
  2432. * and each of the components has the following expected form(s)
  2433. *
  2434. * drive:
  2435. * 0 to _MAX_DRIVE-1 characters, the last of which, if any, is a
  2436. * ':'
  2437. * dir:
  2438. * 0 to _MAX_DIR-1 characters in the form of an absolute path
  2439. * (leading '/' or '\') or relative path, the last of which, if
  2440. * any, must be a '/' or '\'. E.g -
  2441. * absolute path:
  2442. * \top\next\last\ ; or
  2443. * /top/next/last/
  2444. * relative path:
  2445. * top\next\last\ ; or
  2446. * top/next/last/
  2447. * Mixed use of '/' and '\' within a path is also tolerated
  2448. * fname:
  2449. * 0 to _MAX_FNAME-1 characters not including the '.' character
  2450. * ext:
  2451. * 0 to _MAX_EXT-1 characters where, if any, the first must be a
  2452. * '.'
  2453. *
  2454. */
  2455. /* extract drive letter and :, if any */
  2456. if ((strlen(path) >= (_MAX_DRIVE - 2)) && (*(path + _MAX_DRIVE - 2) == ':')) {
  2457. if (drive) {
  2458. lstrcpyn(drive, path, _MAX_DRIVE);
  2459. *(drive + _MAX_DRIVE-1) = '\0';
  2460. }
  2461. path += _MAX_DRIVE - 1;
  2462. }
  2463. else if (drive) {
  2464. *drive = '\0';
  2465. }
  2466. /* extract path string, if any. Path now points to the first character
  2467. * of the path, if any, or the filename or extension, if no path was
  2468. * specified. Scan ahead for the last occurence, if any, of a '/' or
  2469. * '\' path separator character. If none is found, there is no path.
  2470. * We will also note the last '.' character found, if any, to aid in
  2471. * handling the extension.
  2472. */
  2473. for (last_slash = NULL, p = (char *)path; *p; p++) {
  2474. #ifdef _MBCS
  2475. if (IsDBCSLeadByte (*p))
  2476. p++;
  2477. else {
  2478. #endif /* _MBCS */
  2479. if (*p == '/' || *p == '\\')
  2480. /* point to one beyond for later copy */
  2481. last_slash = p + 1;
  2482. else if (*p == '.')
  2483. dot = p;
  2484. #ifdef _MBCS
  2485. }
  2486. #endif /* _MBCS */
  2487. }
  2488. if (last_slash) {
  2489. /* found a path - copy up through last_slash or max. characters
  2490. * allowed, whichever is smaller
  2491. */
  2492. if (dir) {
  2493. len = (unsigned)__min(((char *)last_slash - (char *)path) / sizeof(char),
  2494. (_MAX_DIR - 1));
  2495. lstrcpyn(dir, path, len+1);
  2496. *(dir + len) = '\0';
  2497. }
  2498. path = last_slash;
  2499. }
  2500. else if (dir) {
  2501. /* no path found */
  2502. *dir = '\0';
  2503. }
  2504. /* extract file name and extension, if any. Path now points to the
  2505. * first character of the file name, if any, or the extension if no
  2506. * file name was given. Dot points to the '.' beginning the extension,
  2507. * if any.
  2508. */
  2509. if (dot && (dot >= path)) {
  2510. /* found the marker for an extension - copy the file name up to
  2511. * the '.'.
  2512. */
  2513. if (fname) {
  2514. len = (unsigned)__min(((char *)dot - (char *)path) / sizeof(char),
  2515. (_MAX_FNAME - 1));
  2516. lstrcpyn(fname, path, len+1);
  2517. *(fname + len) = '\0';
  2518. }
  2519. /* now we can get the extension - remember that p still points
  2520. * to the terminating nul character of path.
  2521. */
  2522. if (ext) {
  2523. len = (unsigned)__min(((char *)p - (char *)dot) / sizeof(char),
  2524. (_MAX_EXT - 1));
  2525. lstrcpyn(ext, dot, len+1);
  2526. *(ext + len) = '\0';
  2527. }
  2528. }
  2529. else {
  2530. /* found no extension, give empty extension and copy rest of
  2531. * string into fname.
  2532. */
  2533. if (fname) {
  2534. len = (unsigned)__min(((char *)p - (char *)path) / sizeof(char),
  2535. (_MAX_FNAME - 1));
  2536. lstrcpyn(fname, path, len+1);
  2537. *(fname + len) = '\0';
  2538. }
  2539. if (ext) {
  2540. *ext = '\0';
  2541. }
  2542. }
  2543. }
  2544. void MemMove(void * dst, const void * src, int count)
  2545. {
  2546. #if defined (_M_MRX000) || defined (_M_ALPHA) || defined (_M_PPC)
  2547. {
  2548. RtlMoveMemory( dst, src, count );
  2549. }
  2550. #else /* defined (_M_MRX000) || defined (_M_ALPHA) || defined (_M_PPC) */
  2551. if (dst <= src || (char *)dst >= ((char *)src + count)) {
  2552. memcpy(dst, src, count);
  2553. }
  2554. else {
  2555. /*
  2556. * Overlapping Buffers
  2557. * copy from higher addresses to lower addresses
  2558. */
  2559. dst = (char *)dst + count - 1;
  2560. src = (char *)src + count - 1;
  2561. while (count--) {
  2562. *(char *)dst = *(char *)src;
  2563. dst = (char *)dst - 1;
  2564. src = (char *)src - 1;
  2565. }
  2566. }
  2567. #endif /* defined (_M_MRX000) || defined (_M_ALPHA) || defined (_M_PPC) */
  2568. }
  2569. LPSTR CatPath(LPSTR lpTop, LPCSTR lpTail)
  2570. {
  2571. //
  2572. // make sure we have a slash at the end of the first element
  2573. //
  2574. LPSTR p;
  2575. if (lpTop && lpTop[0])
  2576. {
  2577. p = lpTop + strlen(lpTop);
  2578. p = CharPrev(lpTop,p);
  2579. if (*p != '\\' && *p != '/')
  2580. {
  2581. strcat(lpTop,"\\");
  2582. }
  2583. //
  2584. // strip any leading slash from the second element
  2585. //
  2586. while (*lpTail == '\\') lpTail = CharNext(lpTail);
  2587. //
  2588. }
  2589. // add them together
  2590. //
  2591. strcat(lpTop, lpTail);
  2592. return lpTop;
  2593. }
  2594. ///////////////////////////////////////////////////////////
  2595. //
  2596. // NoRun - Checks registry to determine if the no run option is set for this system
  2597. //
  2598. BOOL NoRun()
  2599. {
  2600. HKEY hKeyResult;
  2601. DWORD dwNoRun;
  2602. DWORD count = sizeof(DWORD);
  2603. DWORD type;
  2604. LONG lReturn;
  2605. lReturn = RegOpenKeyEx( HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer", 0, KEY_READ, &hKeyResult);
  2606. if( lReturn == ERROR_SUCCESS )
  2607. {
  2608. lReturn = RegQueryValueEx(hKeyResult, "NoRun", 0, &type, (BYTE *)&dwNoRun, &count);
  2609. RegCloseKey(hKeyResult);
  2610. }
  2611. if (lReturn == ERROR_SUCCESS)
  2612. {
  2613. if (dwNoRun == 1)
  2614. return TRUE;
  2615. else
  2616. return FALSE;
  2617. }
  2618. else
  2619. {
  2620. count = sizeof(DWORD);
  2621. lReturn = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer", 0, KEY_READ, &hKeyResult);
  2622. if( lReturn == ERROR_SUCCESS )
  2623. {
  2624. lReturn = RegQueryValueEx(hKeyResult, "NoRun", 0, &type, (BYTE *)&dwNoRun, &count);
  2625. RegCloseKey(hKeyResult);
  2626. }
  2627. if (lReturn == ERROR_SUCCESS)
  2628. {
  2629. if (dwNoRun == 1)
  2630. return TRUE;
  2631. else
  2632. return FALSE;
  2633. }
  2634. }
  2635. return FALSE;
  2636. }
  2637. ///////////////////////////////////////////////////////////
  2638. //
  2639. // NormalizeUrlInPlace
  2640. //
  2641. void
  2642. NormalizeUrlInPlace(LPSTR szURL)
  2643. {
  2644. //
  2645. // Normalize the URL by stripping off protocol, storage type, storage name goo from the URL then make sure
  2646. // we only have forward slashes. BUGBUG: May want to consider moving this to util.cpp if it turns up useful.
  2647. //
  2648. PSTR pszSep = strstr(szURL, txtDoubleColonSep);
  2649. if (pszSep)
  2650. {
  2651. strcpy(szURL, pszSep + 3);
  2652. }
  2653. ConvertBackSlashToForwardSlash(szURL);
  2654. }
  2655. void QRect(HDC hdc, INT x, INT y, INT cx, INT cy, INT color)
  2656. {
  2657. DWORD dwColor;
  2658. RECT rc;
  2659. dwColor = SetBkColor(hdc,GetSysColor(color));
  2660. rc.left = x;
  2661. rc.top = y;
  2662. rc.right = x + cx;
  2663. rc.bottom = y + cy;
  2664. ExtTextOut(hdc,0,0,ETO_OPAQUE,&rc,NULL,0,NULL);
  2665. SetBkColor(hdc,dwColor);
  2666. }
  2667. ///////////////////////////////////////////////////////////
  2668. //
  2669. // Determine if the wintype is a global wintype.
  2670. //
  2671. bool
  2672. IsGlobalWinType(const char* szType)
  2673. {
  2674. // Skip possible leading window separator character.
  2675. const char* psz = szType ;
  2676. if (psz[0] == '>')
  2677. {
  2678. psz++ ;
  2679. }
  2680. if (_strnicmp(psz, GLOBAL_WINDOWTYPE_PREFIX, (int)strlen(GLOBAL_WINDOWTYPE_PREFIX)) == 0)
  2681. {
  2682. return true ;
  2683. }
  2684. else if (_strnicmp(psz, GLOBAL_WINDOWTYPE_PREFIX_OFFICE, (int)strlen(GLOBAL_WINDOWTYPE_PREFIX_OFFICE)) == 0)
  2685. {
  2686. return true ;
  2687. }
  2688. else if (_Module.m_GlobalWinTypes.Find(psz))
  2689. {
  2690. return true ;
  2691. }
  2692. else
  2693. {
  2694. return false ;
  2695. }
  2696. }
  2697. ///////////////////////////////////////////////////////////
  2698. //
  2699. // Determine if the wintype is a global wintype.
  2700. //
  2701. bool
  2702. IsGlobalWinTypeW(LPCWSTR szType)
  2703. {
  2704. LPCWSTR psz = szType ;
  2705. if (psz[0] == '>')
  2706. {
  2707. psz++ ;
  2708. }
  2709. if (_wcsnicmp(psz, GLOBAL_WINDOWTYPE_PREFIX_W, wcslen(GLOBAL_WINDOWTYPE_PREFIX_W)) == 0)
  2710. {
  2711. return true ;
  2712. }
  2713. else if (_wcsnicmp(psz, GLOBAL_WINDOWTYPE_PREFIX_OFFICE_W, wcslen(GLOBAL_WINDOWTYPE_PREFIX_OFFICE_W)) == 0)
  2714. {
  2715. return true ;
  2716. }
  2717. else if (_Module.m_GlobalWinTypes.Find(psz))
  2718. {
  2719. return true ;
  2720. }
  2721. else
  2722. {
  2723. return false ;
  2724. }
  2725. }
  2726. static const char txtSetupKey[] = "Software\\Microsoft\\Windows\\CurrentVersion\\Setup";
  2727. static const char txtSharedDir[] = "SharedDir";
  2728. ///////////////////////////////////////////////////////////
  2729. //
  2730. // Get the windows directory for the system or the user
  2731. //
  2732. // Note, Windows NT Terminal Server has changed the system API
  2733. // of GetWindowsDirectory to return a per-user system directory.
  2734. // Inorder to determine this condtion we need to check kernel32
  2735. // for the GetSystemWindowsDirectory API and if it exists use
  2736. // this one instead.
  2737. //
  2738. UINT HHGetWindowsDirectory( LPSTR lpBuffer, UINT uSize, UINT uiType )
  2739. {
  2740. UINT uiReturn = 0;
  2741. static PFN_GETWINDOWSDIRECTORY pfnGetUsersWindowsDirectory = NULL;
  2742. static PFN_GETWINDOWSDIRECTORY pfnGetSystemWindowsDirectory = NULL;
  2743. // determine which system API to call for each case
  2744. if( !pfnGetSystemWindowsDirectory || !pfnGetSystemWindowsDirectory ) {
  2745. HINSTANCE hInst = LoadLibrary( "Kernel32" );
  2746. if( !hInst )
  2747. return uiReturn;
  2748. pfnGetSystemWindowsDirectory = (PFN_GETWINDOWSDIRECTORY) GetProcAddress( hInst, "GetSystemWindowsDirectoryA" );
  2749. pfnGetUsersWindowsDirectory = (PFN_GETWINDOWSDIRECTORY) GetProcAddress( hInst, "GetWindowsDirectoryA" );
  2750. ASSERT( pfnGetUsersWindowsDirectory ); // if NULL then we have a bug!
  2751. if( !pfnGetSystemWindowsDirectory ) {
  2752. pfnGetSystemWindowsDirectory = pfnGetUsersWindowsDirectory;
  2753. }
  2754. FreeLibrary( hInst );
  2755. }
  2756. // for Windows 9x, we need to consult with the registry shareddir first
  2757. // [paulti] - I have no idea why we need to do this -- this code came
  2758. // from Ralph!
  2759. HKEY hkey;
  2760. DWORD type;
  2761. DWORD cbPath = uSize;
  2762. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, txtSetupKey, 0, KEY_READ, &hkey) ==
  2763. ERROR_SUCCESS) {
  2764. RegQueryValueEx(hkey, txtSharedDir, 0, &type, (PBYTE) lpBuffer, &cbPath);
  2765. RegCloseKey(hkey);
  2766. }
  2767. // if this failed, then call the system functions
  2768. if( cbPath == uSize ) { // means couldn't read registry key
  2769. if( uiType == HH_SYSTEM_WINDOWS_DIRECTORY )
  2770. uiReturn = pfnGetSystemWindowsDirectory( lpBuffer, uSize );
  2771. else if( uiType == HH_USERS_WINDOWS_DIRECTORY )
  2772. uiReturn = pfnGetUsersWindowsDirectory( lpBuffer, uSize );
  2773. else
  2774. uiReturn = 0;
  2775. }
  2776. else
  2777. uiReturn = cbPath;
  2778. return uiReturn;
  2779. }
  2780. static const char txtGlobal[] = "global.col";
  2781. static const char txtColReg[] = "hhcolreg.dat";
  2782. static const char txtHelp[] = "help";
  2783. static const char txtHHDat[] = "hh.dat";
  2784. ///////////////////////////////////////////////////////////
  2785. //
  2786. // Get the help directory
  2787. //
  2788. // Note, this is always relative to the system's windows
  2789. // directory and not the user's windows directory.
  2790. // See HHGetWindowsDirectory for details on this.
  2791. //
  2792. UINT HHGetHelpDirectory( LPTSTR lpBuffer, UINT uSize )
  2793. {
  2794. UINT uiReturn = 0;
  2795. uiReturn = HHGetWindowsDirectory( lpBuffer, uSize );
  2796. CatPath( lpBuffer, txtHelp );
  2797. return uiReturn;
  2798. }
  2799. ///////////////////////////////////////////////////////////
  2800. //
  2801. // Get the full pathname to the global collections file
  2802. //
  2803. // Note, this is in always in the system's help directory.
  2804. //
  2805. UINT HHGetGlobalCollectionPathname( LPTSTR lpBuffer, UINT uSize, BOOL *pbNewPath )
  2806. {
  2807. UINT uiReturn = 0;
  2808. *pbNewPath = TRUE;
  2809. uiReturn = HHGetHelpDataPath( lpBuffer );
  2810. if (uiReturn != S_OK)
  2811. {
  2812. *pbNewPath = FALSE;
  2813. uiReturn = HHGetHelpDirectory( lpBuffer, uSize );
  2814. if( !IsDirectory(lpBuffer) )
  2815. CreatePath( lpBuffer );
  2816. }
  2817. CatPath( lpBuffer, txtColReg );
  2818. return uiReturn;
  2819. }
  2820. ///////////////////////////////////////////////////////////
  2821. //
  2822. // Get the full pathname to the old global collections file
  2823. //
  2824. // Note, this is in always in the user's windows\help directory
  2825. // since the old code did not handle the Terminal Server path correctly.
  2826. //
  2827. UINT HHGetOldGlobalCollectionPathname( LPTSTR lpBuffer, UINT uSize )
  2828. {
  2829. UINT uiReturn = 0;
  2830. uiReturn = HHGetHelpDirectory( lpBuffer, uSize );
  2831. if( !IsDirectory(lpBuffer) )
  2832. CreatePath( lpBuffer );
  2833. CatPath( lpBuffer, txtColReg );
  2834. return uiReturn;
  2835. }
  2836. typedef HRESULT (WINAPI *PFN_SHGETSPECIALFOLDERPATH)( HWND hWnd, LPSTR pszPath, int nFolder, BOOL fCreate );
  2837. static const char txtProfiles[] = "Profiles";
  2838. static const char txtUser[] = "Default User";
  2839. static const char txtAllUsers[] = "All Users";
  2840. static const char txtApplicationData[] = "Application Data";
  2841. static const char txtMicrosoft[] = "Microsoft";
  2842. static const char txtHTMLHelp[] = "HTML Help";
  2843. ///////////////////////////////////////////////////////////
  2844. //
  2845. // Get the full path to where the user's data file is stored
  2846. //
  2847. // Note, if the subdirectories of the path does not exist
  2848. // we will create them
  2849. //
  2850. // Note, the Shell32 function SHGetSpecialFolderPathA only exist
  2851. // on platforms with IE4 or later. For those platforms that
  2852. // do not have this API we will have to simulate the returned
  2853. // "%windir%\Profiles\%username%\Application Data" path
  2854. HRESULT HHGetUserDataPath( LPSTR pszPath )
  2855. {
  2856. HRESULT hResult = S_OK;
  2857. static PFN_SHGETSPECIALFOLDERPATH pfnSHGetSpecialFolderPath = NULL;
  2858. // get the pointer to this function in shell32
  2859. if( !pfnSHGetSpecialFolderPath ) {
  2860. HINSTANCE hInst = LoadLibrary( "Shell32" );
  2861. if( !hInst )
  2862. return S_FALSE;
  2863. pfnSHGetSpecialFolderPath = (PFN_SHGETSPECIALFOLDERPATH) GetProcAddress( hInst, "SHGetSpecialFolderPathA" );
  2864. FreeLibrary( hInst ); // since we already have a copy of Shell32 loaded, free it
  2865. }
  2866. // if this function does not exist then we need to similate the return path of
  2867. // "%windir%\Profiles\%username%\Application Data"
  2868. if( !pfnSHGetSpecialFolderPath ) {
  2869. HardCodeUserPath:
  2870. // get the system's Windows directory
  2871. HHGetWindowsDirectory( pszPath, _MAX_PATH, HH_SYSTEM_WINDOWS_DIRECTORY );
  2872. // append "Profiles"
  2873. CatPath( pszPath, txtProfiles );
  2874. if( !IsDirectory(pszPath) )
  2875. if( !CreateDirectory( pszPath, NULL ) )
  2876. return S_FALSE;
  2877. // append "User"
  2878. char szUsername[_MAX_PATH];
  2879. DWORD dwSize = sizeof(szUsername);
  2880. if( !GetUserName( szUsername, &dwSize ) )
  2881. strcpy( szUsername, txtUser );
  2882. CatPath( pszPath, szUsername );
  2883. if( !IsDirectory(pszPath) )
  2884. if( !CreateDirectory( pszPath, NULL ) )
  2885. return S_FALSE;
  2886. // append "Application Data"
  2887. CatPath( pszPath, txtApplicationData );
  2888. if( !IsDirectory(pszPath) )
  2889. if( !CreateDirectory( pszPath, NULL ) )
  2890. return S_FALSE;
  2891. }
  2892. else {
  2893. // now call it
  2894. hResult = pfnSHGetSpecialFolderPath( NULL, pszPath, CSIDL_APPDATA, 0 );
  2895. if (pszPath[0] == NULL)
  2896. goto HardCodeUserPath;
  2897. }
  2898. // append "Microsoft"
  2899. CatPath( pszPath, txtMicrosoft );
  2900. if( !IsDirectory(pszPath) )
  2901. if( !CreateDirectory( pszPath, NULL ) )
  2902. return S_FALSE;
  2903. // append "HTML Help"
  2904. CatPath( pszPath, txtHTMLHelp );
  2905. if( !IsDirectory(pszPath) )
  2906. if( !CreateDirectory( pszPath, NULL ) )
  2907. return S_FALSE;
  2908. return hResult;
  2909. }
  2910. ///////////////////////////////////////////////////////////
  2911. //
  2912. // Get the full pathname to the user's data file
  2913. //
  2914. // Note, older version of HTML Help always put the hh.dat file
  2915. // in the user's windows directory. Thus, if we find one there
  2916. // and not in the new user's directory we will copy over this file
  2917. // to the new location.
  2918. //
  2919. HRESULT HHGetUserDataPathname( LPSTR lpBuffer, UINT uSize )
  2920. {
  2921. HRESULT hResult = S_OK;
  2922. // check the new user data path first
  2923. if( (SUCCEEDED( hResult = HHGetUserDataPath( lpBuffer ))) ) {
  2924. // append the name of the hh.dat file to the path
  2925. CatPath( lpBuffer, txtHHDat );
  2926. // if file exists there then we are done
  2927. if( !IsFile(lpBuffer) ) {
  2928. // if the file does not exist in the new user's path then
  2929. // check the users's windows directory can copy it if found
  2930. char szHHDatPathname[_MAX_PATH];
  2931. HHGetWindowsDirectory( szHHDatPathname, sizeof(szHHDatPathname),
  2932. HH_USERS_WINDOWS_DIRECTORY );
  2933. CatPath( szHHDatPathname, txtHHDat );
  2934. if( IsFile( szHHDatPathname ) ) {
  2935. CopyFile( szHHDatPathname, lpBuffer, TRUE );
  2936. //DeleteFile( szHHDatPathname ); // should we nuke the old one?
  2937. }
  2938. }
  2939. }
  2940. return hResult;
  2941. }
  2942. typedef HRESULT (WINAPI *PFN_SHGETFOLDERPATH)( HWND hWnd, int nFolder, HANDLE hToken, DWORD dwFlags, LPTSTR pszPath );
  2943. #ifndef CSIDL_FLAG_CREATE
  2944. #define CSIDL_COMMON_APPDATA 0x0023
  2945. #define CSIDL_FLAG_CREATE 0x8000
  2946. #endif
  2947. ///////////////////////////////////////////////////////////
  2948. //
  2949. // Get the full path to where the common help data files lives
  2950. // hhcolreg.dat
  2951. //
  2952. // Note, if the subdirectories of the path does not exist
  2953. // we will create them
  2954. //
  2955. HRESULT HHGetHelpDataPath( LPSTR pszPath )
  2956. {
  2957. HRESULT hResult = S_OK;
  2958. static PFN_SHGETFOLDERPATH pfnSHGetFolderPath = NULL;
  2959. // get the pointer to this function in shell32
  2960. if( !pfnSHGetFolderPath ) {
  2961. HINSTANCE hInst = LoadLibrary( "Shell32" );
  2962. if( !hInst )
  2963. return S_FALSE;
  2964. pfnSHGetFolderPath = (PFN_SHGETFOLDERPATH) GetProcAddress( hInst, "SHGetFolderPathA" );
  2965. FreeLibrary( hInst ); // since we already have a copy of Shell32 loaded, free it
  2966. }
  2967. // if this function does not exist then we need to similate the return path of
  2968. // "%windir%\Profiles\All Users\Application Data"
  2969. if( pfnSHGetFolderPath ) {
  2970. // now call it
  2971. hResult = pfnSHGetFolderPath( NULL, CSIDL_FLAG_CREATE | CSIDL_COMMON_APPDATA, NULL, 0, pszPath);
  2972. if (pszPath[0] == NULL)
  2973. return S_FALSE;
  2974. }
  2975. else
  2976. return S_FALSE;
  2977. // append "Microsoft"
  2978. CatPath( pszPath, txtMicrosoft );
  2979. if( !IsDirectory(pszPath) )
  2980. if( !CreateDirectory( pszPath, NULL ) )
  2981. return S_FALSE;
  2982. // append "HTML Help"
  2983. CatPath( pszPath, txtHTMLHelp );
  2984. if( !IsDirectory(pszPath) )
  2985. if( !CreateDirectory( pszPath, NULL ) )
  2986. return S_FALSE;
  2987. return hResult;
  2988. }
  2989. ///////////////////////////////////////////////////////////
  2990. //
  2991. // Get the full path to where the common help data files lives
  2992. // hhcolreg.dat
  2993. //
  2994. // Note, if the subdirectories of the path does not exist
  2995. // we will create them
  2996. //
  2997. HRESULT HHGetCurUserDataPath( LPSTR pszPath )
  2998. {
  2999. HRESULT hResult = S_OK;
  3000. static PFN_SHGETFOLDERPATH pfnSHGetFolderPath = NULL;
  3001. // get the pointer to this function in shell32
  3002. if( !pfnSHGetFolderPath ) {
  3003. HINSTANCE hInst = LoadLibrary( "Shell32" );
  3004. if( !hInst )
  3005. return S_FALSE;
  3006. pfnSHGetFolderPath = (PFN_SHGETFOLDERPATH) GetProcAddress( hInst, "SHGetFolderPathA" );
  3007. FreeLibrary( hInst ); // since we already have a copy of Shell32 loaded, free it
  3008. }
  3009. // if this function does not exist then we need to similate the return path of
  3010. // "%windir%\Profiles\"username"\Application Data"
  3011. if( pfnSHGetFolderPath ) {
  3012. // now call it
  3013. hResult = pfnSHGetFolderPath( NULL, CSIDL_FLAG_CREATE | CSIDL_APPDATA , NULL, 0, pszPath);
  3014. if (pszPath[0] == NULL)
  3015. return S_FALSE;
  3016. }
  3017. else
  3018. return S_FALSE;
  3019. // append "Microsoft"
  3020. CatPath( pszPath, txtMicrosoft );
  3021. if( !IsDirectory(pszPath) )
  3022. if( !CreateDirectory( pszPath, NULL ) )
  3023. return S_FALSE;
  3024. // append "HTML Help"
  3025. CatPath( pszPath, txtHTMLHelp );
  3026. if( !IsDirectory(pszPath) )
  3027. if( !CreateDirectory( pszPath, NULL ) )
  3028. return S_FALSE;
  3029. return hResult;
  3030. }
  3031. ///////////////////////////////////////////////////////////
  3032. //
  3033. // NT Keyboard hidden UI support functions.
  3034. //
  3035. LRESULT SendMessageAnsiOrWide(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
  3036. {
  3037. if (IsWindowUnicode(hwnd))
  3038. {
  3039. return SendMessageW(hwnd, msg, wParam, lParam);
  3040. }
  3041. else
  3042. {
  3043. return SendMessageA(hwnd, msg, wParam, lParam) ;
  3044. }
  3045. }
  3046. void UiStateInitialize(HWND hwnd)
  3047. {
  3048. if (g_bWinNT5 && IsWindow(hwnd))
  3049. {
  3050. SendMessageAnsiOrWide(hwnd, WM_CHANGEUISTATE, MAKEWPARAM(UIS_INITIALIZE, 0), 0) ;
  3051. }
  3052. }
  3053. void UiStateChangeOnTab(HWND hwnd)
  3054. {
  3055. if (g_bWinNT5 && IsWindow(hwnd))
  3056. {
  3057. SendMessageAnsiOrWide(hwnd, WM_CHANGEUISTATE, MAKEWPARAM(UIS_CLEAR, UISF_HIDEFOCUS), 0) ;
  3058. }
  3059. }
  3060. void UiStateChangeOnAlt(HWND hwnd)
  3061. {
  3062. if (g_bWinNT5 && IsWindow(hwnd))
  3063. {
  3064. // The only thing we can do is just turn on the underlines.
  3065. SendMessageAnsiOrWide(hwnd, WM_CHANGEUISTATE, MAKEWPARAM(UIS_CLEAR, UISF_HIDEACCEL | UISF_HIDEFOCUS), 0) ;
  3066. }
  3067. }