windows-nt/Source/XPSP1/NT/drivers/ddk/wdmaudio/ac97/cpl/ac97cpl.cpp
2020-09-26 16:20:57 +08:00

430 lines
14 KiB
C++

/********************************************************************************
** Copyright (c) 2000 Microsoft Corporation. All Rights Reserved.
********************************************************************************/
#include <windows.h>
#include <cpl.h>
#include <ks.h>
#include <ksmedia.h>
#include <setupapi.h>
#include "resource.h"
#include "prvprop.h"
//
// Global Variables.
//
HINSTANCE ghInstance = NULL; // module handle.
const TCHAR AppletName[] = TEXT("AC97 control panel");
#if (DBG)
/////////////////////////////////////////////////////////////////////////////////
// dbgError
/////////////////////////////////////////////////////////////////////////////////
// This function prints an error message.
// It prints first the string passed and then the error that it gets with
// GetLastError as a string.
//
// Arguments:
// szMsg - message to print.
//
// Return Value:
// None.
//
void dbgError (LPCTSTR szMsg)
{
LPTSTR errorMessage;
DWORD count;
// Get the error message from the system.
count = FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
GetLastError (),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)&errorMessage,
0,
NULL);
// Print the msg + error + \n\r.
if (count)
{
OutputDebugString (szMsg);
OutputDebugString (errorMessage);
OutputDebugString (TEXT("\n\r"));
// This is for those without a debugger.
// MessageBox (NULL, szErrorMessage, szMsg, MB_OK | MB_ICONSTOP);
LocalFree (errorMessage);
}
else
{
OutputDebugString (AppletName);
OutputDebugString (TEXT(": Low memory condition. Cannot ")
TEXT("print error message.\n\r"));
}
}
#else
#define dbgError(a) 0;
#endif
/////////////////////////////////////////////////////////////////////////////////
// DllMain
/////////////////////////////////////////////////////////////////////////////////
// Main enty point of the DLL.
// Save the instance handle; it is needed for property sheet creation.
//
// Arguments:
// hModule - instance data, is equal to module handle
// ul_reason_for_call - the reason for the call
// lpReserved - some additional parameter.
//
// Return Value:
// BOOL: FALSE if DLL should fail, TRUE on success
//
BOOL APIENTRY DllMain (HANDLE hModule, ULONG ul_reason_for_call, LPVOID lpReserved)
{
ghInstance = (HINSTANCE) hModule;
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////////
// FindAC97Device
/////////////////////////////////////////////////////////////////////////////////
// This function stores the device info and device data of the "ac97smpl" driver.
// It first creates a list of all devices that have a topology filter exposed
// and then searches through the list to find the device with the service
// "ac97smpl". The information is stored in pspRequest.
//
// For simplicity we search for the service name "ac97smpl".
// Alternately, one could get more information about the device or driver,
// then decide if it is suitable (regardless of its name).
//
// Arguments:
// pspRequest pointer to Property sheet page request structure.
// DeviceInfoData pointer to Device info data structure.
//
// Return Value:
// TRUE on success, otherwise FALSE.
// Note: on success that we have the device list still open - we have to destroy
// the list later. The handle is stored at pspRequest->DeviceInfoSet.
//
BOOL FindAC97Device (PSP_PROPSHEETPAGE_REQUEST pspRequest,
PSP_DEVINFO_DATA DeviceInfoData)
{
TCHAR szServiceName[128];
//
// Prepare the pspRequest structure...
//
pspRequest->cbSize = sizeof (SP_PROPSHEETPAGE_REQUEST);
pspRequest->DeviceInfoData = DeviceInfoData;
pspRequest->PageRequested = SPPSR_ENUM_ADV_DEVICE_PROPERTIES;
// ...and the DeviceInfoData structure.
DeviceInfoData->cbSize = sizeof (SP_DEVINFO_DATA);
// Create a list of devices with Topology interface.
pspRequest->DeviceInfoSet = SetupDiGetClassDevs (&KSCATEGORY_TOPOLOGY,
NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
// None found?
if (pspRequest->DeviceInfoSet == INVALID_HANDLE_VALUE)
{
dbgError (TEXT("Test: SetupDiGetClassDevs: "));
return FALSE;
}
//
// Go through the list of all devices found.
//
int nIndex = 0;
while (SetupDiEnumDeviceInfo (pspRequest->DeviceInfoSet, nIndex, DeviceInfoData))
{
//
// Get the service name for that device.
//
if (!SetupDiGetDeviceRegistryProperty (pspRequest->DeviceInfoSet, DeviceInfoData,
SPDRP_SERVICE, NULL, (PBYTE)szServiceName,
sizeof (szServiceName), NULL))
{
dbgError (TEXT("Test: SetupDiGetDeviceRegistryProperty: "));
SetupDiDestroyDeviceInfoList (pspRequest->DeviceInfoSet);
return FALSE;
}
//
// We only care about service "ac97smpl"
//
DWORD lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
if (CompareString (lcid, NORM_IGNORECASE, szServiceName,
-1, TEXT("AC97SMPL"), -1) == CSTR_EQUAL)
{
//
// We found it! The information is already stored, just return.
// Note that we have the device list still open - we have to destroy
// the list later.
//
return TRUE;
}
// Take the next in the list.
nIndex++;
}
//
// We did not find the service.
//
SetupDiDestroyDeviceInfoList (pspRequest->DeviceInfoSet);
return FALSE;
}
/////////////////////////////////////////////////////////////////////////////////
// AddPropSheet
/////////////////////////////////////////////////////////////////////////////////
// This function is a callback that is passed to the "AC97PropPageProvider"
// function of "ac97prop.dll". It is used to add the property page sheet
// to the property dialog.
// What we do here is store the property sheet handle and return.
//
// Arguments:
// hPSP property sheet handle
// lParam parameter that we passed to "AC97PropPageProvider".
//
// Return Value:
// TRUE on success, otherwise FALSE.
//
BOOL APIENTRY AddPropSheet (HPROPSHEETPAGE hPSP, LPARAM lParam)
{
HPROPSHEETPAGE **pphPropSheet = (HPROPSHEETPAGE **)lParam;
HPROPSHEETPAGE *phPropSheetPage;
// Check the parameters
if (!pphPropSheet)
return FALSE;
// Allocate the space for the handle.
phPropSheetPage = (HPROPSHEETPAGE *)LocalAlloc (LPTR, sizeof(HPROPSHEETPAGE));
if (!phPropSheetPage)
return FALSE;
*phPropSheetPage = hPSP;
*pphPropSheet = phPropSheetPage;
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////////
// GetDLLInfo
/////////////////////////////////////////////////////////////////////////////////
// This function loads the library and gets the entry point address.
// With the information returned we can create the property dialog.
//
// For simplicity reasons we load the DLL "ac97prop" and call the function
// "AC97PropPageProvider". A more flexible course of action is to get this
// information from the registry. To do this, we read the "EnumPropPages32"
// entry in the drivers section to obtain a registry path (read the "drivers"
// entry in the device section to get the registry path of the drivers section)
// -- this path leads to a key and entry which specifies the DLL and entry point.
//
// Arguments:
// *phDLL pointer to module handle of loaded DLL.
// *pAC97PropPageProvider pointer to "AC97PropPageProvider" in loaded DLL
//
// Return Value:
// TRUE on success, otherwise FALSE.
// Note: on success the library is still loaded.
//
BOOL GetDLLInfo (HMODULE *phDLL, LPFNADDPROPSHEETPAGES *pAC97PropPageProvider)
{
// Load the library.
*phDLL = LoadLibrary (TEXT("ac97prop.dll"));
if (!*phDLL)
{
dbgError (TEXT("DisplayPropertySheet: LoadLibrary"));
return FALSE;
}
// Get the address of the function.
*pAC97PropPageProvider = (LPFNADDPROPSHEETPAGES)GetProcAddress (*phDLL,
"AC97PropPageProvider");
if (!*pAC97PropPageProvider)
{
dbgError (TEXT("DisplayPropertySheet: GetProcAddress"));
FreeLibrary (*phDLL);
return FALSE;
}
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////////
// DisplayPropertySheet
/////////////////////////////////////////////////////////////////////////////////
// This function displays the property dialog.
// It is called by CPlApplet when the ac97cpl icon gets a double click.
//
// Arguments:
// hWnd parent window handle
//
// Return Value:
// None.
//
void DisplayPropertySheet (HWND hWnd)
{
SP_PROPSHEETPAGE_REQUEST pspRequest; // structure passed to ac97prop
SP_DEVINFO_DATA DeviceInfoData; // pspRequest points to it.
HMODULE hDLL; // Module handle of library
LPFNADDPROPSHEETPAGES AC97PropPageProvider; // function to be called.
PROPSHEETHEADER psh;
// You could move this to CPL_INIT, then it would be called
// before the control panel window appears.
// In case of an failure the icon would not be displayed. In our sample
// however, the icon will be displayed and when the user clicks on it he
// gets the error message.
if (!FindAC97Device(&pspRequest, &DeviceInfoData))
{
MessageBox (hWnd, TEXT("You must install the ac97 sample driver."),
AppletName, MB_ICONSTOP | MB_OK);
return;
}
// Load the library and get the function pointer.
if (!GetDLLInfo (&hDLL, &AC97PropPageProvider))
{
MessageBox (hWnd, TEXT("The ac97 property page DLL could not load."),
AppletName, MB_ICONSTOP | MB_OK);
SetupDiDestroyDeviceInfoList (pspRequest.DeviceInfoSet);
return;
}
//
// Prepare the header for the property sheet.
//
psh.nStartPage = 0;
psh.dwSize = sizeof(psh);
psh.dwFlags = PSH_PROPTITLE | PSH_NOAPPLYNOW;
psh.hwndParent = hWnd;
psh.hInstance = ghInstance;
psh.pszIcon = NULL;
psh.pszCaption = MAKEINTRESOURCE(IDS_AC97CPL);
psh.nPages = 1;
// Call the function to request the property sheet page.
if (!(*AC97PropPageProvider) ((LPVOID)&pspRequest, AddPropSheet, (LPARAM)&psh.phpage))
{
MessageBox (hWnd, TEXT("\"AC97PropPageProvider\" had a failure."),
AppletName, MB_ICONSTOP | MB_OK);
FreeLibrary (hDLL);
SetupDiDestroyDeviceInfoList (pspRequest.DeviceInfoSet);
return;
}
// Create the dialog. The function returns when the dialog is closed.
if (PropertySheet (&psh) < 0)
{
//
// Dialog closed abnormally. This might be a system failure.
//
MessageBox (hWnd, TEXT("Please reinstall the ac97 sample driver."),
AppletName, MB_ICONSTOP | MB_OK);
}
// Clean up.
FreeLibrary (hDLL);
LocalFree (psh.phpage);
SetupDiDestroyDeviceInfoList (pspRequest.DeviceInfoSet);
}
/////////////////////////////////////////////////////////////////////////////////
// CPlApplet
/////////////////////////////////////////////////////////////////////////////////
// This function is called by the control panel manager. It is very similar to
// a Windows message handler (search for CplApplet in MSDN for description).
//
// Arguments:
// HWND hWnd Parent window handle
// UINT uMsg The message
// LPARAM lParam1 depends on message
// LPARAM lParam2 depends on message
//
// Return Value:
// LONG (depends on message; in general 0 means failure).
//
LONG APIENTRY CPlApplet (HWND hWnd, UINT uMsg, LPARAM lParam1, LPARAM lParam2)
{
switch (uMsg)
{
// Initialize. You can allocate memory here.
case CPL_INIT:
return TRUE;
// How many applets are in this DLL?
case CPL_GETCOUNT:
return 1;
// Requesting information about the dialog box.
// lParam1 is the dialog box number (we have only one) and
// lParam2 is the pointer to a CPLINFO structure.
// There is no return value.
case CPL_INQUIRE:
{
UINT uAppNum = (UINT)lParam1;
LPCPLINFO pCplInfo = (LPCPLINFO)lParam2;
if (!pCplInfo)
return TRUE; // unsuccessful
if (uAppNum == 0) // first Applet?
{
pCplInfo->idIcon = IDI_AC97CPL;
pCplInfo->idName = IDS_AC97CPL;
pCplInfo->idInfo = IDS_AC97CPLINFO;
}
break;
}
// This is basically the same as CPL_INQUIRE, but passes a pointer
// to a different structure.
// This function is called before CPL_INQUIRE and if we return zero
// here, then CPL_INQUIRE is called.
case CPL_NEWINQUIRE:
break;
// One of these messages are sent when we should display the dialog box.
// There is no return value.
// lParam1 is the dialog box number (we have only one)
case CPL_DBLCLK:
case CPL_STARTWPARMS:
{
UINT uAppNum = (UINT)lParam1;
if (uAppNum == 0) // first Applet?
DisplayPropertySheet (hWnd);
break;
}
// We get unloaded in a second.
// There is no return value.
case CPL_EXIT:
break;
default: // Who knows?
break;
}
return 0;
}