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.

1657 lines
44 KiB

  1. //#include "pch.h"
  2. #pragma hdrstop
  3. #include "sautil.h"
  4. BOOL g_fNoWinHelp = FALSE;
  5. VOID ContextHelp(
  6. IN const DWORD* padwMap,
  7. IN HWND hwndDlg,
  8. IN UINT unMsg,
  9. IN WPARAM wparam,
  10. IN LPARAM lparam)
  11. // Calls WinHelp to popup context sensitive help. 'PadwMap' is an array
  12. // of control-ID help-ID pairs terminated with a 0,0 pair. 'UnMsg' is
  13. // WM_HELP or WM_CONTEXTMENU indicating the message received requesting
  14. // help. 'Wparam' and 'lparam' are the parameters of the message received
  15. // requesting help.
  16. //
  17. {
  18. HWND hwnd;
  19. UINT unType;
  20. TCHAR* pszHelpFile;
  21. ASSERT( unMsg==WM_HELP || unMsg==WM_CONTEXTMENU );
  22. // Don't try to do help if it won't work. See common\uiutil\ui.c.
  23. //
  24. {
  25. extern BOOL g_fNoWinHelp;
  26. if (g_fNoWinHelp)
  27. {
  28. return;
  29. }
  30. }
  31. if (unMsg == WM_HELP)
  32. {
  33. LPHELPINFO p = (LPHELPINFO )lparam;;
  34. TRACE3( "ContextHelp(WM_HELP,t=%d,id=%d,h=$%08x)",
  35. p->iContextType, p->iCtrlId,p->hItemHandle );
  36. if (p->iContextType != HELPINFO_WINDOW)
  37. {
  38. return;
  39. }
  40. hwnd = (HWND)p->hItemHandle;
  41. ASSERT( hwnd );
  42. unType = HELP_WM_HELP;
  43. }
  44. else
  45. {
  46. // Standard Win95 method that produces a one-item "What's This?" menu
  47. // that user must click to get help.
  48. //
  49. TRACE1( "ContextHelp(WM_CONTEXTMENU,h=$%08x)", wparam );
  50. hwnd = (HWND )wparam;
  51. unType = HELP_CONTEXTMENU;
  52. };
  53. // if (fRouter)
  54. // {
  55. // pszHelpFile = g_pszRouterHelpFile;
  56. // }
  57. // else
  58. // {
  59. // pszHelpFile = g_pszHelpFile;
  60. // }
  61. pszHelpFile = PszFromId (g_hinstDll, SID_HelpFile );
  62. TRACE1( "WinHelp(%s)", pszHelpFile );
  63. WinHelp( hwnd, pszHelpFile, unType, (ULONG_PTR ) padwMap );
  64. Free0 (pszHelpFile);
  65. }
  66. VOID
  67. AddContextHelpButton(
  68. IN HWND hwnd )
  69. /* Turns on title bar context help button in 'hwnd'.
  70. **
  71. ** Dlgedit.exe doesn't currently support adding this style at dialog
  72. ** resource edit time. When that's fixed set DS_CONTEXTHELP in the dialog
  73. ** definition and remove this routine.
  74. */
  75. {
  76. LONG lStyle;
  77. if (g_fNoWinHelp)
  78. return;
  79. lStyle = GetWindowLong( hwnd, GWL_EXSTYLE );
  80. if (lStyle)
  81. SetWindowLong( hwnd, GWL_EXSTYLE, lStyle | WS_EX_CONTEXTHELP );
  82. }
  83. /* Extended arguments for the MsgDlgUtil routine. Designed so zeroed gives
  84. ** default behaviors.
  85. */
  86. /*----------------------------------------------------------------------------
  87. ** Message popup
  88. **----------------------------------------------------------------------------
  89. */
  90. int
  91. MsgDlgUtil(
  92. IN HWND hwndOwner,
  93. IN DWORD dwMsg,
  94. IN OUT MSGARGS* pargs,
  95. IN HINSTANCE hInstance,
  96. IN DWORD dwTitle )
  97. /* Pops up a message dialog centered on 'hwndOwner'. 'DwMsg' is the
  98. ** string resource ID of the message text. 'Pargs' is a extended
  99. ** formatting arguments or NULL if none. 'hInstance' is the
  100. ** application/module handle where string resources are located.
  101. ** 'DwTitle' is the string ID of the dialog title.
  102. **
  103. ** Returns MessageBox-style code.
  104. */
  105. {
  106. TCHAR* pszUnformatted;
  107. TCHAR* pszResult;
  108. TCHAR* pszNotFound;
  109. int nResult;
  110. TRACE("MsgDlgUtil");
  111. /* A placeholder for missing strings components.
  112. */
  113. pszNotFound = TEXT("");
  114. /* Build the message string.
  115. */
  116. pszResult = pszNotFound;
  117. if (pargs && pargs->pszString)
  118. {
  119. FormatMessage(
  120. FORMAT_MESSAGE_FROM_STRING +
  121. FORMAT_MESSAGE_ALLOCATE_BUFFER +
  122. FORMAT_MESSAGE_ARGUMENT_ARRAY,
  123. pargs->pszString, 0, 0, (LPTSTR )&pszResult, 1,
  124. (va_list* )pargs->apszArgs );
  125. }
  126. else
  127. {
  128. pszUnformatted = PszFromId( hInstance, dwMsg );
  129. if (pszUnformatted)
  130. {
  131. FormatMessage(
  132. FORMAT_MESSAGE_FROM_STRING +
  133. FORMAT_MESSAGE_ALLOCATE_BUFFER +
  134. FORMAT_MESSAGE_ARGUMENT_ARRAY,
  135. pszUnformatted, 0, 0, (LPTSTR )&pszResult, 1,
  136. (va_list* )((pargs) ? pargs->apszArgs : NULL) );
  137. Free( pszUnformatted );
  138. }
  139. }
  140. if (!pargs || !pargs->fStringOutput)
  141. {
  142. TCHAR* pszTitle;
  143. DWORD dwFlags;
  144. HHOOK hhook;
  145. if (pargs && pargs->dwFlags != 0)
  146. dwFlags = pargs->dwFlags;
  147. else
  148. dwFlags = MB_ICONINFORMATION + MB_OK + MB_SETFOREGROUND;
  149. pszTitle = PszFromId( hInstance, dwTitle );
  150. if (hwndOwner)
  151. {
  152. /* Install hook that will get the message box centered on the
  153. ** owner window.
  154. */
  155. hhook = SetWindowsHookEx( WH_CALLWNDPROC,
  156. CenterDlgOnOwnerCallWndProc,
  157. hInstance, GetCurrentThreadId() );
  158. }
  159. else
  160. hhook = NULL;
  161. if (pszResult)
  162. {
  163. nResult = MessageBox( hwndOwner, pszResult, pszTitle, dwFlags );
  164. }
  165. if (hhook)
  166. UnhookWindowsHookEx( hhook );
  167. Free0( pszTitle );
  168. if (pszResult != pszNotFound)
  169. LocalFree( pszResult );
  170. }
  171. else
  172. {
  173. /* Caller wants the string without doing the popup.
  174. */
  175. pargs->pszOutput = (pszResult != pszNotFound) ? pszResult : NULL;
  176. nResult = IDOK;
  177. }
  178. return nResult;
  179. }
  180. VOID
  181. UnclipWindow(
  182. IN HWND hwnd )
  183. /* Moves window 'hwnd' so any clipped parts are again visible on the
  184. ** screen. The window is moved only as far as necessary to achieve this.
  185. */
  186. {
  187. RECT rect;
  188. INT dxScreen = GetSystemMetrics( SM_CXSCREEN );
  189. INT dyScreen = GetSystemMetrics( SM_CYSCREEN );
  190. GetWindowRect( hwnd, &rect );
  191. if (rect.right > dxScreen)
  192. rect.left = dxScreen - (rect.right - rect.left);
  193. if (rect.left < 0)
  194. rect.left = 0;
  195. if (rect.bottom > dyScreen)
  196. rect.top = dyScreen - (rect.bottom - rect.top);
  197. if (rect.top < 0)
  198. rect.top = 0;
  199. SetWindowPos(
  200. hwnd, NULL,
  201. rect.left, rect.top, 0, 0,
  202. SWP_NOZORDER + SWP_NOSIZE );
  203. }
  204. VOID
  205. CenterWindow(
  206. IN HWND hwnd,
  207. IN HWND hwndRef )
  208. /* Center window 'hwnd' on window 'hwndRef' or if 'hwndRef' is NULL on
  209. ** screen. The window position is adjusted so that no parts are clipped
  210. ** by the edge of the screen, if necessary. If 'hwndRef' has been moved
  211. ** off-screen with SetOffDesktop, the original position is used.
  212. */
  213. {
  214. RECT rectCur;
  215. LONG dxCur;
  216. LONG dyCur;
  217. RECT rectRef;
  218. LONG dxRef;
  219. LONG dyRef;
  220. GetWindowRect( hwnd, &rectCur );
  221. dxCur = rectCur.right - rectCur.left;
  222. dyCur = rectCur.bottom - rectCur.top;
  223. if (hwndRef)
  224. {
  225. // if (!SetOffDesktop( hwndRef, SOD_GetOrgRect, &rectRef ))
  226. GetWindowRect( hwndRef, &rectRef );
  227. }
  228. else
  229. {
  230. rectRef.top = rectRef.left = 0;
  231. rectRef.right = GetSystemMetrics( SM_CXSCREEN );
  232. rectRef.bottom = GetSystemMetrics( SM_CYSCREEN );
  233. }
  234. dxRef = rectRef.right - rectRef.left;
  235. dyRef = rectRef.bottom - rectRef.top;
  236. rectCur.left = rectRef.left + ((dxRef - dxCur) / 2);
  237. rectCur.top = rectRef.top + ((dyRef - dyCur) / 2);
  238. SetWindowPos(
  239. hwnd, NULL,
  240. rectCur.left, rectCur.top, 0, 0,
  241. SWP_NOZORDER + SWP_NOSIZE );
  242. UnclipWindow( hwnd );
  243. }
  244. LRESULT CALLBACK
  245. CenterDlgOnOwnerCallWndProc(
  246. int code,
  247. WPARAM wparam,
  248. LPARAM lparam )
  249. /* Standard Win32 CallWndProc hook callback that looks for the next dialog
  250. ** started and centers it on it's owner window.
  251. */
  252. {
  253. /* Arrive here when any window procedure associated with our thread is
  254. ** called.
  255. */
  256. if (!wparam)
  257. {
  258. CWPSTRUCT* p = (CWPSTRUCT* )lparam;
  259. /* The message is from outside our process. Look for the MessageBox
  260. ** dialog initialization message and take that opportunity to center
  261. ** the dialog on it's owner's window.
  262. */
  263. if (p->message == WM_INITDIALOG)
  264. CenterWindow( p->hwnd, GetParent( p->hwnd ) );
  265. }
  266. return 0;
  267. }
  268. TCHAR*
  269. PszFromId(
  270. IN HINSTANCE hInstance,
  271. IN DWORD dwStringId )
  272. /* String resource message loader routine.
  273. **
  274. ** Returns the address of a heap block containing the string corresponding
  275. ** to string resource 'dwStringId' or NULL if error. It is caller's
  276. ** responsibility to Free the returned string.
  277. */
  278. {
  279. HRSRC hrsrc;
  280. TCHAR* pszBuf;
  281. int cchBuf = 256;
  282. int cchGot;
  283. for (;;)
  284. {
  285. pszBuf = (TCHAR*)Malloc( cchBuf * sizeof(TCHAR) );
  286. if (!pszBuf)
  287. break;
  288. /* LoadString wants to deal with character-counts rather than
  289. ** byte-counts...weird. Oh, and if you're thinking I could
  290. ** FindResource then SizeofResource to figure out the string size, be
  291. ** advised it doesn't work. From perusing the LoadString source, it
  292. ** appears the RT_STRING resource type requests a segment of 16
  293. ** strings not an individual string.
  294. */
  295. cchGot = LoadString( hInstance, (UINT )dwStringId, pszBuf, cchBuf );
  296. if (cchGot < cchBuf - 1)
  297. {
  298. TCHAR *pszTemp = pszBuf;
  299. /* Good, got the whole string. Reduce heap block to actual size
  300. ** needed.
  301. */
  302. pszBuf = (TCHAR*)Realloc( pszBuf, (cchGot + 1) * sizeof(TCHAR));
  303. if(NULL == pszBuf)
  304. {
  305. Free(pszTemp);
  306. }
  307. break;
  308. }
  309. /* Uh oh, LoadStringW filled the buffer entirely which could mean the
  310. ** string was truncated. Try again with a larger buffer to be sure it
  311. ** wasn't.
  312. */
  313. Free( pszBuf );
  314. cchBuf += 256;
  315. TRACE1("Grow string buf to %d",cchBuf);
  316. }
  317. return pszBuf;
  318. }
  319. TCHAR*
  320. GetText(
  321. IN HWND hwnd )
  322. /* Returns heap block containing the text contents of the window 'hwnd' or
  323. ** NULL. It is caller's responsibility to Free the returned string.
  324. */
  325. {
  326. INT cch;
  327. TCHAR* psz;
  328. cch = GetWindowTextLength( hwnd );
  329. psz = (TCHAR*)Malloc( (cch + 1) * sizeof(TCHAR) );
  330. if (psz)
  331. {
  332. *psz = TEXT('\0');
  333. GetWindowText( hwnd, psz, cch + 1 );
  334. }
  335. return psz;
  336. }
  337. BOOL
  338. GetErrorText(
  339. DWORD dwError,
  340. TCHAR** ppszError )
  341. /* Fill caller's '*ppszError' with the address of a LocalAlloc'ed heap
  342. ** block containing the error text associated with error 'dwError'. It is
  343. ** caller's responsibility to LocalFree the returned string.
  344. **
  345. ** Returns true if successful, false otherwise.
  346. */
  347. {
  348. #define MAXRASERRORLEN 256
  349. TCHAR szBuf[ MAXRASERRORLEN + 1 ];
  350. DWORD dwFlags;
  351. HANDLE hmodule;
  352. DWORD cch;
  353. /* Don't panic if the RAS API address is not loaded. Caller may be trying
  354. ** and get an error up during LoadRas.
  355. */
  356. // if ((Rasapi32DllLoaded() || RasRpcDllLoaded())
  357. // && g_pRasGetErrorString
  358. // && g_pRasGetErrorString(
  359. if (RasGetErrorString ((UINT)dwError, (LPTSTR)szBuf, MAXRASERRORLEN) == 0)
  360. {
  361. /* It's a RAS error.
  362. */
  363. *ppszError = (TCHAR*)LocalAlloc( LPTR, (lstrlen( szBuf ) + 1) * sizeof(TCHAR) );
  364. if (!*ppszError)
  365. return FALSE;
  366. lstrcpy( *ppszError, szBuf );
  367. return TRUE;
  368. }
  369. /* The rest adapted from BLT's LoadSystem routine.
  370. */
  371. dwFlags = FORMAT_MESSAGE_ALLOCATE_BUFFER + FORMAT_MESSAGE_IGNORE_INSERTS;
  372. if (dwError >= MIN_LANMAN_MESSAGE_ID && dwError <= MAX_LANMAN_MESSAGE_ID)
  373. {
  374. /* It's a net error.
  375. */
  376. dwFlags += FORMAT_MESSAGE_FROM_HMODULE;
  377. hmodule = GetModuleHandle( TEXT("NETMSG.DLL") );
  378. }
  379. else
  380. {
  381. /* It must be a system error.
  382. */
  383. dwFlags += FORMAT_MESSAGE_FROM_SYSTEM;
  384. hmodule = NULL;
  385. }
  386. cch = FormatMessage(
  387. dwFlags, hmodule, dwError, 0, (LPTSTR )ppszError, 1, NULL );
  388. return (cch > 0);
  389. }
  390. int
  391. ErrorDlgUtil(
  392. IN HWND hwndOwner,
  393. IN DWORD dwOperation,
  394. IN DWORD dwError,
  395. IN OUT ERRORARGS* pargs,
  396. IN HINSTANCE hInstance,
  397. IN DWORD dwTitle,
  398. IN DWORD dwFormat )
  399. /* Pops up a modal error dialog centered on 'hwndOwner'. 'DwOperation' is
  400. ** the string resource ID of the string describing the operation underway
  401. ** when the error occurred. 'DwError' is the code of the system or RAS
  402. ** error that occurred. 'Pargs' is a extended formatting arguments or
  403. ** NULL if none. 'hInstance' is the application/module handle where
  404. ** string resources are located. 'DwTitle' is the string ID of the dialog
  405. ** title. 'DwFormat' is the string ID of the error format title.
  406. **
  407. ** Returns MessageBox-style code.
  408. */
  409. {
  410. TCHAR* pszUnformatted;
  411. TCHAR* pszOp;
  412. TCHAR szErrorNum[ 50 ];
  413. TCHAR* pszError;
  414. TCHAR* pszResult;
  415. TCHAR* pszNotFound;
  416. int nResult;
  417. TRACE("ErrorDlgUtil");
  418. /* A placeholder for missing strings components.
  419. */
  420. pszNotFound = TEXT("");
  421. /* Build the error number string.
  422. */
  423. if (dwError > 0x7FFFFFFF)
  424. wsprintf( szErrorNum, TEXT("0x%X"), dwError );
  425. else
  426. wsprintf( szErrorNum, TEXT("%u"), dwError );
  427. /* Build the error text string.
  428. */
  429. if (!GetErrorText( dwError, &pszError ))
  430. pszError = pszNotFound;
  431. /* Build the operation string.
  432. */
  433. pszUnformatted = PszFromId( hInstance, dwOperation );
  434. pszOp = pszNotFound;
  435. if (pszUnformatted)
  436. {
  437. FormatMessage(
  438. FORMAT_MESSAGE_FROM_STRING +
  439. FORMAT_MESSAGE_ALLOCATE_BUFFER +
  440. FORMAT_MESSAGE_ARGUMENT_ARRAY,
  441. pszUnformatted, 0, 0, (LPTSTR )&pszOp, 1,
  442. (va_list* )((pargs) ? pargs->apszOpArgs : NULL) );
  443. Free( pszUnformatted );
  444. }
  445. /* Call MsgDlgUtil with the standard arguments plus any auxillary format
  446. ** arguments.
  447. */
  448. pszUnformatted = PszFromId( hInstance, dwFormat );
  449. pszResult = pszNotFound;
  450. if (pszUnformatted)
  451. {
  452. MSGARGS msgargs;
  453. ZeroMemory( &msgargs, sizeof(msgargs) );
  454. msgargs.dwFlags = MB_ICONEXCLAMATION + MB_OK + MB_SETFOREGROUND;
  455. msgargs.pszString = pszUnformatted;
  456. msgargs.apszArgs[ 0 ] = pszOp;
  457. msgargs.apszArgs[ 1 ] = szErrorNum;
  458. msgargs.apszArgs[ 2 ] = pszError;
  459. if (pargs)
  460. {
  461. msgargs.fStringOutput = pargs->fStringOutput;
  462. CopyMemory( &msgargs.apszArgs[ 3 ], pargs->apszAuxFmtArgs,
  463. 3 * sizeof(TCHAR) );
  464. }
  465. nResult =
  466. MsgDlgUtil(
  467. hwndOwner, 0, &msgargs, hInstance, dwTitle );
  468. Free( pszUnformatted );
  469. if (pargs && pargs->fStringOutput)
  470. pargs->pszOutput = msgargs.pszOutput;
  471. }
  472. if (pszOp != pszNotFound)
  473. LocalFree( pszOp );
  474. if (pszError != pszNotFound)
  475. LocalFree( pszError );
  476. return nResult;
  477. }
  478. int MsgDlgUtil(IN HWND hwndOwner, IN DWORD dwMsg, IN OUT MSGARGS* pargs, IN HINSTANCE hInstance, IN DWORD dwTitle);
  479. #define MsgDlg(h,m,a) \
  480. MsgDlgUtil(h,m,a,g_hinstDll,SID_PopupTitle)
  481. #define ErrorDlg(h,o,e,a) \
  482. ErrorDlgUtil(h,o,e,a,g_hinstDll,SID_PopupTitle,SID_FMT_ErrorMsg)
  483. // LVX stuff (cut-n-paste'd from ...\net\rras\ras\ui\common\uiutil\lvx.c, etc.
  484. static LPCTSTR g_lvxcbContextId = NULL;
  485. BOOL
  486. ListView_IsCheckDisabled (
  487. IN HWND hwndLv,
  488. IN INT iItem)
  489. /* Returns true if the check box of item 'iItem' of listview of checkboxes
  490. ** 'hwndLv' is disabled, false otherwise.
  491. */
  492. {
  493. UINT unState;
  494. unState = ListView_GetItemState( hwndLv, iItem, LVIS_STATEIMAGEMASK );
  495. if ((unState == INDEXTOSTATEIMAGEMASK( SI_DisabledChecked )) ||
  496. (unState == INDEXTOSTATEIMAGEMASK( SI_DisabledUnchecked )))
  497. return TRUE;
  498. return FALSE;
  499. }
  500. VOID
  501. ListView_SetCheck(
  502. IN HWND hwndLv,
  503. IN INT iItem,
  504. IN BOOL fCheck )
  505. /* Sets the check mark on item 'iItem' of listview of checkboxes 'hwndLv'
  506. ** to checked if 'fCheck' is true or unchecked if false.
  507. */
  508. {
  509. NM_LISTVIEW nmlv;
  510. if (ListView_IsCheckDisabled(hwndLv, iItem))
  511. return;
  512. ListView_SetItemState( hwndLv, iItem,
  513. INDEXTOSTATEIMAGEMASK( (fCheck) ? SI_Checked : SI_Unchecked ),
  514. LVIS_STATEIMAGEMASK );
  515. nmlv.hdr.code = LVXN_SETCHECK;
  516. nmlv.hdr.hwndFrom = hwndLv;
  517. nmlv.iItem = iItem;
  518. FORWARD_WM_NOTIFY(
  519. GetParent(hwndLv), GetDlgCtrlID(hwndLv), &nmlv, SendMessage
  520. );
  521. }
  522. VOID*
  523. ListView_GetParamPtr(
  524. IN HWND hwndLv,
  525. IN INT iItem )
  526. /* Returns the lParam address of the 'iItem' item in 'hwndLv' or NULL if
  527. ** none or error.
  528. */
  529. {
  530. LV_ITEM item;
  531. ZeroMemory( &item, sizeof(item) );
  532. item.mask = LVIF_PARAM;
  533. item.iItem = iItem;
  534. if (!ListView_GetItem( hwndLv, &item ))
  535. return NULL;
  536. return (VOID* )item.lParam;
  537. }
  538. BOOL
  539. ListView_GetCheck(
  540. IN HWND hwndLv,
  541. IN INT iItem )
  542. /* Returns true if the check box of item 'iItem' of listview of checkboxes
  543. ** 'hwndLv' is checked, false otherwise. This function works on disabled
  544. ** check boxes as well as enabled ones.
  545. */
  546. {
  547. UINT unState;
  548. unState = ListView_GetItemState( hwndLv, iItem, LVIS_STATEIMAGEMASK );
  549. return !!((unState == INDEXTOSTATEIMAGEMASK( SI_Checked )) ||
  550. (unState == INDEXTOSTATEIMAGEMASK( SI_DisabledChecked )));
  551. }
  552. LRESULT APIENTRY
  553. LvxcbProc(
  554. IN HWND hwnd,
  555. IN UINT unMsg,
  556. IN WPARAM wparam,
  557. IN LPARAM lparam )
  558. /* List view subclass window procedure to trap toggle-check events.
  559. */
  560. {
  561. WNDPROC pOldProc;
  562. INT iItem;
  563. BOOL fSet;
  564. BOOL fClear;
  565. BOOL fToggle;
  566. iItem = -1;
  567. fSet = fClear = fToggle = FALSE;
  568. if (unMsg == WM_LBUTTONDOWN)
  569. {
  570. LV_HITTESTINFO info;
  571. /* Left mouse button pressed over checkbox icon toggles state.
  572. ** Normally, we'd use LVHT_ONITEMSTATEICON and be done with it, but we
  573. ** want to work with our cool owner-drawn list view extensions in
  574. ** which case the control doesn't know where the icon is on the item,
  575. ** so it returns a hit anywhere on the item anyway.
  576. */
  577. ZeroMemory( &info, sizeof(info) );
  578. info.pt.x = LOWORD( lparam );
  579. info.pt.y = HIWORD( lparam );
  580. info.flags = LVHT_ONITEM;
  581. iItem = ListView_HitTest( hwnd, &info );
  582. if (iItem >= 0)
  583. {
  584. /* OK, it's over item 'iItem'. Now figure out if it's over the
  585. ** checkbox. Note this currently doesn't account for use of the
  586. ** "indent" feature on an owner-drawn item.
  587. */
  588. if ((INT )(LOWORD( lparam )) >= GetSystemMetrics( SM_CXSMICON ))
  589. iItem = -1;
  590. else
  591. fToggle = TRUE;
  592. }
  593. }
  594. else if (unMsg == WM_LBUTTONDBLCLK)
  595. {
  596. LV_HITTESTINFO info;
  597. /* Left mouse button double clicked over any area toggles state.
  598. ** Normally, we'd use LVHT_ONITEMSTATEICON and be done with it, but we
  599. ** want to work with our cool owner-drawn list view extensions in
  600. ** which case the control doesn't know where the icon is on the item,
  601. ** so it returns a hit anywhere on the item anyway.
  602. */
  603. ZeroMemory( &info, sizeof(info) );
  604. info.pt.x = LOWORD( lparam );
  605. info.pt.y = HIWORD( lparam );
  606. info.flags = LVHT_ONITEM;
  607. iItem = ListView_HitTest( hwnd, &info );
  608. if (iItem >= 0)
  609. {
  610. /* OK, it's over item 'iItem'. If the click does not occur
  611. * over a checkbox, inform the parent of the double click.
  612. */
  613. if ((INT )(LOWORD( lparam )) >= GetSystemMetrics( SM_CXSMICON )) {
  614. NM_LISTVIEW nmlv;
  615. nmlv.hdr.code = LVXN_DBLCLK;
  616. nmlv.hdr.hwndFrom = hwnd;
  617. nmlv.iItem = iItem;
  618. FORWARD_WM_NOTIFY(
  619. GetParent(hwnd), GetDlgCtrlID(hwnd), &nmlv, SendMessage);
  620. iItem = -1;
  621. }
  622. /*
  623. * Otherwise, toggle the state.
  624. */
  625. else
  626. fToggle = TRUE;
  627. }
  628. }
  629. else if (unMsg == WM_CHAR)
  630. {
  631. /* Space bar pressed with item selected toggles check.
  632. ** Plus or Equals keys set check.
  633. ** Minus key clears check.
  634. */
  635. switch (wparam)
  636. {
  637. case TEXT(' '):
  638. fToggle = TRUE;
  639. break;
  640. case TEXT('+'):
  641. case TEXT('='):
  642. fSet = TRUE;
  643. break;
  644. case TEXT('-'):
  645. fClear = TRUE;
  646. break;
  647. }
  648. if (fToggle || fSet || fClear)
  649. iItem = ListView_GetNextItem( hwnd, -1, LVNI_SELECTED );
  650. }
  651. else if (unMsg == WM_KEYDOWN)
  652. {
  653. /* Left arrow becomes up arrow and right arrow becomes down arrow so
  654. ** the list of checkboxes behaves just like a static group of
  655. ** checkboxes.
  656. */
  657. if (wparam == VK_LEFT)
  658. wparam = VK_UP;
  659. else if (wparam == VK_RIGHT)
  660. wparam = VK_DOWN;
  661. }
  662. if (iItem >= 0)
  663. {
  664. /* If we are handling the spacebar, plus, minus, or equals,
  665. ** the change we make applies to all the selected items;
  666. ** hence the do {} while(WM_CHAR).
  667. */
  668. do {
  669. if (fToggle)
  670. {
  671. UINT unOldState;
  672. BOOL fCheck;
  673. fCheck = ListView_GetCheck( hwnd, iItem );
  674. ListView_SetCheck( hwnd, iItem, !fCheck );
  675. }
  676. else if (fSet)
  677. {
  678. if (!ListView_GetCheck( hwnd, iItem ))
  679. ListView_SetCheck( hwnd, iItem, TRUE );
  680. }
  681. else if (fClear)
  682. {
  683. if (ListView_GetCheck( hwnd, iItem ))
  684. ListView_SetCheck( hwnd, iItem, FALSE );
  685. }
  686. iItem = ListView_GetNextItem(hwnd, iItem, LVNI_SELECTED);
  687. } while(iItem >= 0 && unMsg == WM_CHAR);
  688. if (fSet || fClear) {
  689. /* Don't pass to listview to avoid beep.
  690. */
  691. return 0;
  692. }
  693. }
  694. pOldProc = (WNDPROC )GetProp( hwnd, g_lvxcbContextId );
  695. if (pOldProc)
  696. return CallWindowProc( pOldProc, hwnd, unMsg, wparam, lparam );
  697. return 0;
  698. }
  699. BOOL
  700. ListView_InstallChecks(
  701. IN HWND hwndLv,
  702. IN HINSTANCE hinst )
  703. /* Initialize "list of checkbox" handling for listview 'hwndLv'. 'Hinst'
  704. ** is the module instance containing the two checkbox icons. See LVX.RC.
  705. **
  706. ** Returns true if successful, false otherwise. Caller must eventually
  707. ** call 'ListView_UninstallChecks', typically in WM_DESTROY processing.
  708. */
  709. {
  710. HICON hIcon;
  711. HIMAGELIST himl;
  712. WNDPROC pOldProc;
  713. // pmay: 397395
  714. //
  715. // Prevent endless loops resulting from accidentally calling this
  716. // api twice.
  717. //
  718. pOldProc = (WNDPROC)GetWindowLongPtr(hwndLv, GWLP_WNDPROC);
  719. if (pOldProc == LvxcbProc)
  720. {
  721. return TRUE;
  722. }
  723. /* Build checkbox image lists.
  724. */
  725. himl = ImageList_Create(
  726. GetSystemMetrics( SM_CXSMICON ),
  727. GetSystemMetrics( SM_CYSMICON ),
  728. ILC_MASK | ILC_MIRROR, 2, 2 );
  729. /* The order these are added is significant since it implicitly
  730. ** establishes the state indices matching SI_Unchecked and SI_Checked.
  731. */
  732. hIcon = LoadIcon( hinst, MAKEINTRESOURCE( IID_Unchecked ) );
  733. if ( NULL != hIcon )
  734. {
  735. ImageList_AddIcon( himl, hIcon );
  736. DeleteObject( hIcon );
  737. }
  738. hIcon = LoadIcon( hinst, MAKEINTRESOURCE( IID_Checked ) );
  739. if ( NULL != hIcon )
  740. {
  741. ImageList_AddIcon( himl, hIcon );
  742. DeleteObject( hIcon );
  743. }
  744. hIcon = LoadIcon( hinst, MAKEINTRESOURCE( IID_DisabledUnchecked ) );
  745. if ( NULL != hIcon )
  746. {
  747. ImageList_AddIcon( himl, hIcon );
  748. DeleteObject( hIcon );
  749. }
  750. hIcon = LoadIcon( hinst, MAKEINTRESOURCE( IID_DisabledChecked ) );
  751. if ( NULL != hIcon )
  752. {
  753. ImageList_AddIcon( himl, hIcon );
  754. DeleteObject( hIcon );
  755. }
  756. ListView_SetImageList( hwndLv, himl, LVSIL_STATE );
  757. /* Register atom for use in the Windows XxxProp calls which are used to
  758. ** associate the old WNDPROC with the listview window handle.
  759. */
  760. if (!g_lvxcbContextId)
  761. g_lvxcbContextId = (LPCTSTR )GlobalAddAtom( _T("RASLVXCB") );
  762. if (!g_lvxcbContextId)
  763. return FALSE;
  764. /* Subclass the current window procedure.
  765. */
  766. pOldProc = (WNDPROC)SetWindowLongPtr(
  767. hwndLv, GWLP_WNDPROC, (ULONG_PTR)LvxcbProc );
  768. return SetProp( hwndLv, g_lvxcbContextId, (HANDLE )pOldProc );
  769. }
  770. VOID
  771. ListView_InsertSingleAutoWidthColumn(
  772. HWND hwndLv )
  773. // Insert a single auto-sized column into listview 'hwndLv', e.g. for a
  774. // list of checkboxes with no visible column header.
  775. //
  776. {
  777. LV_COLUMN col;
  778. ZeroMemory( &col, sizeof(col) );
  779. col.mask = LVCF_FMT;
  780. col.fmt = LVCFMT_LEFT;
  781. ListView_InsertColumn( hwndLv, 0, &col );
  782. ListView_SetColumnWidth( hwndLv, 0, LVSCW_AUTOSIZE );
  783. }
  784. TCHAR*
  785. Ellipsisize(
  786. IN HDC hdc,
  787. IN TCHAR* psz,
  788. IN INT dxColumn,
  789. IN INT dxColText OPTIONAL )
  790. /* Returns a heap string containing the 'psz' shortened to fit in the
  791. ** given width, if necessary, by truncating and adding "...". 'Hdc' is the
  792. ** device context with the appropiate font selected. 'DxColumn' is the
  793. ** width of the column. It is caller's responsibility to Free the
  794. ** returned string.
  795. */
  796. {
  797. const TCHAR szDots[] = TEXT("...");
  798. SIZE size;
  799. TCHAR* pszResult;
  800. TCHAR* pszResultLast;
  801. TCHAR* pszResult2nd;
  802. DWORD cch;
  803. cch = lstrlen( psz );
  804. pszResult = (TCHAR*)Malloc( (cch * sizeof(TCHAR)) + sizeof(szDots) );
  805. if (!pszResult)
  806. return NULL;
  807. lstrcpy( pszResult, psz );
  808. dxColumn -= dxColText;
  809. if (dxColumn <= 0)
  810. {
  811. /* None of the column text will be visible so bag the calculations and
  812. ** just return the original string.
  813. */
  814. return pszResult;
  815. }
  816. if (!GetTextExtentPoint32( hdc, pszResult, cch, &size ))
  817. {
  818. Free( pszResult );
  819. return NULL;
  820. }
  821. pszResult2nd = CharNext( pszResult );
  822. pszResultLast = pszResult + cch;
  823. while (size.cx > dxColumn && pszResultLast > pszResult2nd)
  824. {
  825. /* Doesn't fit. Lop off a character, add the ellipsis, and try again.
  826. ** The minimum result is "..." for empty original or "x..." for
  827. ** non-empty original.
  828. */
  829. pszResultLast = CharPrev( pszResult2nd, pszResultLast );
  830. lstrcpy( pszResultLast, szDots );
  831. if (!GetTextExtentPoint( hdc, pszResult, lstrlen( pszResult ), &size ))
  832. {
  833. Free( pszResult );
  834. return NULL;
  835. }
  836. }
  837. return pszResult;
  838. }
  839. BOOL
  840. LvxDrawItem(
  841. IN DRAWITEMSTRUCT* pdis,
  842. IN PLVXCALLBACK pLvxCallback )
  843. /* Respond to WM_DRAWITEM by drawing the list view item. 'Pdis' is the
  844. ** information sent by the system. 'PLvxCallback' is caller's callback to
  845. ** get information about drawing the control.
  846. **
  847. ** Returns true is processed the message, false otherwise.
  848. */
  849. {
  850. LV_ITEM item;
  851. INT i;
  852. INT dxState;
  853. INT dyState;
  854. INT dxSmall;
  855. INT dySmall;
  856. INT dxIndent;
  857. UINT uiStyleState;
  858. UINT uiStyleSmall;
  859. HIMAGELIST himlState;
  860. HIMAGELIST himlSmall;
  861. LVXDRAWINFO* pDrawInfo;
  862. RECT rc;
  863. RECT rcClient;
  864. BOOL fEnabled;
  865. BOOL fSelected;
  866. HDC hdc;
  867. HFONT hfont;
  868. TRACE3("LvxDrawItem,i=%d,a=$%X,s=$%X",
  869. pdis->itemID,pdis->itemAction,pdis->itemState);
  870. /* Make sure this is something we want to handle.
  871. */
  872. if (pdis->CtlType != ODT_LISTVIEW)
  873. return FALSE;
  874. if (pdis->itemAction != ODA_DRAWENTIRE
  875. && pdis->itemAction != ODA_SELECT
  876. && pdis->itemAction != ODA_FOCUS)
  877. {
  878. return TRUE;
  879. }
  880. /* Get item information from the list view.
  881. */
  882. ZeroMemory( &item, sizeof(item) );
  883. item.mask = LVIF_IMAGE + LVIF_STATE;
  884. item.iItem = pdis->itemID;
  885. item.stateMask = LVIS_STATEIMAGEMASK;
  886. if (!ListView_GetItem( pdis->hwndItem, &item ))
  887. {
  888. TRACE("LvxDrawItem GetItem failed");
  889. return TRUE;
  890. }
  891. /* Stash some useful stuff for reference later.
  892. */
  893. fEnabled = IsWindowEnabled( pdis->hwndItem )
  894. && !(pdis->itemState & ODS_DISABLED);
  895. fSelected = (pdis->itemState & ODS_SELECTED);
  896. GetClientRect( pdis->hwndItem, &rcClient );
  897. /* Callback owner to get drawing information.
  898. */
  899. ASSERT(pLvxCallback);
  900. pDrawInfo = pLvxCallback( pdis->hwndItem, pdis->itemID );
  901. ASSERT(pDrawInfo);
  902. /* Get image list icon sizes now, though we draw them last because their
  903. ** background is set up during first column text output.
  904. */
  905. dxState = dyState = 0;
  906. himlState = ListView_GetImageList( pdis->hwndItem, LVSIL_STATE );
  907. if (himlState)
  908. ImageList_GetIconSize( himlState, &dxState, &dyState );
  909. dxSmall = dySmall = 0;
  910. himlSmall = ListView_GetImageList( pdis->hwndItem, LVSIL_SMALL );
  911. if (himlSmall)
  912. ImageList_GetIconSize( himlSmall, &dxSmall, &dySmall );
  913. uiStyleState = uiStyleSmall = ILD_TRANSPARENT;
  914. /* Figure out the number of pixels to indent the item, if any.
  915. */
  916. if (pDrawInfo->dxIndent >= 0)
  917. dxIndent = pDrawInfo->dxIndent;
  918. else
  919. {
  920. if (dxSmall > 0)
  921. dxIndent = dxSmall;
  922. else
  923. dxIndent = GetSystemMetrics( SM_CXSMICON );
  924. }
  925. /* Get a device context for the window and set it up with the font the
  926. ** control says it's using. (Can't use the one that comes in the
  927. ** DRAWITEMSTRUCT because sometimes it has the wrong rectangle, see bug
  928. ** 13106)
  929. */
  930. hdc = GetDC( pdis->hwndItem );
  931. if(NULL == hdc)
  932. {
  933. return FALSE;
  934. }
  935. hfont = (HFONT )SendMessage( pdis->hwndItem, WM_GETFONT, 0, 0 );
  936. if (hfont)
  937. SelectObject( hdc, hfont );
  938. /* Set things up as if we'd just got done processing a column that ends
  939. ** after the icons, then loop thru each column from left to right.
  940. */
  941. rc.right = pdis->rcItem.left + dxIndent + dxState + dxSmall;
  942. rc.top = pdis->rcItem.top;
  943. rc.bottom = pdis->rcItem.bottom;
  944. for (i = 0; i < pDrawInfo->cCols; ++i)
  945. {
  946. TCHAR szText[ LVX_MaxColTchars + 1 ];
  947. TCHAR* pszText;
  948. INT dxCol;
  949. /* Get the column width, adding any index and icon width to the first
  950. ** column.
  951. */
  952. dxCol = ListView_GetColumnWidth( pdis->hwndItem, i );
  953. if (i == 0)
  954. dxCol -= dxIndent + dxState + dxSmall;
  955. szText[ 0 ] = TEXT('\0');
  956. ListView_GetItemText( pdis->hwndItem, pdis->itemID, i, szText,
  957. LVX_MaxColTchars + 1 );
  958. /* Update rectangle to enclose just this one item's column 'i'.
  959. */
  960. rc.left = rc.right;
  961. rc.right = rc.left + dxCol;
  962. if ((pDrawInfo->dwFlags & LVXDI_DxFill)
  963. && i == pDrawInfo->cCols - 1)
  964. {
  965. INT dxWnd = pdis->rcItem.left + rcClient.right;
  966. if (rc.right < dxWnd)
  967. {
  968. /* When the last column does not fill out a full controls
  969. ** width of space, extend it to the right so it does. Note
  970. ** this does not mean the user can't scroll off to the right
  971. ** if they want.
  972. ** (Abolade-Gbadegesin 03-27-96)
  973. ** Don't subtrace rc.left when there is only one column;
  974. ** this accounts for the space needed for icons.
  975. */
  976. rc.right = pdis->rcItem.right = dxWnd;
  977. if (i == 0) {
  978. ListView_SetColumnWidth(pdis->hwndItem, i, rc.right);
  979. }
  980. else {
  981. ListView_SetColumnWidth(
  982. pdis->hwndItem, i, rc.right - rc.left );
  983. }
  984. }
  985. }
  986. /* Lop the text and append "..." if it won't fit in the column.
  987. */
  988. pszText = Ellipsisize( hdc, szText, rc.right - rc.left, LVX_dxColText );
  989. if (!pszText)
  990. continue;
  991. /* Figure out the appropriate text and background colors for the
  992. ** current item state.
  993. */
  994. if (fEnabled)
  995. {
  996. if (fSelected)
  997. {
  998. SetTextColor( hdc, GetSysColor( COLOR_HIGHLIGHTTEXT ) );
  999. SetBkColor( hdc, GetSysColor( COLOR_HIGHLIGHT ) );
  1000. if (pDrawInfo->dwFlags & LVXDI_Blend50Sel)
  1001. uiStyleSmall |= ILD_BLEND50;
  1002. }
  1003. else
  1004. {
  1005. if (pDrawInfo->adwFlags[ i ] & LVXDIA_3dFace)
  1006. {
  1007. SetTextColor( hdc, GetSysColor( COLOR_WINDOWTEXT ) );
  1008. SetBkColor( hdc, GetSysColor( COLOR_3DFACE ) );
  1009. }
  1010. else
  1011. {
  1012. SetTextColor( hdc, GetSysColor( COLOR_WINDOWTEXT ) );
  1013. SetBkColor( hdc, GetSysColor( COLOR_WINDOW ) );
  1014. }
  1015. }
  1016. }
  1017. else
  1018. {
  1019. if (pDrawInfo->adwFlags[ i ] & LVXDIA_Static)
  1020. {
  1021. SetTextColor( hdc, GetSysColor( COLOR_WINDOWTEXT ) );
  1022. SetBkColor( hdc, GetSysColor( COLOR_3DFACE ) );
  1023. }
  1024. else
  1025. {
  1026. SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) );
  1027. SetBkColor( hdc, GetSysColor( COLOR_3DFACE ) );
  1028. }
  1029. if (pDrawInfo->dwFlags & LVXDI_Blend50Dis)
  1030. uiStyleSmall |= ILD_BLEND50;
  1031. }
  1032. /* Draw the column text. In the first column the background of any
  1033. ** indent and icons is erased to the text background color.
  1034. */
  1035. {
  1036. RECT rcBg = rc;
  1037. if (i == 0)
  1038. rcBg.left -= dxIndent + dxState + dxSmall;
  1039. ExtTextOut( hdc, rc.left + LVX_dxColText,
  1040. rc.top + LVX_dyColText, ETO_CLIPPED + ETO_OPAQUE,
  1041. &rcBg, pszText, lstrlen( pszText ), NULL );
  1042. }
  1043. Free( pszText );
  1044. }
  1045. /* Finally, draw the icons, if caller specified any.
  1046. */
  1047. if (himlState)
  1048. {
  1049. ImageList_Draw( himlState, (item.state >> 12) - 1, hdc,
  1050. pdis->rcItem.left + dxIndent, pdis->rcItem.top, uiStyleState );
  1051. }
  1052. if (himlSmall)
  1053. {
  1054. ImageList_Draw( himlSmall, item.iImage, hdc,
  1055. pdis->rcItem.left + dxIndent + dxState,
  1056. pdis->rcItem.top, uiStyleSmall );
  1057. }
  1058. /* Draw the dotted focus rectangle around the whole item, if indicated.
  1059. */
  1060. //comment for bug 52688 whistler
  1061. // if ((pdis->itemState & ODS_FOCUS) && GetFocus() == pdis->hwndItem)
  1062. // DrawFocusRect( hdc, &pdis->rcItem );
  1063. //
  1064. ReleaseDC( pdis->hwndItem, hdc );
  1065. return TRUE;
  1066. }
  1067. BOOL
  1068. LvxMeasureItem(
  1069. IN HWND hwnd,
  1070. IN OUT MEASUREITEMSTRUCT* pmis )
  1071. /* Respond to WM_MEASUREITEM message, i.e. fill in the height of an item
  1072. ** in the ListView. 'Hwnd' is the owner window. 'Pmis' is the structure
  1073. ** provided from Windows.
  1074. **
  1075. ** Returns true is processed the message, false otherwise.
  1076. */
  1077. {
  1078. HDC hdc;
  1079. HWND hwndLv;
  1080. HFONT hfont;
  1081. TEXTMETRIC tm;
  1082. UINT dySmIcon;
  1083. RECT rc;
  1084. TRACE("LvxMeasureItem");
  1085. if (pmis->CtlType != ODT_LISTVIEW)
  1086. return FALSE;
  1087. hwndLv = GetDlgItem( hwnd, pmis->CtlID );
  1088. ASSERT(hwndLv);
  1089. /* Get a device context for the list view control and set up the font the
  1090. ** control says it's using. MSDN claims the final font may not be
  1091. ** available at this point, but it sure seems to be.
  1092. */
  1093. hdc = GetDC( hwndLv );
  1094. hfont = (HFONT )SendMessage( hwndLv, WM_GETFONT, 0, 0 );
  1095. if (hfont)
  1096. SelectObject( hdc, hfont );
  1097. if (GetTextMetrics( hdc, &tm ))
  1098. pmis->itemHeight = tm.tmHeight + 1;
  1099. else
  1100. pmis->itemHeight = 0;
  1101. /* Make sure it's tall enough for a standard small icon.
  1102. */
  1103. dySmIcon = (UINT )GetSystemMetrics( SM_CYSMICON );
  1104. if (pmis->itemHeight < dySmIcon + LVX_dyIconSpacing)
  1105. pmis->itemHeight = dySmIcon + LVX_dyIconSpacing;
  1106. /* Set the width since the docs say to, though I don't think it's used by
  1107. ** list view.
  1108. */
  1109. GetClientRect( hwndLv, &rc );
  1110. pmis->itemWidth = rc.right - rc.left - 1;
  1111. ReleaseDC( hwndLv, hdc );
  1112. return TRUE;
  1113. }
  1114. BOOL
  1115. ListView_OwnerHandler(
  1116. IN HWND hwnd,
  1117. IN UINT unMsg,
  1118. IN WPARAM wparam,
  1119. IN LPARAM lparam,
  1120. IN PLVXCALLBACK pLvxCallback )
  1121. /* Handler that, when installed, turns a regular report-view-only list
  1122. ** view (but with style LVS_OWNERDRAWFIXED) into an enhanced list view
  1123. ** with full width selection bar and other custom column display options.
  1124. ** It should appear in list view owner's dialog proc as follows:
  1125. **
  1126. ** BOOL
  1127. ** MyDlgProc(
  1128. ** IN HWND hwnd,
  1129. ** IN UINT unMsg,
  1130. ** IN WPARAM wparam,
  1131. ** IN LPARAM lparam )
  1132. ** {
  1133. ** if (ListView_OwnerHandler(
  1134. ** hwnd, unMsg, wParam, lParam, MyLvxCallback ))
  1135. ** return TRUE;
  1136. **
  1137. ** <the rest of your stuff here>
  1138. ** }
  1139. **
  1140. ** 'PLvxCallback' is caller's callback routine that provides information
  1141. ** about drawing columns and other options.
  1142. **
  1143. ** Returns true if processed message, false otherwise.
  1144. */
  1145. {
  1146. /* This routine executes on EVERY message thru the dialog so keep it
  1147. ** efficient, please.
  1148. */
  1149. switch (unMsg)
  1150. {
  1151. case WM_DRAWITEM:
  1152. return LvxDrawItem( (DRAWITEMSTRUCT* )lparam, pLvxCallback );
  1153. case WM_MEASUREITEM:
  1154. return LvxMeasureItem( hwnd, (MEASUREITEMSTRUCT* )lparam );
  1155. }
  1156. return FALSE;
  1157. }
  1158. // StrDup* functions
  1159. TCHAR* _StrDup(LPCTSTR psz ) // my local version...
  1160. /* Returns heap block containing a copy of 0-terminated string 'psz' or
  1161. ** NULL on error or is 'psz' is NULL. It is caller's responsibility to
  1162. ** 'Free' the returned string.
  1163. */
  1164. {
  1165. TCHAR* pszNew = NULL;
  1166. if (psz)
  1167. {
  1168. pszNew = (TCHAR*)Malloc( (lstrlen( psz ) + 1) * sizeof(TCHAR) );
  1169. if (!pszNew)
  1170. {
  1171. TRACE("StrDup Malloc failed");
  1172. return NULL;
  1173. }
  1174. lstrcpy( pszNew, psz );
  1175. }
  1176. return pszNew;
  1177. }
  1178. TCHAR*
  1179. StrDupTFromW(
  1180. LPCWSTR psz )
  1181. /* Returns heap block containing a copy of 0-terminated string 'psz' or
  1182. ** NULL on error or is 'psz' is NULL. The output string is converted to
  1183. ** UNICODE. It is caller's responsibility to Free the returned string.
  1184. */
  1185. {
  1186. #ifdef UNICODE
  1187. return _StrDup ( psz );
  1188. #else // !UNICODE
  1189. CHAR* pszNew = NULL;
  1190. if (psz)
  1191. {
  1192. DWORD cb;
  1193. cb = WideCharToMultiByte( CP_ACP, 0, psz, -1, NULL, 0, NULL, NULL );
  1194. ASSERT(cb);
  1195. pszNew = (CHAR* )Malloc( cb + 1 );
  1196. if (!pszNew)
  1197. {
  1198. TRACE("StrDupTFromW Malloc failed");
  1199. return NULL;
  1200. }
  1201. cb = WideCharToMultiByte( CP_ACP, 0, psz, -1, pszNew, cb, NULL, NULL );
  1202. if (cb == 0)
  1203. {
  1204. Free( pszNew );
  1205. TRACE("StrDupTFromW conversion failed");
  1206. return NULL;
  1207. }
  1208. }
  1209. return pszNew;
  1210. #endif
  1211. }
  1212. WCHAR*
  1213. StrDupWFromT(
  1214. LPCTSTR psz )
  1215. /* Returns heap block containing a copy of 0-terminated string 'psz' or
  1216. ** NULL on error or if 'psz' is NULL. The output string is converted to
  1217. ** UNICODE. It is caller's responsibility to Free the returned string.
  1218. */
  1219. {
  1220. #ifdef UNICODE
  1221. return _StrDup ( psz );
  1222. #else // !UNICODE
  1223. WCHAR* pszNew = NULL;
  1224. if (psz)
  1225. {
  1226. DWORD cb;
  1227. cb = MultiByteToWideChar( CP_ACP, 0, psz, -1, NULL, 0 );
  1228. ASSERT(cb);
  1229. pszNew = (WCHAR*)Malloc( (cb + 1) * sizeof(WCHAR) );
  1230. if (!pszNew)
  1231. {
  1232. TRACE("StrDupWFromT Malloc failed");
  1233. return NULL;
  1234. }
  1235. cb = MultiByteToWideChar( CP_ACP, 0, psz, -1, pszNew, cb );
  1236. if (cb == 0)
  1237. {
  1238. Free( pszNew );
  1239. TRACE("StrDupWFromT conversion failed");
  1240. return NULL;
  1241. }
  1242. }
  1243. return pszNew;
  1244. #endif
  1245. }
  1246. void
  1247. IpHostAddrToPsz(
  1248. IN DWORD dwAddr,
  1249. OUT LPTSTR pszBuffer )
  1250. // Converts an IP address in host byte order to its
  1251. // string representation.
  1252. // pszBuffer should be allocated by the caller and be
  1253. // at least 16 characters long.
  1254. //
  1255. {
  1256. BYTE* pb = (BYTE*)&dwAddr;
  1257. static const TCHAR c_szIpAddr [] = TEXT("%d.%d.%d.%d");
  1258. wsprintf (pszBuffer, c_szIpAddr, pb[3], pb[2], pb[1], pb[0]);
  1259. }
  1260. #ifdef DOWNLEVEL_CLIENT
  1261. DWORD
  1262. IpPszToHostAddr(
  1263. IN LPCTSTR cp )
  1264. // Converts an IP address represented as a string to
  1265. // host byte order.
  1266. //
  1267. {
  1268. DWORD val, base, n;
  1269. TCHAR c;
  1270. DWORD parts[4], *pp = parts;
  1271. again:
  1272. // Collect number up to ``.''.
  1273. // Values are specified as for C:
  1274. // 0x=hex, 0=octal, other=decimal.
  1275. //
  1276. val = 0; base = 10;
  1277. if (*cp == TEXT('0'))
  1278. base = 8, cp++;
  1279. if (*cp == TEXT('x') || *cp == TEXT('X'))
  1280. base = 16, cp++;
  1281. while (c = *cp)
  1282. {
  1283. if ((c >= TEXT('0')) && (c <= TEXT('9')))
  1284. {
  1285. val = (val * base) + (c - TEXT('0'));
  1286. cp++;
  1287. continue;
  1288. }
  1289. if ((base == 16) &&
  1290. ( ((c >= TEXT('0')) && (c <= TEXT('9'))) ||
  1291. ((c >= TEXT('A')) && (c <= TEXT('F'))) ||
  1292. ((c >= TEXT('a')) && (c <= TEXT('f'))) ))
  1293. {
  1294. val = (val << 4) + (c + 10 - (
  1295. ((c >= TEXT('a')) && (c <= TEXT('f')))
  1296. ? TEXT('a')
  1297. : TEXT('A') ) );
  1298. cp++;
  1299. continue;
  1300. }
  1301. break;
  1302. }
  1303. if (*cp == TEXT('.'))
  1304. {
  1305. // Internet format:
  1306. // a.b.c.d
  1307. // a.b.c (with c treated as 16-bits)
  1308. // a.b (with b treated as 24 bits)
  1309. //
  1310. if (pp >= parts + 3)
  1311. return (DWORD) -1;
  1312. *pp++ = val, cp++;
  1313. goto again;
  1314. }
  1315. // Check for trailing characters.
  1316. //
  1317. if (*cp && (*cp != TEXT(' ')))
  1318. return 0xffffffff;
  1319. *pp++ = val;
  1320. // Concoct the address according to
  1321. // the number of parts specified.
  1322. //
  1323. n = (DWORD) (pp - parts);
  1324. switch (n)
  1325. {
  1326. case 1: // a -- 32 bits
  1327. val = parts[0];
  1328. break;
  1329. case 2: // a.b -- 8.24 bits
  1330. val = (parts[0] << 24) | (parts[1] & 0xffffff);
  1331. break;
  1332. case 3: // a.b.c -- 8.8.16 bits
  1333. val = (parts[0] << 24) | ((parts[1] & 0xff) << 16) |
  1334. (parts[2] & 0xffff);
  1335. break;
  1336. case 4: // a.b.c.d -- 8.8.8.8 bits
  1337. val = (parts[0] << 24) | ((parts[1] & 0xff) << 16) |
  1338. ((parts[2] & 0xff) << 8) | (parts[3] & 0xff);
  1339. break;
  1340. default:
  1341. return 0xffffffff;
  1342. }
  1343. return val;
  1344. }
  1345. #endif
  1346. VOID*
  1347. Free0(
  1348. VOID* p )
  1349. /* Like Free, but deals with NULL 'p'.
  1350. */
  1351. {
  1352. if (!p)
  1353. return NULL;
  1354. return Free( p );
  1355. }
  1356. HRESULT ActivateLuna(HANDLE* phActivationContext, ULONG_PTR* pulCookie)
  1357. {
  1358. HRESULT hr = E_FAIL;
  1359. TCHAR szPath[MAX_PATH];
  1360. if(0 != GetModuleFileName(_Module.GetResourceInstance(), szPath, sizeof(szPath) / sizeof(TCHAR)))
  1361. {
  1362. ACTCTX ActivationContext;
  1363. ZeroMemory(&ActivationContext, sizeof(ActivationContext));
  1364. ActivationContext.cbSize = sizeof(ActivationContext);
  1365. ActivationContext.lpSource = szPath;
  1366. ActivationContext.dwFlags = ACTCTX_FLAG_RESOURCE_NAME_VALID;
  1367. ActivationContext.lpResourceName = MAKEINTRESOURCE(123);
  1368. ULONG_PTR ulCookie;
  1369. HANDLE hActivationContext = CreateActCtx(&ActivationContext);
  1370. if(NULL != hActivationContext)
  1371. {
  1372. if(TRUE == ActivateActCtx(hActivationContext, &ulCookie))
  1373. {
  1374. *phActivationContext = hActivationContext;
  1375. *pulCookie = ulCookie;
  1376. hr = S_OK;
  1377. }
  1378. else
  1379. {
  1380. ReleaseActCtx(hActivationContext);
  1381. }
  1382. }
  1383. }
  1384. return hr;
  1385. }
  1386. HRESULT DeactivateLuna(HANDLE hActivationContext, ULONG_PTR ulCookie)
  1387. {
  1388. DeactivateActCtx(0, ulCookie);
  1389. ReleaseActCtx(hActivationContext);
  1390. return S_OK;
  1391. }