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.

501 lines
12 KiB

  1. /*******************************************************************************
  2. *
  3. * (C) COPYRIGHT MICROSOFT CORP., 1993-1994
  4. *
  5. * TITLE: PCCARD.C
  6. *
  7. * VERSION: 1.0
  8. *
  9. * AUTHOR: RAL
  10. *
  11. * DATE: 11/01/94
  12. *
  13. ********************************************************************************
  14. *
  15. * CHANGE LOG:
  16. *
  17. * DATE REV DESCRIPTION
  18. * ----------- --- -------------------------------------------------------------
  19. * Nov. 11, 94 RAL Original
  20. * Oct 23, 95 Shawnb UNICODE enabled
  21. *
  22. *******************************************************************************/
  23. #include "stdafx.h"
  24. #include "systray.h"
  25. #define PCMCIAMENU_PROPERTIES 100
  26. #define PCMCIAMENU_DISABLE 101
  27. #define PCMCIAMENU_SOCKET 200
  28. extern HANDLE g_hPCCARD;
  29. extern HINSTANCE g_hInstance;
  30. static BOOL g_bPCMCIAEnabled = FALSE;
  31. static BOOL g_bPCMCIAIconShown = FALSE;
  32. static HICON g_hPCMCIAIcon = NULL;
  33. #define MAX_DEVNODES 20
  34. static DWORD g_aDevnodes[MAX_DEVNODES];
  35. static BYTE g_aSktState[MAX_DEVNODES] = {0};
  36. static UINT g_numskts = 0;
  37. static DWORD g_PCMCIAFlags = 0;
  38. static TCHAR g_szDevNodeKeyFmt[] = REGSTR_PATH_DYNA_ENUM TEXT ("\\%X");
  39. static const TCHAR g_szEnumKeyPrefix[] = REGSTR_PATH_ENUM TEXT ("\\");
  40. static const TCHAR g_szPCMCIAFlags[] = REGSTR_VAL_SYSTRAYPCCARDFLAGS;
  41. static const TCHAR g_szClass[] = REGSTR_VAL_CLASS;
  42. static const TCHAR g_szModemClass[] = REGSTR_KEY_MODEM_CLASS;
  43. #if NOTYET
  44. static const TCHAR g_szDiskDriveClass[] = REGSTR_KEY_DISKDRIVE_CLASS;
  45. #endif
  46. #define SKTSTATE_GOODEJECT 1
  47. #define SKTSTATE_SHOULDWARN 2
  48. #define SKTSTATE_TYPEKNOWN 4
  49. HKEY OpenDevnodeDynKey(DWORD dwDevnode)
  50. {
  51. TCHAR szScratch[MAX_PATH];
  52. HKEY hkDyn = NULL;
  53. wsprintf(szScratch, g_szDevNodeKeyFmt, dwDevnode);
  54. if (RegOpenKey(HKEY_DYN_DATA, szScratch, &hkDyn) != ERROR_SUCCESS) {
  55. return(NULL);
  56. }
  57. return hkDyn;
  58. }
  59. UINT GetDynInfo(DWORD dwDevNode, LPCTSTR lpszValName,
  60. LPVOID lpBuffer, UINT cbBuffer)
  61. {
  62. UINT cbSize = 0;
  63. HKEY hkDyn = OpenDevnodeDynKey(dwDevNode);
  64. if (hkDyn) {
  65. if (RegQueryValueEx(hkDyn, lpszValName, NULL, NULL,
  66. lpBuffer, &cbBuffer) == ERROR_SUCCESS) {
  67. cbSize = cbBuffer;
  68. }
  69. RegCloseKey(hkDyn);
  70. }
  71. return(cbSize);
  72. }
  73. HKEY OpenDevnodeHwKey(DWORD dwDevnode)
  74. {
  75. TCHAR szScratch[MAX_PATH];
  76. HKEY hkDyn, hkHw = NULL;
  77. UINT cbSize;
  78. UINT cchOffset;
  79. if ((hkDyn = OpenDevnodeDynKey(dwDevnode)) == NULL) {
  80. return(NULL);
  81. }
  82. lstrcpy(szScratch, g_szEnumKeyPrefix);
  83. cbSize = sizeof(szScratch) - sizeof(g_szEnumKeyPrefix);
  84. cchOffset = ARRAYSIZE(g_szEnumKeyPrefix) - 1;
  85. if (RegQueryValueEx(hkDyn, REGSTR_VAL_HARDWARE_KEY,
  86. NULL, NULL, (LPSTR)&(szScratch[cchOffset]),
  87. &cbSize) == ERROR_SUCCESS) {
  88. if (RegOpenKey(HKEY_LOCAL_MACHINE, szScratch, &hkHw) != ERROR_SUCCESS) {
  89. hkHw = NULL;
  90. }
  91. }
  92. RegCloseKey(hkDyn);
  93. return(hkHw);
  94. }
  95. UINT GetHwInfo(DWORD dwDevNode, LPCTSTR lpszValName,
  96. LPVOID lpBuffer, UINT cbBuffer)
  97. {
  98. UINT cbSize = 0;
  99. HKEY hkHw = OpenDevnodeHwKey(dwDevNode);
  100. if (hkHw) {
  101. if (RegQueryValueEx(hkHw, lpszValName, NULL, NULL,
  102. lpBuffer, &cbBuffer) == ERROR_SUCCESS) {
  103. cbSize = cbBuffer;
  104. }
  105. RegCloseKey(hkHw);
  106. }
  107. return(cbSize);
  108. }
  109. void UpdateSktTypes()
  110. {
  111. UINT i;
  112. TCHAR szClassName[32];
  113. for (i = 0; i < g_numskts; i++) {
  114. if (g_aSktState[i] == 0 && g_aDevnodes[i] != 0) {
  115. if (GetHwInfo(g_aDevnodes[i], g_szClass,
  116. szClassName, sizeof(szClassName))) {
  117. g_aSktState[i] |= SKTSTATE_TYPEKNOWN;
  118. if (lstrcmpi(g_szModemClass, szClassName) != 0) {
  119. g_aSktState[i] |= SKTSTATE_SHOULDWARN;
  120. }
  121. }
  122. }
  123. }
  124. }
  125. void UpdateSocketInfo()
  126. {
  127. UINT cbReturned;
  128. if (DeviceIoControl(g_hPCCARD, PCCARD_IOCTL_GET_DEVNODES,
  129. NULL, 0,
  130. g_aDevnodes, sizeof(g_aDevnodes), &cbReturned, NULL)) {
  131. g_numskts = cbReturned / 4;
  132. } else {
  133. g_numskts = 0;
  134. }
  135. UpdateSktTypes();
  136. }
  137. void UpdateGlobalFlags()
  138. {
  139. HKEY hk;
  140. if (RegOpenKey(HKEY_CURRENT_USER, REGSTR_PATH_SYSTRAY, &hk) ==
  141. ERROR_SUCCESS) {
  142. UINT cb = sizeof(g_PCMCIAFlags);
  143. if (RegQueryValueEx(hk, g_szPCMCIAFlags, NULL, NULL,
  144. (LPSTR)(&g_PCMCIAFlags), &cb) != ERROR_SUCCESS) {
  145. g_PCMCIAFlags = 0;
  146. }
  147. RegCloseKey(hk);
  148. }
  149. }
  150. BOOL PCMCIA_Init(HWND hWnd)
  151. {
  152. if (g_hPCCARD == INVALID_HANDLE_VALUE) {
  153. g_hPCCARD = CreateFile(TEXT ("\\\\.\\PCCARD"), GENERIC_READ | GENERIC_WRITE,
  154. FILE_SHARE_READ | FILE_SHARE_WRITE,
  155. NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  156. UpdateGlobalFlags();
  157. }
  158. return(g_hPCCARD != INVALID_HANDLE_VALUE);
  159. }
  160. //
  161. // NOTE: This function expects the caller to have called UpdateSocketInfo
  162. // prior to calling it.
  163. //
  164. void PCMCIA_UpdateStatus(HWND hWnd, BOOL bShowIcon, DWORD dnRemove)
  165. {
  166. if (bShowIcon) {
  167. UINT i;
  168. bShowIcon = FALSE; // Assume no devnodes
  169. for (i = 0; i < g_numskts; i++) {
  170. if (g_aDevnodes[i] != 0 && g_aDevnodes[i] != dnRemove) {
  171. bShowIcon = TRUE;
  172. break;
  173. }
  174. }
  175. }
  176. if (bShowIcon != g_bPCMCIAIconShown) {
  177. g_bPCMCIAIconShown = bShowIcon;
  178. if (bShowIcon) {
  179. LPTSTR pStr = LoadDynamicString(IDS_PCMCIATIP);
  180. g_hPCMCIAIcon = LoadImage(g_hInstance, MAKEINTRESOURCE(IDI_PCMCIA),
  181. IMAGE_ICON, 16, 16, 0);
  182. SysTray_NotifyIcon(hWnd, STWM_NOTIFYPCMCIA, NIM_ADD,
  183. g_hPCMCIAIcon, pStr);
  184. DeleteDynamicString(pStr);
  185. } else {
  186. SysTray_NotifyIcon(hWnd, STWM_NOTIFYPCMCIA, NIM_DELETE, NULL, NULL);
  187. if (g_hPCMCIAIcon) {
  188. DestroyIcon(g_hPCMCIAIcon);
  189. }
  190. }
  191. }
  192. }
  193. #define DEVNODE_NOT_IN_LIST -1
  194. int FindSocketIndex(DWORD dn)
  195. {
  196. int i;
  197. for (i = 0; i < (int)g_numskts; i++) {
  198. if (g_aDevnodes[i] == dn) {
  199. return(i);
  200. }
  201. }
  202. return(DEVNODE_NOT_IN_LIST);
  203. }
  204. void PCMCIA_DeviceChange(HWND hDlg, WPARAM wParam, LPARAM lParam)
  205. {
  206. int i;
  207. #define lpdbd ((PDEV_BROADCAST_DEVNODE)lParam)
  208. #define DN_STARTED 0x00000008 // WARNING KEEP THIS IN SYNC WITH CONFIGMG.H
  209. if ((wParam != DBT_DEVICEREMOVEPENDING &&
  210. wParam != DBT_DEVICEARRIVAL &&
  211. wParam != DBT_DEVICEREMOVECOMPLETE) ||
  212. lpdbd->dbcd_devicetype != DBT_DEVTYP_DEVNODE) {
  213. return;
  214. }
  215. switch (wParam) {
  216. case DBT_DEVICEREMOVEPENDING: // Query remove succeeded
  217. i = FindSocketIndex(lpdbd->dbcd_devnode);
  218. if (i != DEVNODE_NOT_IN_LIST) {
  219. g_aSktState[i] |= SKTSTATE_GOODEJECT;
  220. }
  221. break;
  222. case DBT_DEVICEARRIVAL:
  223. UpdateSocketInfo();
  224. i = FindSocketIndex(lpdbd->dbcd_devnode);
  225. if (i != DEVNODE_NOT_IN_LIST) {
  226. g_aSktState[i] = 0;
  227. UpdateSktTypes();
  228. PCMCIA_UpdateStatus(hDlg, TRUE, 0);
  229. }
  230. break;
  231. case DBT_DEVICEREMOVECOMPLETE:
  232. {
  233. ULONG Status = 0L;
  234. ULONG Size = sizeof(ULONG);
  235. TCHAR szDevNode[REGSTR_MAX_VALUE_LENGTH];
  236. HKEY hkDevDyna;
  237. wsprintf(szDevNode, TEXT ("%s\\%8X"),REGSTR_PATH_DYNA_ENUM,lpdbd->dbcd_devnode);
  238. if (RegOpenKey( HKEY_DYN_DATA,
  239. szDevNode,
  240. &hkDevDyna ) == ERROR_SUCCESS)
  241. {
  242. RegQueryValueEx( hkDevDyna, REGSTR_VAL_STATUS, 0, NULL, (LPSTR)&Status, &Size );
  243. RegCloseKey(hkDevDyna);
  244. }
  245. if (Status & DN_STARTED)
  246. {
  247. i = FindSocketIndex(lpdbd->dbcd_devnode);
  248. if (i != DEVNODE_NOT_IN_LIST) {
  249. //
  250. // Check to see if we're supposed to warn the user about this
  251. // eject. Only warn if NOT good eject and class is one we warn
  252. // about.
  253. //
  254. BOOL fWarnUser = (g_aSktState[i] &
  255. (SKTSTATE_SHOULDWARN | SKTSTATE_GOODEJECT)) ==
  256. SKTSTATE_SHOULDWARN;
  257. g_aSktState[i] = 0;
  258. UpdateSocketInfo();
  259. PCMCIA_UpdateStatus(hDlg, TRUE, lpdbd->dbcd_devnode);
  260. if (fWarnUser) {
  261. // Make sure the user did not turn this off earlier
  262. UpdateGlobalFlags();
  263. if (!(g_PCMCIAFlags & PCMCIA_REGFLAG_NOWARN)) {
  264. const TCHAR szOpen[] = TEXT ("open");
  265. const TCHAR szRunDLL[] = TEXT ("RUNDLL32.EXE");
  266. const TCHAR szParams[] = TEXT ("RUNDLL mspcic.dll,EjectWarningDlg");
  267. ShellExecute(NULL, szOpen, szRunDLL,
  268. szParams, NULL, SW_SHOW);
  269. }
  270. }
  271. }
  272. }
  273. break;
  274. }
  275. }
  276. #undef lpdbd
  277. }
  278. //
  279. // Called at init time and whenever services are enabled/disabled.
  280. // Returns false if PCMCIA services are not active.
  281. //
  282. BOOL PCMCIA_CheckEnable(HWND hWnd, BOOL bSvcEnabled)
  283. {
  284. BOOL bEnable = bSvcEnabled && PCMCIA_Init(hWnd);
  285. if (bEnable != g_bPCMCIAEnabled) {
  286. g_bPCMCIAEnabled = bEnable;
  287. UpdateSocketInfo();
  288. PCMCIA_UpdateStatus(hWnd, bEnable, 0);
  289. if (!bEnable) {
  290. CloseIfOpen(&g_hPCCARD);
  291. }
  292. }
  293. return(bEnable);
  294. }
  295. /*----------------------------------------------------------------------------
  296. * PCMCIA_CreateMenu()
  297. *
  298. * build a menu containing all sockets.
  299. *
  300. *----------------------------------------------------------------------------*/
  301. //static CRITICAL_SECTION csMenu;
  302. static HMENU _hMenu[2] = {0};
  303. HMENU PCMCIA_CreateMenu(LONG l)
  304. {
  305. //EnterCriticalSection(&csMenu);
  306. if (l > 0) {
  307. if (_hMenu[1] == NULL) {
  308. HMENU hmenu = _hMenu[l] = CreatePopupMenu();
  309. LPTSTR lpszMenu;
  310. if ((lpszMenu = LoadDynamicString(IDS_PCCARDMENU1)) != NULL) {
  311. AppendMenu(hmenu,MF_STRING,PCMCIAMENU_PROPERTIES,lpszMenu);
  312. DeleteDynamicString(lpszMenu);
  313. }
  314. if ((lpszMenu = LoadDynamicString(IDS_PCCARDMENU2)) != NULL) {
  315. AppendMenu(hmenu,MF_STRING,PCMCIAMENU_DISABLE,lpszMenu);
  316. DeleteDynamicString(lpszMenu);
  317. }
  318. SetMenuDefaultItem(hmenu,PCMCIAMENU_PROPERTIES,FALSE);
  319. }
  320. } else {
  321. HMENU hMenu;
  322. if (_hMenu[0]) {
  323. DestroyMenu(_hMenu[0]);
  324. }
  325. hMenu = _hMenu[0] = CreatePopupMenu();
  326. if (g_hPCCARD != INVALID_HANDLE_VALUE) {
  327. TCHAR szDesc[80];
  328. LPTSTR lpszMenuText;
  329. UINT i;
  330. UpdateSocketInfo();
  331. for (i = 0; i < g_numskts; i++) {
  332. if (g_aDevnodes[i] &&
  333. GetHwInfo(g_aDevnodes[i], REGSTR_VAL_DEVDESC, szDesc, sizeof(szDesc))) {
  334. #if NOTYET
  335. DWORD dwChild;
  336. TCHAR szClassName[32];
  337. TCHAR szDriveLetters[32];
  338. if (GetDynInfo(g_aDevnodes[i], REGSTR_VAL_CHILD,
  339. &dwChild, sizeof(dwChild)) &&
  340. GetHwInfo(dwChild, g_szClass,
  341. szClassName, sizeof(szClassName)) &&
  342. lstrcmpi(g_szDiskDriveClass, szClassName) == 0 &&
  343. GetHwInfo(dwChild, REGSTR_VAL_CURDRVLET,
  344. szDriveLetters, sizeof(szDriveLetters)) &&
  345. lstrlen(szDriveLetters) > 0) {
  346. lpszMenuText = LoadDynamicString(IDS_EJECTFMTDISKDRIVE,
  347. szDesc, szDriveLetters[0]);
  348. }
  349. else
  350. #endif
  351. {
  352. lpszMenuText = LoadDynamicString(IDS_EJECTFMT, szDesc);
  353. }
  354. if (lpszMenuText) {
  355. AppendMenu(hMenu,MF_STRING,PCMCIAMENU_SOCKET+i,lpszMenuText);
  356. DeleteDynamicString(lpszMenuText);
  357. }
  358. }
  359. }
  360. }
  361. }
  362. //LeaveCriticalSection(&csMenu);
  363. return _hMenu[l];
  364. }
  365. void PCMCIA_Menu(HWND hwnd, UINT uMenuNum, UINT uButton)
  366. {
  367. POINT pt;
  368. UINT iCmd;
  369. SetForegroundWindow(hwnd);
  370. GetCursorPos(&pt);
  371. iCmd = TrackPopupMenu(PCMCIA_CreateMenu(uMenuNum), uButton | TPM_RETURNCMD | TPM_NONOTIFY,
  372. pt.x, pt.y, 0, hwnd, NULL);
  373. if (iCmd >= PCMCIAMENU_SOCKET) {
  374. const TCHAR szOpen[] = TEXT ("open");
  375. const TCHAR szRunDLL[] = TEXT ("RUNDLL32.EXE");
  376. LPTSTR lpszCommand = LoadDynamicString(IDS_RUNEJECT, iCmd-PCMCIAMENU_SOCKET);
  377. if (lpszCommand == NULL)
  378. return;
  379. ShellExecute(NULL, szOpen, szRunDLL,
  380. lpszCommand, NULL, SW_SHOW);
  381. DeleteDynamicString(lpszCommand);
  382. } else {
  383. switch (iCmd) {
  384. case PCMCIAMENU_PROPERTIES:
  385. SysTray_RunProperties(IDS_RUNPCMCIAPROPERTIES);
  386. break;
  387. case PCMCIAMENU_DISABLE:
  388. PostMessage(hwnd, STWM_ENABLESERVICE, STSERVICE_PCMCIA, FALSE);
  389. break;
  390. }
  391. }
  392. }
  393. void PCMCIA_Notify(HWND hwnd, WPARAM wParam, LPARAM lParam)
  394. {
  395. switch (lParam)
  396. {
  397. case WM_RBUTTONUP:
  398. PCMCIA_Menu(hwnd, 1, TPM_RIGHTBUTTON);
  399. break;
  400. case WM_LBUTTONDOWN:
  401. SetTimer(hwnd, PCMCIA_TIMER_ID, GetDoubleClickTime()+100, NULL);
  402. break;
  403. case WM_LBUTTONDBLCLK:
  404. KillTimer(hwnd, PCMCIA_TIMER_ID);
  405. SysTray_RunProperties(IDS_RUNPCMCIAPROPERTIES);
  406. break;
  407. }
  408. }
  409. void PCMCIA_Timer(HWND hwnd)
  410. {
  411. KillTimer(hwnd, PCMCIA_TIMER_ID);
  412. PCMCIA_Menu(hwnd, 0, TPM_LEFTBUTTON);
  413. }