2025-11-28 00:35:46 +09:00

784 lines
21 KiB
C++

#include "mapper.h"
#include "MainDialog.h"
#include "types.h"
#include "fil_data.h"
// Forward declares
void FillMajorTypes(ListBox& listbox);
void FillSubType(ListBox& listboxMajor, ListBox& listboxMinor);
void EnableSecondTypePair(
ListBox& ListMajor,
ListBox& ListMajor2,
ListBox& ListMinor2
);
void FillTypeArray(
ListBox& ListMajor,
ListBox& ListMinor,
GUID *atypes,
int nIndex,
DWORD *pdwPairs
);
void AddMeritToString(WCHAR *szInfo, size_t len, DWORD dwMerit);
/// MainDialog
MainDialog::MainDialog()
: CBaseDialog(IDD_MAPPER_DIALOG),
m_pMapper(NULL)
{
}
MainDialog::~MainDialog()
{
SAFE_RELEASE(m_pMapper);
}
HRESULT MainDialog::OnInitDialog()
{
HRESULT hr;
// Create the filter mapper that will be used for all queries
hr = CoCreateInstance(
CLSID_FilterMapper2,
NULL, CLSCTX_INPROC, IID_IFilterMapper2,
(void **) &m_pMapper);
if (SUCCEEDED(hr))
{
InitializeControls();
SetDefaults();
// Customize list box tab stops for good formatting.
int nTabStops[2]={140,230};
m_ListFilters.SendMessage(LB_SETTABSTOPS, 2, (LPARAM)nTabStops);
// Perform a default search with the default parameters.
OnButtonSearch();
}
return hr;
}
INT_PTR MainDialog::OnCommand(HWND hControl, WORD idControl, WORD msg)
{
switch (idControl)
{
case IDC_BUTTON_SEARCH:
if (msg == BN_CLICKED)
{
OnButtonSearch();
}
break;
case IDC_BUTTON_CLEAR:
if (msg == BN_CLICKED)
{
OnButtonClear();
}
break;
case IDC_LIST_INPUT_MAJOR:
if (msg == LBN_SELCHANGE)
{
OnSelchangeListInputMajor();
}
break;
case IDC_LIST_OUTPUT_MAJOR:
if (msg == LBN_SELCHANGE)
{
OnSelchangeListOutputMajor();
}
break;
case IDC_LIST_INPUT_MAJOR2:
if (msg == LBN_SELCHANGE)
{
OnSelchangeListInputMajor2();
}
break;
case IDC_LIST_OUTPUT_MAJOR2:
if (msg == LBN_SELCHANGE)
{
OnSelchangeListOutputMajor2();
}
break;
}
return 1;
}
///////////////////////////////////////////////////////////////////////
// Name: InitializeControls
// Desc: Associates the control wrapper classes with the
// correct windows for the control.
///////////////////////////////////////////////////////////////////////
void MainDialog::InitializeControls()
{
m_ListOutputMinor2.SetWindow(GetDlgItem(IDC_LIST_OUTPUT_MINOR2));
m_ListOutputMinor.SetWindow(GetDlgItem(IDC_LIST_OUTPUT_MINOR));
m_ListOutputMajor2.SetWindow(GetDlgItem(IDC_LIST_OUTPUT_MAJOR2));
m_ListOutputMajor.SetWindow(GetDlgItem(IDC_LIST_OUTPUT_MAJOR));
m_ListInputMinor2.SetWindow(GetDlgItem(IDC_LIST_INPUT_MINOR2));
m_ListInputMinor.SetWindow(GetDlgItem(IDC_LIST_INPUT_MINOR));
m_ListInputMajor2.SetWindow(GetDlgItem(IDC_LIST_INPUT_MAJOR2));
m_ListInputMajor.SetWindow(GetDlgItem(IDC_LIST_INPUT_MAJOR));
m_bAtLeastOneOutputPin.SetWindow(GetDlgItem(IDC_CHECK_OUTPUT_PIN));
m_bAtLeastOneInputPin.SetWindow(GetDlgItem(IDC_CHECK_INPUT_PIN));
m_bIsRenderer.SetWindow(GetDlgItem(IDC_CHECK_RENDERER));
m_bExactMatch.SetWindow(GetDlgItem(IDC_CHECK_EXACT_MATCH));
m_ComboMerit.SetWindow(GetDlgItem(IDC_COMBO_MERIT));
m_ComboOutputCat.SetWindow(GetDlgItem(IDC_COMBO_OUTPUT_CATEGORY));
m_ComboInputCat.SetWindow(GetDlgItem(IDC_COMBO_INPUT_CATEGORY));
m_ListFilters.SetWindow(GetDlgItem(IDC_LIST_FILTERS));
}
///////////////////////////////////////////////////////////////////////
// Name: SetDefaults
// Desc: Restore the UI controls to their default settings.
///////////////////////////////////////////////////////////////////////
void MainDialog::SetDefaults()
{
// The app allows you to specify up to two major/minor type pairs.
FillMajorTypes(m_ListInputMajor);
FillMajorTypes(m_ListInputMajor2);
FillMajorTypes(m_ListOutputMajor);
FillMajorTypes(m_ListOutputMajor2);
// Initialize subtype list boxes
m_ListInputMinor.ClearItems();
m_ListInputMinor2.ClearItems();
m_ListOutputMinor.ClearItems();
m_ListOutputMinor2.ClearItems();
// Set checkboxes to preferred default values
m_bAtLeastOneInputPin.SetCheck(1);
m_bAtLeastOneOutputPin.SetCheck(1);
// Initialize merit box
m_ComboMerit.ClearItems();
for (int i=0; i < NUM_MERIT_TYPES; i++)
{
m_ComboMerit.InsertString(i, merittypes[i].szName);
m_ComboMerit.SetItemData(i, merittypes[i].dwMerit);
}
m_ComboMerit.Select(4); // "Normal" merit
// Initialize pin categories
m_ComboInputCat.ClearItems();
m_ComboOutputCat.ClearItems();
m_ComboInputCat.AddString(L"<Don't care>\0");
m_ComboOutputCat.AddString(L"<Don't care>\0");
// Fill pin category lists
for (int i=1; i < NUM_PIN_TYPES; i++)
{
m_ComboInputCat.InsertString(i, pintypes[i].szName);
m_ComboInputCat.SetItemData(i, (DWORD_PTR)pintypes[i].pGUID);
m_ComboOutputCat.InsertString(i, pintypes[i].szName);
m_ComboOutputCat.SetItemData(i, (DWORD_PTR)pintypes[i].pGUID);
}
m_ComboInputCat.Select(0);
m_ComboOutputCat.Select(0);
// Clear filter list
m_ListFilters.ClearItems();
SetDlgItemText(IDC_STATIC_NUMFILTERS, L"Filters Matching Query : 0");
// Select the first item in each type list
FillSubType(m_ListInputMajor, m_ListInputMinor);
FillSubType(m_ListInputMajor2, m_ListInputMinor2);
FillSubType(m_ListOutputMajor, m_ListOutputMinor);
FillSubType(m_ListOutputMajor2, m_ListOutputMinor2);
// Disable the second type/subtype listboxes until the user selects
// something other than "don't care" for the first type/subtype pair.
OnSelchangeListInputMajor();
OnSelchangeListOutputMajor();
}
///////////////////////////////////////////////////////////////////////
// Name: OnButtonClear
// Desc: Called when the Clear button is clicked.
///////////////////////////////////////////////////////////////////////
void MainDialog::OnButtonClear()
{
// Clear all values and reset dialog
SetDefaults();
}
///////////////////////////////////////////////////////////////////////
// Name: OnSelchangeListInputMajor
// Desc: Called when the "Input Media Type" list is selected.
///////////////////////////////////////////////////////////////////////
void MainDialog::OnSelchangeListInputMajor()
{
// User has selected a new major type, so refill the subtype list box
FillSubType(m_ListInputMajor, m_ListInputMinor);
// Since the second type/subtype pair is irrelevant if the first
// is a don't care, disable the second set if appropriate.
EnableSecondTypePair(m_ListInputMajor, m_ListInputMajor2, m_ListInputMinor2);
}
///////////////////////////////////////////////////////////////////////
// Name: OnSelchangeListInputMajor2
// Desc: Called when the "Secondary Input Type" list is selected.
///////////////////////////////////////////////////////////////////////
void MainDialog::OnSelchangeListInputMajor2()
{
// User has selected a new major type, so refill the subtype list box
FillSubType(m_ListInputMajor2, m_ListInputMinor2);
}
///////////////////////////////////////////////////////////////////////
// Name: OnSelchangeListOutputMajor
// Desc: Called when the "Output Media Type" list is selected.
///////////////////////////////////////////////////////////////////////
void MainDialog::OnSelchangeListOutputMajor()
{
// User has selected a new major type, so refill the subtype list box
FillSubType(m_ListOutputMajor, m_ListOutputMinor);
// Since the second type/subtype pair is irrelevant if the first
// is a don't care, disable the second set if appropriate.
EnableSecondTypePair(m_ListOutputMajor, m_ListOutputMajor2, m_ListOutputMinor2);
}
///////////////////////////////////////////////////////////////////////
// Name: OnSelchangeListOutputMajor2
// Desc: Called when the "Secondary Output Type" list is selected.
///////////////////////////////////////////////////////////////////////
void MainDialog::OnSelchangeListOutputMajor2()
{
// User has selected a new major type, so refill the subtype list box
FillSubType(m_ListOutputMajor2, m_ListOutputMinor2);
}
///////////////////////////////////////////////////////////////////////
// Name: OnButtonSearch
// Desc: Called when the "Saerch" button is clicked.
//
// This function enumerates the filters that match the search criteria
// the user has selected. For each matching filter, the name, merit,
// and DLL is listed.
//
///////////////////////////////////////////////////////////////////////
void MainDialog::OnButtonSearch()
{
HRESULT hr=S_OK;
int nFilters = 0;
IEnumMoniker *pEnum = NULL;
IMoniker *pMoniker=0;
// Clear any previous results
m_ListFilters.ClearItems();
// Enumerate filters based on the current dialog box selections.
hr = EnumerateFilters(&pEnum);
if (FAILED(hr))
{
return;
}
// Reset the enumerator.
hr = pEnum->Reset(); // Not strictly necessary but can't hurt.
// Go through each moniker in the collection.
while((hr = pEnum->Next(1, &pMoniker, NULL)) == S_OK)
{
IPropertyBag *pPropBag = NULL;
DWORD dwMerit;
VARIANT varName;
VARIANT varFilterClsid;
VariantInit(&varName);
VariantInit(&varFilterClsid);
// Initialize variant types
varName.vt = VT_BSTR;
varFilterClsid.vt = VT_BSTR;
// Get a property bag for this moniker.
hr = pMoniker->BindToStorage(
0, 0, IID_IPropertyBag, (void **)&pPropBag);
// Read the filter name from the property bag
if (SUCCEEDED(hr))
{
hr = pPropBag->Read(L"FriendlyName", &varName, 0);
}
// Read the Merit value from the property bag
if (SUCCEEDED(hr))
{
hr = GetMerit(pPropBag, &dwMerit);
}
// Read filter's CLSID from property bag. The CLSID is
// returned as a string (BSTR).
if (SUCCEEDED(hr))
{
hr = pPropBag->Read(L"CLSID", &varFilterClsid, 0);
}
// Add filter name and filename to listbox
if(SUCCEEDED(hr))
{
nFilters++;
AddFilterToList(varName.bstrVal, varFilterClsid.bstrVal, dwMerit);
}
// Clean up.
SysFreeString(varFilterClsid.bstrVal);
SysFreeString(varName.bstrVal);
SAFE_RELEASE(pPropBag);
SAFE_RELEASE(pMoniker);
}
// Display number of filters matching query
WCHAR szNumFilters[48];
hr = StringCchPrintf(szNumFilters, NUMELMS(szNumFilters), L"Filters Matching Query : %d\0", nFilters);
SetDlgItemText(IDC_STATIC_NUMFILTERS, szNumFilters);
if (nFilters == 0)
{
m_ListFilters.AddString(L"<No filters matched query>");
}
// Clean up enumerator
SAFE_RELEASE(pEnum);
}
///////////////////////////////////////////////////////////////////////
// Name: EnumerateFilters
// Desc: Enumerates the filters that match the user's search criteria.
///////////////////////////////////////////////////////////////////////
HRESULT MainDialog::EnumerateFilters(IEnumMoniker **ppEnum)
{
HRESULT hr;
assert(ppEnum);
// First set up the boolean values
BOOL bExactMatch = m_bExactMatch.IsChecked();
BOOL bAtLeastOneInputPin = m_bAtLeastOneInputPin.IsChecked();
BOOL bAtLeastOneOutputPin = m_bAtLeastOneOutputPin.IsChecked();
BOOL bIsRenderer = m_bIsRenderer.IsChecked();
DWORD_PTR dwMerit = 0;
GUID *pInCat = NULL;
GUID *pOutCat = NULL;
// Merit
m_ComboMerit.GetCurrentSelectionItemData(&dwMerit);
// Pin categories
m_ComboInputCat.GetCurrentSelectionItemData((DWORD_PTR*)&pInCat);
m_ComboOutputCat.GetCurrentSelectionItemData((DWORD_PTR*)&pOutCat);
// Major type/subtype pairs
DWORD dwInputTypes=0, dwOutputTypes=0;
GUID arrayInput[4], arrayOutput[4];
// Initialize GUID type/subtype arrays
for (int i=0; i<4; i++)
{
arrayInput[i] = GUID_NULL;
arrayOutput[i] = GUID_NULL;
}
// Fill each of the four GUID arrays (input/output, major/minor).
// If the first call doesn't set anything (primary), don't bother to
// read the secondary value, since it would be invalid anyway due to
// its position within the array (2) but with a count of only 1.
FillTypeArray(m_ListInputMajor, m_ListInputMinor, arrayInput, 0, &dwInputTypes);
if (dwInputTypes)
{
FillTypeArray(m_ListInputMajor2, m_ListInputMinor2, arrayInput, 2, &dwInputTypes);
}
FillTypeArray(m_ListOutputMajor, m_ListOutputMinor, arrayOutput, 0, &dwOutputTypes);
if (dwOutputTypes)
{
FillTypeArray(m_ListOutputMajor2, m_ListOutputMinor2, arrayOutput, 2, &dwOutputTypes);
}
hr = m_pMapper->EnumMatchingFilters(
ppEnum,
0, // Reserved
bExactMatch, // Use exact match?
(DWORD)dwMerit, // Minimum merit
bAtLeastOneInputPin,
dwInputTypes, // Number of major type/subtype pairs for input
arrayInput, // Array of major type/subtype pairs for input
NULL, // Input medium
pInCat, // Input pin category
bIsRenderer, // Must be a renderer?
bAtLeastOneOutputPin,
dwOutputTypes, // Number of major type/subtype pairs for output
arrayOutput, // Array of major type/subtype pairs for output
NULL, // Output medium
pOutCat); // Output pin category
return hr;
}
///////////////////////////////////////////////////////////////////////
// Name: AddFilterToList
// Desc: Displays information about a filter in the "Filters" list box.
//
// szFilterName: Display name of the filter.
// szGUID: CLSID of the filter, in string format
// dwMerit: Filter merit
///////////////////////////////////////////////////////////////////////
void MainDialog::AddFilterToList(const WCHAR *szFilterName, const WCHAR *szGUID, DWORD dwMerit)
{
const DWORD STRING_LEN = 300;
WCHAR szInfo[STRING_LEN], szFilename[STRING_LEN];
HRESULT hr;
// First add the friendly name of the filter
hr = StringCchPrintf(szInfo, STRING_LEN, L"%s\t\0", szFilterName);
// Add the filter's merit value
if (SUCCEEDED(hr))
{
AddMeritToString(szInfo, STRING_LEN, dwMerit);
}
// Get the filter's server (DLL) name from the registry
if (SUCCEEDED(hr))
{
hr = GetFilenameByCLSIDString(szGUID, szFilename, STRING_LEN);
}
// Add the filter's server name
if (SUCCEEDED(hr))
{
hr = StringCchCat(szInfo, STRING_LEN, L"\t\0");
}
if (SUCCEEDED(hr))
{
hr = StringCchCat(szInfo, STRING_LEN, szFilename);
}
// Add the final string to the listbox
if (SUCCEEDED(hr))
{
m_ListFilters.AddString(szInfo);
}
}
// Read merit and version information
HRESULT MainDialog::GetMerit(IPropertyBag *pPropBag, DWORD *pdwMerit)
{
HRESULT hr;
IAMFilterData *pData = NULL;
VARIANT varFilData={0};
varFilData.vt = VT_UI1 | VT_ARRAY;
varFilData.parray = 0; // docs say to zero this
BYTE *pbFilterData = 0; // 0 if not read
DWORD dwcbFilterDAta = 0; // 0 if not read
// Read compressed filter data from the property bag with a variant
hr = pPropBag->Read(L"FilterData", &varFilData, 0);
if (SUCCEEDED(hr))
{
assert(varFilData.vt == (VT_UI1 | VT_ARRAY));
dwcbFilterDAta = varFilData.parray->rgsabound[0].cElements;
// Access the filter data
hr = SafeArrayAccessData(varFilData.parray, (void **)&pbFilterData);
}
// Get the IAMFilterData interface for parsing the filter data
if (SUCCEEDED(hr))
{
hr = m_pMapper->QueryInterface(__uuidof(IAMFilterData), (void **)&pData);
}
if (SUCCEEDED(hr))
{
BYTE *pb=0;
// Use a helper method to parse the binary filter data. Pass in
// the pointer to the filter data, its size, and a buffer to fill with
// the resulting data. The "pb" buffer is allocated with CoTaskMemAlloc,
// so it must be correspondingly freed by the caller.
hr = pData->ParseFilterData(pbFilterData, dwcbFilterDAta, &pb);
if(SUCCEEDED(hr))
{
REGFILTER2 *pFil = ((REGFILTER2 **)pb)[0];
// Assign the merit value from the REGFILTER2 structure
if (pFil)
{
*pdwMerit = pFil->dwMerit;
// Free the memory allocated by ParseFilterData
CoTaskMemFree(pFil);
}
}
}
if (pbFilterData)
{
SafeArrayUnaccessData(varFilData.parray);
VariantClear(&varFilData);
}
// Release the IAMFilterData interface
SAFE_RELEASE(pData);
return hr;
}
////// Helper functions
void FillMajorTypes(ListBox& listbox)
{
listbox.ClearItems();
// Fill the specified list box with major type name/GUID
for (int i=0; i < NUM_MAJOR_TYPES; i++)
{
listbox.AddItem(majortypes[i].szName, (void *) majortypes[i].pGUID);
}
listbox.Select(0);
}
void FillSubType(ListBox& listboxMajor, ListBox& listboxMinor)
{
const GUIDINFO *pSubtype;
UINT nSelection = 0;
listboxMajor.GetCurrentSelection(&nSelection);
int nMajorType;
// First clear the subtype list
listboxMinor.ClearItems();
// If the "don't care" item was selected, clear and exit
if (nSelection == 0)
{
listboxMinor.AddString(L"<No subtypes>\0");
listboxMinor.Select(0);
return;
}
else
{
nMajorType = nSelection - 1;
}
// Determine how to fill the minor type list, based on the
// currently selected major type.
pSubtype = pSubTypes[nMajorType];
// If there's no associated subtype, just add a default
if (!pSubtype)
{
listboxMinor.AddString(L"<No subtypes>\0");
listboxMinor.Select(0);
return;
}
else
{
// Set a default item for "don't care"
listboxMinor.AddString(L"<Don't care>\0");
int i=0;
// Fill the subtype list box. Enter N item data to the N+1 list slot.
while (pSubtype[i].pGUID != NULL)
{
listboxMinor.AddItem(pSubtype[i].szName, (void *) pSubtype[i].pGUID);
i++;
}
listboxMinor.Select(0);
}
}
void EnableSecondTypePair(
ListBox& ListMajor,
ListBox& ListMajor2,
ListBox& ListMinor2
)
{
// If there is no selection in the first major type listbox,
// clear and disable the second major/minor type listboxes.
UINT selection = 0;
ListMajor.GetCurrentSelection(&selection);
if (selection == 0)
{
ListMajor2.Select(0);
FillSubType(ListMajor2, ListMinor2);
ListMajor2.Enable(FALSE);
ListMinor2.Enable(FALSE);
}
else
{
ListMajor2.Enable(TRUE);
ListMinor2.Enable(TRUE);
}
}
void FillTypeArray(
ListBox& ListMajor,
ListBox& ListMinor,
GUID *atypes,
int nIndex,
DWORD *pdwPairs
)
{
UINT nMajorSel = 0, nMinorSel = 0;
BOOL result = ListMajor.GetCurrentSelection(&nMajorSel);
// If no selection ("don't care"), just exit without modifying the array
if (!result || nMajorSel == 0)
{
return;
}
// Get GUID for major type
const GUID *p1 = (const GUID *)ListMajor.GetItem(nMajorSel);
// Since the FilterMapper interface requires GUIDs (instead of GUID *),
// copy the specified GUID data into its array slot.
if (p1)
{
memcpy(&atypes[nIndex], p1, sizeof(GUID));
}
else
{
memset(&atypes[nIndex], 0, sizeof(GUID));
}
// Increment number of type/subtype pairs
(*pdwPairs)++;
result = ListMinor.GetCurrentSelection(&nMinorSel);
// If no selection ("don't care"), or uninitialized (returning -1),
// just exit without modifying the array
if (!result || nMinorSel == 0)
{
return;
}
// Get GUID for subtype
const GUID *p2 = (const GUID *)ListMinor.GetItem(nMinorSel);
if (p2)
{
memcpy(&atypes[nIndex+1], p2, sizeof(GUID));
}
else
{
memset(&atypes[nIndex+1], 0, sizeof(GUID));
}
}
void AddMeritToString(WCHAR *szInfo, size_t len, DWORD dwMerit)
{
WCHAR szMerit[32];
HRESULT hr;
switch (dwMerit)
{
case MERIT_NORMAL:
hr = StringCchCopy(szMerit, NUMELMS(szMerit), L"MERIT_NORMAL\0");
break; // Assume normal
case MERIT_PREFERRED:
hr = StringCchCopy(szMerit, NUMELMS(szMerit), L"MERIT_PREFERRED\0");
break;
case MERIT_UNLIKELY:
hr = StringCchCopy(szMerit, NUMELMS(szMerit), L"MERIT_UNLIKELY\0");
break;
case MERIT_DO_NOT_USE:
hr = StringCchCopy(szMerit, NUMELMS(szMerit), L"MERIT_DO_NOT_USE\0");
break;
case MERIT_SW_COMPRESSOR:
hr = StringCchCopy(szMerit, NUMELMS(szMerit), L"MERIT_SW_COMPRESSOR\0");
break;
case MERIT_HW_COMPRESSOR:
hr = StringCchCopy(szMerit, NUMELMS(szMerit), L"MERIT_HW_COMPRESSOR\0");
break;
default:
hr = StringCchPrintf(szMerit, NUMELMS(szMerit), L"0x%08x\0", dwMerit);
break;
}
// Add new merit information to string
hr = StringCchCat(szInfo, len , szMerit);
}