Files
Client/Library/dxx8/samples/Multimedia/DirectShow/Misc/SysEnum/SysEnumDlg.cpp
LGram16 e067522598 Initial commit: ROW Client source code
Game client codebase including:
- CharacterActionControl: Character and creature management
- GlobalScript: Network, items, skills, quests, utilities
- RYLClient: Main client application with GUI and event handlers
- Engine: 3D rendering engine (RYLGL)
- MemoryManager: Custom memory allocation
- Library: Third-party dependencies (DirectX, boost, etc.)
- Tools: Development utilities

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-29 16:24:34 +09:00

655 lines
17 KiB
C++

//------------------------------------------------------------------------------
// File: SysEnumDlg.cpp
//
// Desc: DirectShow sample code - implementation of dialog for device
// enumeration.
//
// Copyright (c) 2000-2001 Microsoft Corporation. All rights reserved.
//------------------------------------------------------------------------------
#include "stdafx.h"
#include <atlbase.h>
#include "SysEnum.h"
#include "SysEnumDlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CAboutDlg dialog used for App About
class CAboutDlg : public CDialog
{
public:
CAboutDlg();
// Dialog Data
//{{AFX_DATA(CAboutDlg)
enum { IDD = IDD_ABOUTBOX };
//}}AFX_DATA
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CAboutDlg)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
//}}AFX_VIRTUAL
// Implementation
protected:
//{{AFX_MSG(CAboutDlg)
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
//{{AFX_DATA_INIT(CAboutDlg)
//}}AFX_DATA_INIT
}
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CAboutDlg)
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
//{{AFX_MSG_MAP(CAboutDlg)
// No message handlers
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CSysEnumDlg dialog
CSysEnumDlg::CSysEnumDlg(CWnd* pParent /*=NULL*/)
: CDialog(CSysEnumDlg::IDD, pParent)
{
//{{AFX_DATA_INIT(CSysEnumDlg)
m_bShowAllCategories = FALSE;
//}}AFX_DATA_INIT
// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CSysEnumDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CSysEnumDlg)
DDX_Control(pDX, IDC_STATIC_FILENAME, m_StrFilename);
DDX_Control(pDX, IDC_STATIC_FILTERS, m_StrFilters);
DDX_Control(pDX, IDC_STATIC_CLASSES, m_StrClasses);
DDX_Control(pDX, IDC_LIST_FILTERS, m_FilterList);
DDX_Control(pDX, IDC_LIST_DEVICES, m_DeviceList);
DDX_Check(pDX, IDC_CHECK_SHOWALL, m_bShowAllCategories);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CSysEnumDlg, CDialog)
//{{AFX_MSG_MAP(CSysEnumDlg)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_LBN_SELCHANGE(IDC_LIST_DEVICES, OnSelchangeListDevices)
ON_WM_CLOSE()
ON_BN_CLICKED(IDC_CHECK_SHOWALL, OnCheckShowall)
ON_LBN_SELCHANGE(IDC_LIST_FILTERS, OnSelchangeListFilters)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CSysEnumDlg message handlers
void CSysEnumDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialog::OnSysCommand(nID, lParam);
}
}
// If you add a minimize button to your dialog, you will need the code below
// to draw the icon. For MFC applications using the document/view model,
// this is automatically done for you by the framework.
void CSysEnumDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // device context for painting
SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);
// Center icon in client rectangle
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// Draw the icon
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialog::OnPaint();
}
}
// The system calls this to obtain the cursor to display while the user drags
// the minimized window.
HCURSOR CSysEnumDlg::OnQueryDragIcon()
{
return (HCURSOR) m_hIcon;
}
BOOL CSysEnumDlg::OnInitDialog()
{
HRESULT hr;
CDialog::OnInitDialog();
// Add "About..." menu item to system menu.
// IDM_ABOUTBOX must be in the system command range.
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
CString strAboutMenu;
strAboutMenu.LoadString(IDS_ABOUTBOX);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
// Set the icon for this dialog. The framework does this automatically
// when the application's main window is not a dialog
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
////////////////////////////////////////////////////////////////////////
//
// DirectShow-specific initialization code
CoInitialize(NULL);
// Instantiate the system device enumerator
m_pSysDevEnum = NULL;
hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL,
CLSCTX_INPROC, IID_ICreateDevEnum,
(void **)&m_pSysDevEnum);
if FAILED(hr)
{
CoUninitialize();
return FALSE;
}
// By default, only enumerate subset of categories listed in docs
m_bShowAllCategories = FALSE;
FillCategoryList();
return TRUE; // return TRUE unless you set the focus to a control
}
void CSysEnumDlg::OnCheckShowall()
{
// Toggle category type and redraw the category list
m_bShowAllCategories ^= 1;
FillCategoryList();
SetNumFilters(0);
}
void CSysEnumDlg::FillCategoryList(void)
{
// Clear listboxes
ClearDeviceList();
ClearFilterList();
if (m_bShowAllCategories)
{
// Emulate the behavior of GraphEdit by enumerating all
// categories in the system
DisplayFullCategorySet();
}
else
{
// Fill the category list box with the categories to display,
// using the names stored in the CATEGORY_INFO array.
// SysEnumDlg.H for a category description.
for (int i=0; i < NUM_CATEGORIES; i++)
{
m_DeviceList.AddString(categories[i].szName);
}
// Update listbox title with number of classes
SetNumClasses(NUM_CATEGORIES);
}
}
void CSysEnumDlg::SetNumClasses(int nClasses)
{
TCHAR szClasses[64];
wsprintf(szClasses, TEXT("%s (%d found)\0"), STR_CLASSES, nClasses);
m_StrClasses.SetWindowText(szClasses);
}
void CSysEnumDlg::SetNumFilters(int nFilters)
{
TCHAR szFilters[64];
if (nFilters)
wsprintf(szFilters, TEXT("%s (%d found)\0"), STR_FILTERS, nFilters);
else
wsprintf(szFilters, TEXT("%s\0"), STR_FILTERS);
m_StrFilters.SetWindowText(szFilters);
}
void CSysEnumDlg::DisplayFullCategorySet(void)
{
USES_CONVERSION;
HRESULT hr;
IEnumMoniker *pEmCat = 0;
ICreateDevEnum *pCreateDevEnum = NULL;
int nClasses=0;
// Create an enumerator
hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER,
IID_ICreateDevEnum, (void**)&pCreateDevEnum);
ASSERT(SUCCEEDED(hr));
if (FAILED(hr))
return;
// Use the meta-category that contains a list of all categories.
// This emulates the behavior of GraphEdit.
hr = pCreateDevEnum->CreateClassEnumerator(
CLSID_ActiveMovieCategories, &pEmCat, 0);
ASSERT(SUCCEEDED(hr));
if(hr == S_OK)
{
IMoniker *pMCat;
ULONG cFetched;
// Enumerate over every category
while(hr = pEmCat->Next(1, &pMCat, &cFetched),
hr == S_OK)
{
IPropertyBag *pPropBag;
// Associate moniker with a file
hr = pMCat->BindToStorage(0, 0, IID_IPropertyBag, (void **)&pPropBag);
if(SUCCEEDED(hr))
{
VARIANT varCatClsid;
varCatClsid.vt = VT_BSTR;
// Read CLSID string from property bag
hr = pPropBag->Read(L"CLSID", &varCatClsid, 0);
if(SUCCEEDED(hr))
{
CLSID clsidCat;
if(CLSIDFromString(varCatClsid.bstrVal, &clsidCat) == S_OK)
{
// Use the guid if we can't get the name
WCHAR *wszCatName;
TCHAR szCatDesc[MAX_PATH];
VARIANT varCatName;
varCatName.vt = VT_BSTR;
// Read filter name
hr = pPropBag->Read(L"FriendlyName", &varCatName, 0);
if(SUCCEEDED(hr))
wszCatName = varCatName.bstrVal;
else
wszCatName = varCatClsid.bstrVal;
#ifndef UNICODE
WideCharToMultiByte(
CP_ACP, 0, wszCatName, -1,
szCatDesc, sizeof(szCatDesc), 0, 0);
#else
lstrcpy(szCatDesc, W2T(wszCatName));
#endif
if(SUCCEEDED(hr))
SysFreeString(varCatName.bstrVal);
// Add category name and CLSID to list box
AddFilterCategory(szCatDesc, &clsidCat);
nClasses++;
}
SysFreeString(varCatClsid.bstrVal);
}
pPropBag->Release();
}
else
{
break;
}
pMCat->Release();
} // for loop
pEmCat->Release();
}
pCreateDevEnum->Release();
// Update listbox title with number of classes
SetNumClasses(nClasses);
}
void CSysEnumDlg::AddFilterCategory(
const TCHAR *szCatDesc,
const GUID *pCatGuid)
{
// Allocate a new CLSID, whose pointer will be stored in
// the listbox. When the listbox is cleared, these will be deleted.
CLSID *pclsid = new CLSID;
if (pclsid)
*pclsid = *pCatGuid;
// Add the category name and a pointer to its CLSID to the list box
int nSuccess = m_DeviceList.AddString(szCatDesc);
int nIndexNew = m_DeviceList.FindStringExact(-1, szCatDesc);
nSuccess = m_DeviceList.SetItemDataPtr(nIndexNew, pclsid);
}
void CSysEnumDlg::AddFilter(
const TCHAR *szFilterName,
const GUID *pCatGuid)
{
// Allocate a new CLSID, whose pointer will be stored in
// the listbox. When the listbox is cleared, these will be deleted.
CLSID *pclsid = new CLSID;
if (pclsid)
*pclsid = *pCatGuid;
// Add the category name and a pointer to its CLSID to the list box
int nSuccess = m_FilterList.AddString(szFilterName);
int nIndexNew = m_FilterList.FindStringExact(-1, szFilterName);
nSuccess = m_FilterList.SetItemDataPtr(nIndexNew, pclsid);
}
void CSysEnumDlg::ClearDeviceList(void)
{
CLSID *pStoredId = NULL;
int nCount = m_DeviceList.GetCount();
// Delete any CLSID pointers that were stored in the listbox item data
for (int i=0; i < nCount; i++)
{
pStoredId = (CLSID *) m_DeviceList.GetItemDataPtr(i);
if (pStoredId != 0)
{
delete pStoredId;
pStoredId = NULL;
}
}
// Clean up
m_DeviceList.ResetContent();
SetNumClasses(0);
}
void CSysEnumDlg::ClearFilterList(void)
{
CLSID *pStoredId = NULL;
int nCount = m_FilterList.GetCount();
// Delete any CLSID pointers that were stored in the listbox item data
for (int i=0; i < nCount; i++)
{
pStoredId = (CLSID *) m_FilterList.GetItemDataPtr(i);
if (pStoredId != 0)
{
delete pStoredId;
pStoredId = NULL;
}
}
// Clean up
m_FilterList.ResetContent();
SetNumFilters(0);
m_StrFilename.SetWindowText(TEXT("<No filter selected>"));
}
void CSysEnumDlg::OnSelchangeListDevices()
{
HRESULT hr;
IEnumMoniker *pEnumCat = NULL;
// Get the currently selected category name
int nItem = m_DeviceList.GetCurSel();
const CLSID *clsid;
if (m_bShowAllCategories)
{
// Read the CLSID pointer from the list box's item data
clsid = (CLSID *) m_DeviceList.GetItemDataPtr(nItem);
}
else
{
// Read the CLSID pointer from our hard-coded array of
// documented filter categories
clsid = categories[nItem].pclsid;
}
// If the CLSID wasn't allocated earlier, then fail
if (!clsid)
{
MessageBeep(0);
return;
}
//
// WARNING!
//
// Some third-party filters throw an exception (int 3) during enumeration
// on Debug builds, often due to heap corruption in RtlFreeHeap().
// This is not an issue on Release builds.
//
// Enumerate all filters of the selected category
hr = m_pSysDevEnum->CreateClassEnumerator(*clsid, &pEnumCat, 0);
ASSERT(SUCCEEDED(hr));
if FAILED(hr)
return;
// Enumerate all filters using the category enumerator
hr = EnumFilters(pEnumCat);
SAFE_RELEASE(pEnumCat);
}
HRESULT CSysEnumDlg::EnumFilters(IEnumMoniker *pEnumCat)
{
HRESULT hr=S_OK;
IMoniker *pMoniker;
ULONG cFetched;
VARIANT varName={0};
int nFilters=0;
// Clear the current filter list
ClearFilterList();
// If there are no filters of a requested type, show default string
if (!pEnumCat)
{
m_FilterList.AddString(TEXT("<< No entries >>"));
SetNumFilters(nFilters);
return S_FALSE;
}
// Enumerate all items associated with the moniker
while(pEnumCat->Next(1, &pMoniker, &cFetched) == S_OK)
{
IPropertyBag *pPropBag;
ASSERT(pMoniker);
// Associate moniker with a file
hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag,
(void **)&pPropBag);
ASSERT(SUCCEEDED(hr));
ASSERT(pPropBag);
if (FAILED(hr))
continue;
// Read filter name from property bag
varName.vt = VT_BSTR;
hr = pPropBag->Read(L"FriendlyName", &varName, 0);
if (FAILED(hr))
continue;
// Get filter name (converting BSTR name to a CString)
CString str(varName.bstrVal);
SysFreeString(varName.bstrVal);
nFilters++;
// Read filter's CLSID from property bag. This CLSID string will be
// converted to a binary CLSID and passed to AddFilter(), which will
// add the filter's name to the listbox and its CLSID to the listbox
// item's DataPtr item. When the user clicks on a filter name in
// the listbox, we'll read the stored CLSID, convert it to a string,
// and use it to find the filter's filename in the registry.
VARIANT varFilterClsid;
varFilterClsid.vt = VT_BSTR;
// Read CLSID string from property bag
hr = pPropBag->Read(L"CLSID", &varFilterClsid, 0);
if(SUCCEEDED(hr))
{
CLSID clsidFilter;
// Add filter name and CLSID to listbox
if(CLSIDFromString(varFilterClsid.bstrVal, &clsidFilter) == S_OK)
{
AddFilter(str, &clsidFilter);
}
SysFreeString(varFilterClsid.bstrVal);
}
// Cleanup interfaces
SAFE_RELEASE(pPropBag);
SAFE_RELEASE(pMoniker);
}
// Update count of enumerated filters
SetNumFilters(nFilters);
return hr;
}
void CSysEnumDlg::OnSelchangeListFilters()
{
const CLSID *clsid;
// Get the currently selected category name
int nItem = m_FilterList.GetCurSel();
// Read the CLSID pointer from the list box's item data
clsid = (CLSID *) m_FilterList.GetItemDataPtr(nItem);
// Find the filter filename in the registry (by CLSID)
if (clsid != 0)
ShowFilenameByCLSID(*clsid);
}
void CSysEnumDlg::ShowFilenameByCLSID(REFCLSID clsid)
{
HRESULT hr;
LPOLESTR strCLSID;
// Convert binary CLSID to a readable version
hr = StringFromCLSID(clsid, &strCLSID);
if(SUCCEEDED(hr))
{
TCHAR szKey[512];
CString strQuery(strCLSID);
// Create key name for reading filename registry
wsprintf(szKey, TEXT("Software\\Classes\\CLSID\\%s\\InprocServer32\0"),
strQuery);
// Free memory associated with strCLSID (allocated in StringFromCLSID)
CoTaskMemFree(strCLSID);
HKEY hkeyFilter=0;
DWORD dwSize=MAX_PATH;
BYTE pbFilename[MAX_PATH];
int rc=0;
// Open the CLSID key that contains information about the filter
rc = RegOpenKey(HKEY_LOCAL_MACHINE, szKey, &hkeyFilter);
if (rc == ERROR_SUCCESS)
{
rc = RegQueryValueEx(hkeyFilter, NULL, // Read (Default) value
NULL, NULL, pbFilename, &dwSize);
if (rc == ERROR_SUCCESS)
{
TCHAR szFilename[MAX_PATH];
wsprintf(szFilename, TEXT("%s\0"), pbFilename);
m_StrFilename.SetWindowText(szFilename);
}
rc = RegCloseKey(hkeyFilter);
}
}
}
void CSysEnumDlg::OnClose()
{
// Free any stored CLSID pointers (in listbox item data ptr area)
ClearFilterList();
ClearDeviceList();
// Release system device enumerator and close COM
SAFE_RELEASE(m_pSysDevEnum);
CoUninitialize();
CDialog::OnClose();
}