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.

429 lines
14 KiB

  1. /********************************************************************************
  2. ** Copyright (c) 2000 Microsoft Corporation. All Rights Reserved.
  3. ********************************************************************************/
  4. #include <windows.h>
  5. #include <cpl.h>
  6. #include <ks.h>
  7. #include <ksmedia.h>
  8. #include <setupapi.h>
  9. #include "resource.h"
  10. #include "prvprop.h"
  11. //
  12. // Global Variables.
  13. //
  14. HINSTANCE ghInstance = NULL; // module handle.
  15. const TCHAR AppletName[] = TEXT("AC97 control panel");
  16. #if (DBG)
  17. /////////////////////////////////////////////////////////////////////////////////
  18. // dbgError
  19. /////////////////////////////////////////////////////////////////////////////////
  20. // This function prints an error message.
  21. // It prints first the string passed and then the error that it gets with
  22. // GetLastError as a string.
  23. //
  24. // Arguments:
  25. // szMsg - message to print.
  26. //
  27. // Return Value:
  28. // None.
  29. //
  30. void dbgError (LPCTSTR szMsg)
  31. {
  32. LPTSTR errorMessage;
  33. DWORD count;
  34. // Get the error message from the system.
  35. count = FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER |
  36. FORMAT_MESSAGE_FROM_SYSTEM |
  37. FORMAT_MESSAGE_IGNORE_INSERTS,
  38. NULL,
  39. GetLastError (),
  40. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  41. (LPTSTR)&errorMessage,
  42. 0,
  43. NULL);
  44. // Print the msg + error + \n\r.
  45. if (count)
  46. {
  47. OutputDebugString (szMsg);
  48. OutputDebugString (errorMessage);
  49. OutputDebugString (TEXT("\n\r"));
  50. // This is for those without a debugger.
  51. // MessageBox (NULL, szErrorMessage, szMsg, MB_OK | MB_ICONSTOP);
  52. LocalFree (errorMessage);
  53. }
  54. else
  55. {
  56. OutputDebugString (AppletName);
  57. OutputDebugString (TEXT(": Low memory condition. Cannot ")
  58. TEXT("print error message.\n\r"));
  59. }
  60. }
  61. #else
  62. #define dbgError(a) 0;
  63. #endif
  64. /////////////////////////////////////////////////////////////////////////////////
  65. // DllMain
  66. /////////////////////////////////////////////////////////////////////////////////
  67. // Main enty point of the DLL.
  68. // Save the instance handle; it is needed for property sheet creation.
  69. //
  70. // Arguments:
  71. // hModule - instance data, is equal to module handle
  72. // ul_reason_for_call - the reason for the call
  73. // lpReserved - some additional parameter.
  74. //
  75. // Return Value:
  76. // BOOL: FALSE if DLL should fail, TRUE on success
  77. //
  78. BOOL APIENTRY DllMain (HANDLE hModule, ULONG ul_reason_for_call, LPVOID lpReserved)
  79. {
  80. ghInstance = (HINSTANCE) hModule;
  81. return TRUE;
  82. }
  83. /////////////////////////////////////////////////////////////////////////////////
  84. // FindAC97Device
  85. /////////////////////////////////////////////////////////////////////////////////
  86. // This function stores the device info and device data of the "ac97smpl" driver.
  87. // It first creates a list of all devices that have a topology filter exposed
  88. // and then searches through the list to find the device with the service
  89. // "ac97smpl". The information is stored in pspRequest.
  90. //
  91. // For simplicity we search for the service name "ac97smpl".
  92. // Alternately, one could get more information about the device or driver,
  93. // then decide if it is suitable (regardless of its name).
  94. //
  95. // Arguments:
  96. // pspRequest pointer to Property sheet page request structure.
  97. // DeviceInfoData pointer to Device info data structure.
  98. //
  99. // Return Value:
  100. // TRUE on success, otherwise FALSE.
  101. // Note: on success that we have the device list still open - we have to destroy
  102. // the list later. The handle is stored at pspRequest->DeviceInfoSet.
  103. //
  104. BOOL FindAC97Device (PSP_PROPSHEETPAGE_REQUEST pspRequest,
  105. PSP_DEVINFO_DATA DeviceInfoData)
  106. {
  107. TCHAR szServiceName[128];
  108. //
  109. // Prepare the pspRequest structure...
  110. //
  111. pspRequest->cbSize = sizeof (SP_PROPSHEETPAGE_REQUEST);
  112. pspRequest->DeviceInfoData = DeviceInfoData;
  113. pspRequest->PageRequested = SPPSR_ENUM_ADV_DEVICE_PROPERTIES;
  114. // ...and the DeviceInfoData structure.
  115. DeviceInfoData->cbSize = sizeof (SP_DEVINFO_DATA);
  116. // Create a list of devices with Topology interface.
  117. pspRequest->DeviceInfoSet = SetupDiGetClassDevs (&KSCATEGORY_TOPOLOGY,
  118. NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
  119. // None found?
  120. if (pspRequest->DeviceInfoSet == INVALID_HANDLE_VALUE)
  121. {
  122. dbgError (TEXT("Test: SetupDiGetClassDevs: "));
  123. return FALSE;
  124. }
  125. //
  126. // Go through the list of all devices found.
  127. //
  128. int nIndex = 0;
  129. while (SetupDiEnumDeviceInfo (pspRequest->DeviceInfoSet, nIndex, DeviceInfoData))
  130. {
  131. //
  132. // Get the service name for that device.
  133. //
  134. if (!SetupDiGetDeviceRegistryProperty (pspRequest->DeviceInfoSet, DeviceInfoData,
  135. SPDRP_SERVICE, NULL, (PBYTE)szServiceName,
  136. sizeof (szServiceName), NULL))
  137. {
  138. dbgError (TEXT("Test: SetupDiGetDeviceRegistryProperty: "));
  139. SetupDiDestroyDeviceInfoList (pspRequest->DeviceInfoSet);
  140. return FALSE;
  141. }
  142. //
  143. // We only care about service "ac97smpl"
  144. //
  145. DWORD lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
  146. if (CompareString (lcid, NORM_IGNORECASE, szServiceName,
  147. -1, TEXT("AC97SMPL"), -1) == CSTR_EQUAL)
  148. {
  149. //
  150. // We found it! The information is already stored, just return.
  151. // Note that we have the device list still open - we have to destroy
  152. // the list later.
  153. //
  154. return TRUE;
  155. }
  156. // Take the next in the list.
  157. nIndex++;
  158. }
  159. //
  160. // We did not find the service.
  161. //
  162. SetupDiDestroyDeviceInfoList (pspRequest->DeviceInfoSet);
  163. return FALSE;
  164. }
  165. /////////////////////////////////////////////////////////////////////////////////
  166. // AddPropSheet
  167. /////////////////////////////////////////////////////////////////////////////////
  168. // This function is a callback that is passed to the "AC97PropPageProvider"
  169. // function of "ac97prop.dll". It is used to add the property page sheet
  170. // to the property dialog.
  171. // What we do here is store the property sheet handle and return.
  172. //
  173. // Arguments:
  174. // hPSP property sheet handle
  175. // lParam parameter that we passed to "AC97PropPageProvider".
  176. //
  177. // Return Value:
  178. // TRUE on success, otherwise FALSE.
  179. //
  180. BOOL APIENTRY AddPropSheet (HPROPSHEETPAGE hPSP, LPARAM lParam)
  181. {
  182. HPROPSHEETPAGE **pphPropSheet = (HPROPSHEETPAGE **)lParam;
  183. HPROPSHEETPAGE *phPropSheetPage;
  184. // Check the parameters
  185. if (!pphPropSheet)
  186. return FALSE;
  187. // Allocate the space for the handle.
  188. phPropSheetPage = (HPROPSHEETPAGE *)LocalAlloc (LPTR, sizeof(HPROPSHEETPAGE));
  189. if (!phPropSheetPage)
  190. return FALSE;
  191. *phPropSheetPage = hPSP;
  192. *pphPropSheet = phPropSheetPage;
  193. return TRUE;
  194. }
  195. /////////////////////////////////////////////////////////////////////////////////
  196. // GetDLLInfo
  197. /////////////////////////////////////////////////////////////////////////////////
  198. // This function loads the library and gets the entry point address.
  199. // With the information returned we can create the property dialog.
  200. //
  201. // For simplicity reasons we load the DLL "ac97prop" and call the function
  202. // "AC97PropPageProvider". A more flexible course of action is to get this
  203. // information from the registry. To do this, we read the "EnumPropPages32"
  204. // entry in the drivers section to obtain a registry path (read the "drivers"
  205. // entry in the device section to get the registry path of the drivers section)
  206. // -- this path leads to a key and entry which specifies the DLL and entry point.
  207. //
  208. // Arguments:
  209. // *phDLL pointer to module handle of loaded DLL.
  210. // *pAC97PropPageProvider pointer to "AC97PropPageProvider" in loaded DLL
  211. //
  212. // Return Value:
  213. // TRUE on success, otherwise FALSE.
  214. // Note: on success the library is still loaded.
  215. //
  216. BOOL GetDLLInfo (HMODULE *phDLL, LPFNADDPROPSHEETPAGES *pAC97PropPageProvider)
  217. {
  218. // Load the library.
  219. *phDLL = LoadLibrary (TEXT("ac97prop.dll"));
  220. if (!*phDLL)
  221. {
  222. dbgError (TEXT("DisplayPropertySheet: LoadLibrary"));
  223. return FALSE;
  224. }
  225. // Get the address of the function.
  226. *pAC97PropPageProvider = (LPFNADDPROPSHEETPAGES)GetProcAddress (*phDLL,
  227. "AC97PropPageProvider");
  228. if (!*pAC97PropPageProvider)
  229. {
  230. dbgError (TEXT("DisplayPropertySheet: GetProcAddress"));
  231. FreeLibrary (*phDLL);
  232. return FALSE;
  233. }
  234. return TRUE;
  235. }
  236. /////////////////////////////////////////////////////////////////////////////////
  237. // DisplayPropertySheet
  238. /////////////////////////////////////////////////////////////////////////////////
  239. // This function displays the property dialog.
  240. // It is called by CPlApplet when the ac97cpl icon gets a double click.
  241. //
  242. // Arguments:
  243. // hWnd parent window handle
  244. //
  245. // Return Value:
  246. // None.
  247. //
  248. void DisplayPropertySheet (HWND hWnd)
  249. {
  250. SP_PROPSHEETPAGE_REQUEST pspRequest; // structure passed to ac97prop
  251. SP_DEVINFO_DATA DeviceInfoData; // pspRequest points to it.
  252. HMODULE hDLL; // Module handle of library
  253. LPFNADDPROPSHEETPAGES AC97PropPageProvider; // function to be called.
  254. PROPSHEETHEADER psh;
  255. // You could move this to CPL_INIT, then it would be called
  256. // before the control panel window appears.
  257. // In case of an failure the icon would not be displayed. In our sample
  258. // however, the icon will be displayed and when the user clicks on it he
  259. // gets the error message.
  260. if (!FindAC97Device(&pspRequest, &DeviceInfoData))
  261. {
  262. MessageBox (hWnd, TEXT("You must install the ac97 sample driver."),
  263. AppletName, MB_ICONSTOP | MB_OK);
  264. return;
  265. }
  266. // Load the library and get the function pointer.
  267. if (!GetDLLInfo (&hDLL, &AC97PropPageProvider))
  268. {
  269. MessageBox (hWnd, TEXT("The ac97 property page DLL could not load."),
  270. AppletName, MB_ICONSTOP | MB_OK);
  271. SetupDiDestroyDeviceInfoList (pspRequest.DeviceInfoSet);
  272. return;
  273. }
  274. //
  275. // Prepare the header for the property sheet.
  276. //
  277. psh.nStartPage = 0;
  278. psh.dwSize = sizeof(psh);
  279. psh.dwFlags = PSH_PROPTITLE | PSH_NOAPPLYNOW;
  280. psh.hwndParent = hWnd;
  281. psh.hInstance = ghInstance;
  282. psh.pszIcon = NULL;
  283. psh.pszCaption = MAKEINTRESOURCE(IDS_AC97CPL);
  284. psh.nPages = 1;
  285. // Call the function to request the property sheet page.
  286. if (!(*AC97PropPageProvider) ((LPVOID)&pspRequest, AddPropSheet, (LPARAM)&psh.phpage))
  287. {
  288. MessageBox (hWnd, TEXT("\"AC97PropPageProvider\" had a failure."),
  289. AppletName, MB_ICONSTOP | MB_OK);
  290. FreeLibrary (hDLL);
  291. SetupDiDestroyDeviceInfoList (pspRequest.DeviceInfoSet);
  292. return;
  293. }
  294. // Create the dialog. The function returns when the dialog is closed.
  295. if (PropertySheet (&psh) < 0)
  296. {
  297. //
  298. // Dialog closed abnormally. This might be a system failure.
  299. //
  300. MessageBox (hWnd, TEXT("Please reinstall the ac97 sample driver."),
  301. AppletName, MB_ICONSTOP | MB_OK);
  302. }
  303. // Clean up.
  304. FreeLibrary (hDLL);
  305. LocalFree (psh.phpage);
  306. SetupDiDestroyDeviceInfoList (pspRequest.DeviceInfoSet);
  307. }
  308. /////////////////////////////////////////////////////////////////////////////////
  309. // CPlApplet
  310. /////////////////////////////////////////////////////////////////////////////////
  311. // This function is called by the control panel manager. It is very similar to
  312. // a Windows message handler (search for CplApplet in MSDN for description).
  313. //
  314. // Arguments:
  315. // HWND hWnd Parent window handle
  316. // UINT uMsg The message
  317. // LPARAM lParam1 depends on message
  318. // LPARAM lParam2 depends on message
  319. //
  320. // Return Value:
  321. // LONG (depends on message; in general 0 means failure).
  322. //
  323. LONG APIENTRY CPlApplet (HWND hWnd, UINT uMsg, LPARAM lParam1, LPARAM lParam2)
  324. {
  325. switch (uMsg)
  326. {
  327. // Initialize. You can allocate memory here.
  328. case CPL_INIT:
  329. return TRUE;
  330. // How many applets are in this DLL?
  331. case CPL_GETCOUNT:
  332. return 1;
  333. // Requesting information about the dialog box.
  334. // lParam1 is the dialog box number (we have only one) and
  335. // lParam2 is the pointer to a CPLINFO structure.
  336. // There is no return value.
  337. case CPL_INQUIRE:
  338. {
  339. UINT uAppNum = (UINT)lParam1;
  340. LPCPLINFO pCplInfo = (LPCPLINFO)lParam2;
  341. if (!pCplInfo)
  342. return TRUE; // unsuccessful
  343. if (uAppNum == 0) // first Applet?
  344. {
  345. pCplInfo->idIcon = IDI_AC97CPL;
  346. pCplInfo->idName = IDS_AC97CPL;
  347. pCplInfo->idInfo = IDS_AC97CPLINFO;
  348. }
  349. break;
  350. }
  351. // This is basically the same as CPL_INQUIRE, but passes a pointer
  352. // to a different structure.
  353. // This function is called before CPL_INQUIRE and if we return zero
  354. // here, then CPL_INQUIRE is called.
  355. case CPL_NEWINQUIRE:
  356. break;
  357. // One of these messages are sent when we should display the dialog box.
  358. // There is no return value.
  359. // lParam1 is the dialog box number (we have only one)
  360. case CPL_DBLCLK:
  361. case CPL_STARTWPARMS:
  362. {
  363. UINT uAppNum = (UINT)lParam1;
  364. if (uAppNum == 0) // first Applet?
  365. DisplayPropertySheet (hWnd);
  366. break;
  367. }
  368. // We get unloaded in a second.
  369. // There is no return value.
  370. case CPL_EXIT:
  371. break;
  372. default: // Who knows?
  373. break;
  374. }
  375. return 0;
  376. }