Leaked source code of windows server 2003
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.

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