- взаимодействия компонент программного обеспечения через IOCTL-запросы
Разработаны механизмы:
- поиска доступа к аудиоустройству в режиме ядра
- синхронизации потоков, работающих на разных уровнях IRQL
Разработано программное обеспечение в соответствии с техническим заданием и проведено его тестирование.
Разработанный программный продукт полностью удовлетворяет поставленной задаче и осуществляет настраиваемое озвучивание нажатий клавиш на клавиатуре под управлением ОС Microsoft Windows NT 5.
5. Список литературы
1. Oney W. Programming the Microsoft Windows Driver Model.— Redmond, Washington: Microsoft Press., 1999.
2. Форум разработчиков MS Windows на сайте microsoft.com.
3. Рассылка, посвящённая разработке аудиодрайверов на сайте wdmaudiodev.de
4. Рассылка, посвящённая разработке драйверов для Windows на сайте osronline.com
5. Microsoft Windows Server 2003 DDK Documentation.
6. Приложения
6.1 Функции установки драйвера в системе
#define DRIVER_KEY "System\CurrentControlSet\Services\"DRIVER_NAME
#define FILTER_KEY "System\CurrentControlSet\Control\Class\{4D36E96B-E325-11CE-BFC1-08002BE10318}"
char * SearchString(char * Value, DWORD ValueLength, char * String)
{if(ValueLength < strlen(String)) return NULL;
DWORD len = (DWORD) (ValueLength - strlen(String));
do
{if(!stricmp(&Value[len], String) && (!len || !Value[len - 1]))
{return &Value[len];}}
while(len--);
return NULL;}
HRESULT DriverWasInstalled()
{HKEY hKeyFilter;
DWORD type, length;
char filters[MAX_PATH];
HRESULT hr = S_OK;
if(RegCreateKey(HKEY_LOCAL_MACHINE, FILTER_KEY, &hKeyFilter) == ERROR_SUCCESS)
{length = sizeof(filters);
RegQueryValueEx(hKeyFilter, "UpperFilters", 0, &type, (PUCHAR) filters, &length);
if(SearchString(filters, length, DRIVER_NAME))
{hr = S_OK;}
else
{hr = E_FAIL;}
RegCloseKey(hKeyFilter);}
Else
{hr = E_FAIL;}
return hr;}
HRESULT InstallDriver()
{HKEY hKeyDriver, hKeyFilter;
DWORD value, type, length;
char filters[MAX_PATH];
char SystemDirectory[MAX_PATH];
HRESULT hr = S_OK;
GetSystemDirectory(SystemDirectory, sizeof(SystemDirectory));
strcat(SystemDirectory, "\Drivers\"DRIVER_NAME".sys");
if(!CopyFile("driver\"DRIVER_NAME".sys", SystemDirectory, FALSE))
{hr = E_ACCESSDENIED;}
else if(RegCreateKey(HKEY_LOCAL_MACHINE, DRIVER_KEY, &hKeyDriver) == ERROR_SUCCESS &&
RegCreateKey(HKEY_LOCAL_MACHINE, FILTER_KEY, &hKeyFilter) == ERROR_SUCCESS)
{value = 1;
RegSetValueEx(hKeyDriver, "Type", 0, REG_DWORD, (PUCHAR) &value, sizeof(value));
value = 1;
RegSetValueEx(hKeyDriver,"ErrorControl",0,REG_DWORD, (PUCHAR)&value, sizeof(value));
value = 3;
RegSetValueEx(hKeyDriver, "Start", 0, REG_DWORD, (PUCHAR) &value, sizeof(value));
length = sizeof(filters);
RegQueryValueEx(hKeyFilter, "UpperFilters", 0, &type, (PUCHAR) filters, &length);
if(!SearchString(filters, length, DRIVER_NAME))
{strcpy(&filters[length - 1], DRIVER_NAME);
length += (DWORD) strlen(DRIVER_NAME);
filters[length] = 0;
RegSetValueEx(hKeyFilter,"UpperFilters",0,type, (PUCHAR)filters, length+1);}
else
{hr = S_FALSE;}
RegCloseKey(hKeyDriver);
RegCloseKey(hKeyFilter);}
else
{DeleteFile(SystemDirectory);
hr = E_ACCESSDENIED;}
return hr;}
HRESULT UninstallDriver()
{HKEY hKey;
DWORD type, length;
char filters[MAX_PATH], * ptr;
char SystemDirectory[MAX_PATH];
HRESULT hr = S_OK;
if(RegOpenKey(HKEY_LOCAL_MACHINE, FILTER_KEY, &hKey) == ERROR_SUCCESS)
{length = sizeof(filters);
RegQueryValueEx(hKey, "UpperFilters", 0, &type, (PUCHAR) filters, &length);
if(ptr = SearchString(filters, length, DRIVER_NAME))
{memcpy(ptr,ptr+strlen(DRIVER_NAME)+1,length-(ptr-filters)-strlen(DRIVER_NAME)-1);
length -= (DWORD) strlen(DRIVER_NAME) + 1;
RegSetValueEx(hKey, "UpperFilters", 0, type, (PUCHAR) filters, length);}
else
{hr = S_FALSE;}
RegCloseKey(hKey);}
else
{hr = E_ACCESSDENIED;}
RegDeleteKey(HKEY_LOCAL_MACHINE, DRIVER_KEY"\Security");
RegDeleteKey(HKEY_LOCAL_MACHINE, DRIVER_KEY"\Enum");
RegDeleteKey(HKEY_LOCAL_MACHINE, DRIVER_KEY);
GetSystemDirectory(SystemDirectory, sizeof(SystemDirectory));
strcat(SystemDirectory, "\Drivers\"DRIVER_NAME".sys");
if(!DeleteFile(SystemDirectory))
{hr = S_FALSE;}
return hr;}
6.2 Изменения в библиотеке DirectKS
В файле audfilter.cpp
Что заменить:
CKsAudRenPin*
CKsAudRenFilter::CreateRenderPin
(const WAVEFORMATEX* pwfx,
BOOL fLooped)
{TRACE_ENTER();
HRESULT hr = S_OK;
CKsAudRenPin* pPin = FindViablePin(pwfx);
if (!pPin)
{DebugPrintf(TRACE_NORMAL, TEXT("Could not find a Render pin that supports the given wave format"));
hr = E_FAIL;}
else
{hr = pPin->SetFormat(pwfx);
if (FAILED(hr))
{DebugPrintf(TRACE_ERROR, TEXT("Failed to set Render Pin format - the pin lied about its supported formats"));}}
if (SUCCEEDED(hr))
{hr = pPin->Instantiate(fLooped);
if (SUCCEEDED(hr))
{DebugPrintf(TRACE_LOW, TEXT("Successfully instantiated Render Pin. Handle = 0x%08x"), pPin->GetHandle());}
else
{DebugPrintf(TRACE_ERROR, TEXT("Failed to instantiate Render Pin"));}}
if (FAILED(hr))
{// Initialize pPin to NULL again
pPin = NULL;
// Try to intstantiate all the pins, one at a time
CKsPin *pKsPin;
LISTPOS listPosPin = m_listRenderSinkPins.GetHeadPosition();
while( !pPin && m_listRenderSinkPins.GetNext( listPosPin, &pKsPin ))
{CKsAudRenPin *pKsAudRenPin = (CKsAudRenPin *)pKsPin;
hr = pKsAudRenPin->SetFormat( pwfx );
if (SUCCEEDED(hr))
{hr = pKsAudRenPin->Instantiate(fLooped);}
if (SUCCEEDED(hr))
{// Save the pin in pPin
pPin = pKsAudRenPin;
break;}}}
if (FAILED(hr))
{// Don't delete the pin - it's still in m_listRenderPins
//delete pPin;
pPin = NULL;}
else
{// Remove the pin from the filter's list of pins
LISTPOS listPosPinNode = m_listPins.Find( pPin );
assert(listPosPinNode);
m_listPins.RemoveAt( listPosPinNode );
listPosPinNode = m_listRenderSinkPins.Find( pPin );
assert(listPosPinNode);
m_listRenderSinkPins.RemoveAt( listPosPinNode );}
TRACE_LEAVE_HRESULT(hr);
return pPin;}
Заменить на:
CKsAudRenPin*
CKsAudRenFilter::CreateRenderPin
(BOOL fLooped)
{TRACE_ENTER();
HRESULT hr = S_OK;
CKsAudRenPin * pPin = FindViablePin();
if(!pPin)
{DebugPrintf(TRACE_NORMAL, TEXT("Could not find a Render pin that supports the given wave format"));
hr = E_FAIL;}
if(SUCCEEDED(hr))
{hr = pPin->Instantiate(fLooped);
if (SUCCEEDED(hr))
{DebugPrintf(TRACE_LOW, TEXT("Successfully instantiated Render Pin. Handle = 0x%08x"), pPin->GetHandle());}
else
{DebugPrintf(TRACE_ERROR, TEXT("Failed to instantiate Render Pin"));}}
/*if(FAILED(hr))
{// Initialize pPin to NULL again
pPin = NULL;
// Try to intstantiate all the pins, one at a time
CKsPin * pKsPin;
LISTPOS listPosPin = m_listRenderSinkPins.GetHeadPosition();
while(!pPin && m_listRenderSinkPins.GetNext(listPosPin, &pKsPin))
{CKsAudRenPin * pKsAudRenPin = (CKsAudRenPin *)pKsPin;
hr = pKsAudRenPin->Instantiate(fLooped);
if(SUCCEEDED(hr))
{// Save the pin in pPin
pPin = pKsAudRenPin;
break;}}}*/
if(FAILED(hr))
{// Don't delete the pin - it's still in m_listRenderPins
//delete pPin;
pPin = NULL;}
else
{// Remove the pin from the filter's list of pins
LISTPOS listPosPinNode = m_listPins.Find(pPin);
assert(listPosPinNode);
m_listPins.RemoveAt(listPosPinNode);
listPosPinNode = m_listRenderSinkPins.Find(pPin);
assert(listPosPinNode);
m_listRenderSinkPins.RemoveAt(listPosPinNode);}
TRACE_LEAVE_HRESULT(hr);
return pPin;}
Что заменить:
CKsAudRenPin*
CKsAudRenFilter::FindViablePin
(const WAVEFORMATEX* pwfx)
{TRACE_ENTER();
assert( pwfx );
CKsPin* pNode;
LISTPOS listPos = m_listRenderSinkPins.GetHeadPosition();
while(m_listRenderSinkPins.GetNext( listPos, &pNode ))
{CKsAudRenPin* pPin = (CKsAudRenPin*)pNode;
// To only look at non-digital output pins, check that pPin->IsVolumeSupported() is TRUE,
// as digital output pins don't have volume controls associated with them.
if( pPin->IsFormatSupported( pwfx ) )
{// This should be a valid pin
TRACE_LEAVE();
return pPin;}}
TRACE_LEAVE();
return NULL;}
Заменить на:
CKsAudRenPin*
CKsAudRenFilter::FindViablePin
(){TRACE_ENTER();
CKsPin * pNode;
LISTPOS listPos = m_listRenderSinkPins.GetHeadPosition();
while(m_listRenderSinkPins.GetNext( listPos, &pNode ))
{CKsAudRenPin * pPin = (CKsAudRenPin*)pNode;
// To only look at non-digital output pins, check that pPin->IsVolumeSupported() is TRUE,
// as digital output pins don't have volume controls associated with them.
if(pPin->IsFormatSupported())
{/ This should be a valid pin
TRACE_LEAVE();
return pPin;}}
TRACE_LEAVE();
return NULL;}
В файле audfilter.h
Что заменить:
CKsAudRenPin* CreateRenderPin(const WAVEFORMATEX* pwfx, BOOL fLooped);
Заменить на:
CKsAudRenPin * CreateRenderPin(BOOL fLooped);
Что заменить:
CKsAudRenPin* FindViablePin(const WAVEFORMATEX* pwfx);
Заменить на:
CKsAudRenPin * FindViablePin();
В файле audpin.cpp
Что заменить:
BOOL CKsAudPin::IsFormatSupported(const WAVEFORMATEX* pwfx)
{TRACE_ENTER();
LISTPOS listPosRange = m_listDataRange.GetHeadPosition();
KSDATARANGE_AUDIO* pKSDATARANGE_AUDIO;
while( m_listDataRange.GetNext( listPosRange, &pKSDATARANGE_AUDIO ) )
{if( KSDATAFORMAT_TYPE_WILDCARD == pKSDATARANGE_AUDIO->DataRange.MajorFormat
|| KSDATAFORMAT_TYPE_AUDIO == pKSDATARANGE_AUDIO->DataRange.MajorFormat )
{// Set the format to search for
GUID guidFormat = {DEFINE_WAVEFORMATEX_GUID(pwfx->wFormatTag)};
// If this is a WaveFormatExtensible structure, then use its defined SubFormat
if( WAVE_FORMAT_EXTENSIBLE == pwfx->wFormatTag )
{guidFormat = ((WAVEFORMATEXTENSIBLE *)pwfx)->SubFormat;}
if( KSDATAFORMAT_SUBTYPE_WILDCARD == pKSDATARANGE_AUDIO->DataRange.SubFormat
|| guidFormat == pKSDATARANGE_AUDIO->DataRange.SubFormat )
{if( KSDATAFORMAT_SPECIFIER_WILDCARD == pKSDATARANGE_AUDIO->DataRange.Specifier
|| KSDATAFORMAT_SPECIFIER_WAVEFORMATEX == pKSDATARANGE_AUDIO->DataRange.Specifier )
{if( pKSDATARANGE_AUDIO->MaximumChannels >= pwfx->nChannels
&& pKSDATARANGE_AUDIO->MinimumBitsPerSample <= pwfx->wBitsPerSample
&& pKSDATARANGE_AUDIO->MaximumBitsPerSample >= pwfx->wBitsPerSample
&& pKSDATARANGE_AUDIO->MinimumSampleFrequency <= pwfx->nSamplesPerSec
&& pKSDATARANGE_AUDIO->MaximumSampleFrequency >= pwfx->nSamplesPerSec )
{// This should be a valid pin
TRACE_LEAVE();
return TRUE;}}}}}
TRACE_LEAVE();
return FALSE;}
Заменить на:
BOOL CKsAudPin::IsFormatSupported()
{TRACE_ENTER();
LISTPOS listPosRange = m_listDataRange.GetHeadPosition();
KSDATARANGE_MUSIC * pKSDATARANGE_MUSIC;
while(m_listDataRange.GetNext(listPosRange, &pKSDATARANGE_MUSIC))
{if(KSDATAFORMAT_TYPE_WILDCARD == pKSDATARANGE_MUSIC->DataRange.MajorFormat
||KSDATAFORMAT_TYPE_MUSIC == pKSDATARANGE_MUSIC->DataRange.MajorFormat)
{if(KSDATAFORMAT_SUBTYPE_WILDCARD == pKSDATARANGE_MUSIC->DataRange.SubFormat
||KSDATAFORMAT_SUBTYPE_MIDI == pKSDATARANGE_MUSIC->DataRange.SubFormat)
{if(KSDATAFORMAT_SPECIFIER_WILDCARD == pKSDATARANGE_MUSIC->DataRange.Specifier
||KSDATAFORMAT_SPECIFIER_NONE == pKSDATARANGE_MUSIC->DataRange.Specifier)
{if(KSMUSIC_TECHNOLOGY_SWSYNTH == pKSDATARANGE_MUSIC->Technology)
{// This should be a valid pin
TRACE_LEAVE();
return TRUE;}}}}}
TRACE_LEAVE();
return FALSE;}
Что заменить:
HRESULT CKsAudPin::Init()
{TRACE_ENTER();
HRESULT hr = S_OK;
BOOL fViablePin = FALSE;
// Make sure at least one interface is standard streaming
if (SUCCEEDED(hr))
{fViablePin = FALSE;
for(ULONG i = 0; i < m_Descriptor.cInterfaces && !fViablePin; i++)
{fViablePin =
fViablePin ||
IsEqualGUIDAligned(m_Descriptor.pInterfaces[i].Set, KSINTERFACESETID_Standard) &&
(m_Descriptor.pInterfaces[i].Id == KSINTERFACE_STANDARD_STREAMING) ;}
if (!fViablePin)
{DebugPrintf(TRACE_ERROR, TEXT("No standard streaming interfaces on the pin"));
hr = E_FAIL;}}
// Make sure at least one medium is standard streaming
if (SUCCEEDED(hr))
{fViablePin = FALSE;
for(ULONG i = 0; i < m_Descriptor.cInterfaces && !fViablePin; i++)
{fViablePin =
fViablePin ||
IsEqualGUIDAligned(m_Descriptor.pMediums[i].Set, KSMEDIUMSETID_Standard) &&
(m_Descriptor.pMediums[i].Id == KSMEDIUM_STANDARD_DEVIO) ;}
if (!fViablePin)
{DebugPrintf(TRACE_ERROR, TEXT("No standard streaming mediums on the pin"));
hr = E_FAIL;}}
// Make sure at least one datarange supports audio
if (SUCCEEDED(hr))
{fViablePin = FALSE;
PKSDATARANGE pDataRange = m_Descriptor.pDataRanges;
for(ULONG i = 0; i < m_Descriptor.cDataRanges; i++)
{// SubType should either be compatible with WAVEFORMATEX or
// it should be WILDCARD
fViablePin =
fViablePin ||
IS_VALID_WAVEFORMATEX_GUID(&pDataRange->SubFormat) ||
IsEqualGUIDAligned(pDataRange->SubFormat, KSDATAFORMAT_SUBTYPE_PCM) ||
IsEqualGUIDAligned(pDataRange->SubFormat, KSDATAFORMAT_SUBTYPE_WILDCARD);
if (fViablePin && IsEqualGUIDAligned(pDataRange->MajorFormat, KSDATAFORMAT_TYPE_AUDIO))
{// Copy the data range into the pin
PKSDATARANGE_AUDIO pCopyDataRangeAudio = new KSDATARANGE_AUDIO;
if( pCopyDataRangeAudio )
{PKSDATARANGE_AUDIO pDataRangeAudio = (PKSDATARANGE_AUDIO)pDataRange;
CopyMemory( pCopyDataRangeAudio, pDataRangeAudio, sizeof(KSDATARANGE_AUDIO) );
if (NULL == m_listDataRange.AddTail( pCopyDataRangeAudio ))
{delete pCopyDataRangeAudio;
pCopyDataRangeAudio = NULL;
DebugPrintf(TRACE_ERROR, TEXT("Unable to allocate list entry to save datarange in"));
hr = E_OUTOFMEMORY;}}
else
{DebugPrintf(TRACE_ERROR, TEXT("Unable to allocate memory to save datarange in"));
hr = E_OUTOFMEMORY;}}
pDataRange = (PKSDATARANGE)( ((PBYTE)pDataRange) + pDataRange->FormatSize);}
if (!fViablePin)
{DebugPrintf(TRACE_ERROR, TEXT("No audio dataranges on the pin"));
hr = E_FAIL;}}
TRACE_LEAVE_HRESULT(hr);
return hr;}
Заменить на:
HRESULT CKsAudPin::Init()
{TRACE_ENTER();
HRESULT hr = S_OK;
BOOL fViablePin = FALSE;
// Make sure at least one interface is standard streaming
if (SUCCEEDED(hr))
{fViablePin = FALSE;
for(ULONG i = 0; i < m_Descriptor.cInterfaces && !fViablePin; i++)