Files
Client/Library/dxx8/samples/Multimedia/DirectShow/Players/StillView/stillviewDlg.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

1100 lines
29 KiB
C++

//------------------------------------------------------------------------------
// File: StillViewDlg.cpp
//
// Desc: DirectShow sample code - implementation of CStillViewDlg class.
//
// Copyright (c) 1998-2001 Microsoft Corporation. All rights reserved.
//------------------------------------------------------------------------------
#include "stdafx.h"
#include <atlbase.h>
#include "StillView.h"
#include "StillViewDlg.h"
#include "mediatypes.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()
/////////////////////////////////////////////////////////////////////////////
// CStillViewDlg dialog
CStillViewDlg::CStillViewDlg(CWnd* pParent /*=NULL*/)
: CDialog(CStillViewDlg::IDD, pParent), m_pGB(0), m_pMC(0), m_pBV(0), m_pVW(0), m_pME(0)
{
//{{AFX_DATA_INIT(CStillViewDlg)
//}}AFX_DATA_INIT
// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CStillViewDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CStillViewDlg)
DDX_Control(pDX, IDC_STATIC_FILETIME, m_StrFileTime);
DDX_Control(pDX, IDC_STATIC_IMAGESIZE, m_StrImageSize);
DDX_Control(pDX, IDC_EDIT_MEDIADIR, m_EditMediaDir);
DDX_Control(pDX, IDC_SPIN_FILES, m_SpinFiles);
DDX_Control(pDX, IDC_BUTTON_PROPPAGE, m_ButtonProperties);
DDX_Control(pDX, IDC_STATUS_DIRECTORY, m_StrMediaPath);
DDX_Control(pDX, IDC_STATIC_FILEDATE, m_StrFileDate);
DDX_Control(pDX, IDC_STATIC_FILESIZE, m_StrFileSize);
DDX_Control(pDX, IDC_LIST_PINS_OUTPUT, m_ListPinsOutput);
DDX_Control(pDX, IDC_LIST_PINS_INPUT, m_ListPinsInput);
DDX_Control(pDX, IDC_STATIC_FILELIST, m_StrFileList);
DDX_Control(pDX, IDC_MOVIE_SCREEN, m_Screen);
DDX_Control(pDX, IDC_LIST_FILTERS, m_ListFilters);
DDX_Control(pDX, IDC_LIST_FILES, m_ListFiles);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CStillViewDlg, CDialog)
//{{AFX_MSG_MAP(CStillViewDlg)
ON_WM_ERASEBKGND()
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_WM_CLOSE()
ON_WM_DESTROY()
ON_LBN_SELCHANGE(IDC_LIST_FILES, OnSelectFile)
ON_LBN_SELCHANGE(IDC_LIST_FILTERS, OnSelchangeListFilters)
ON_LBN_DBLCLK(IDC_LIST_FILTERS, OnDblclkListFilters)
ON_BN_CLICKED(IDC_BUTTON_PROPPAGE, OnButtonProppage)
ON_NOTIFY(UDN_DELTAPOS, IDC_SPIN_FILES, OnDeltaposSpinFiles)
ON_BN_CLICKED(IDC_BUTTON_SET_MEDIADIR, OnButtonSetMediadir)
ON_BN_CLICKED(IDC_BUTTON_GRAPHEDIT, OnButtonGraphedit)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CStillViewDlg message handlers
void CStillViewDlg::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 CStillViewDlg::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 CStillViewDlg::OnQueryDragIcon()
{
return (HCURSOR) m_hIcon;
}
/////////////////////////////////////////////////////////////////////////////
// CStillViewDlg DirectShow code and message handlers
BOOL CStillViewDlg::OnInitDialog()
{
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
// Initialize COM
CoInitialize(NULL);
// Initialize DirectShow and query for needed interfaces
HRESULT hr = InitDirectShow();
if(FAILED(hr))
{
RetailOutput(TEXT("Failed to initialize DirectShow! hr=0x%x\r\n"), hr);
return FALSE;
}
// Since we're embedding video in a child window of a dialog,
// we must set the WS_CLIPCHILDREN style to prevent the bounding
// rectangle from drawing over our video frames.
m_Screen.ModifyStyle(0, WS_CLIPCHILDREN);
// Propagate the files list and select the first item
InitMediaDirectory();
return TRUE; // return TRUE unless you set the focus to a control
}
void CStillViewDlg::InitMediaDirectory(void)
{
// Fill the media file list, starting with the directory passed
// on the command line. If no directory is passed, then read the
// default media path for the DirectX SDK.
TCHAR szDir[MAX_PATH];
LONG lResult=0;
if (theApp.m_lpCmdLine[0] == L'\0')
{
lResult = GetDXMediaPath(szDir);
// If the DirectX SDK is not installed, use the Windows
// directory instead.
if (lResult != 0)
{
GetWindowsDirectory(szDir, MAX_PATH);
_tcscat(szDir, _T("\\") );
}
}
else
_tcscpy(szDir, theApp.m_lpCmdLine);
TCHAR szPathMsg[MAX_PATH];
wsprintf(szPathMsg, TEXT("Media directory: %s\0"), szDir);
m_StrMediaPath.SetWindowText(szPathMsg);
// Save current directory name
wsprintf(m_szCurrentDir, TEXT("%s\0"), szDir);
m_EditMediaDir.SetLimitText(MAX_PATH);
m_EditMediaDir.SetWindowText(szDir);
FillFileList(szDir);
}
LONG CStillViewDlg::GetDXMediaPath(TCHAR *szPath)
{
HKEY hKey;
DWORD dwType, dwSize = MAX_PATH;
// Open the appropriate registry key
LONG lResult = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
_T("Software\\Microsoft\\DirectX SDK"),
0, KEY_READ, &hKey );
if( ERROR_SUCCESS != lResult )
return -1;
lResult = RegQueryValueEx( hKey, _T("DX81SDK Samples Path"), NULL,
&dwType, (BYTE*)szPath, &dwSize );
RegCloseKey( hKey );
if( ERROR_SUCCESS != lResult )
return -1;
_tcscat( szPath, _T("\\Media\\") );
return 0;
}
void CStillViewDlg::OnButtonSetMediadir()
{
TCHAR szEditPath[MAX_PATH];
DWORD dwAttr;
// Read the string in the media directory edit box.
m_EditMediaDir.GetWindowText(szEditPath, MAX_PATH);
// Is this a valid directory name?
dwAttr = GetFileAttributes(szEditPath);
if ((dwAttr == (DWORD) -1) || (! (dwAttr & FILE_ATTRIBUTE_DIRECTORY)))
{
MessageBox(TEXT("Please enter a valid directory name."), TEXT("Media error"));
return;
}
// User has specified a valid media directory.
// Update the current path string.
TCHAR szPathMsg[MAX_PATH];
wsprintf(szPathMsg, TEXT("Media directory: %s\0"), szEditPath);
m_StrMediaPath.SetWindowText(szPathMsg);
// Save current directory name. Append the trailing '\' to match
// the string created by GetDXSDKMediaPath() (if not present)
int nLength = _tcslen(szEditPath);
if (szEditPath[nLength - 1] != TEXT('\\'))
wsprintf(m_szCurrentDir, TEXT("%s\\\0"), szEditPath);
// Propagate the files list and select the first item
FillFileList(szEditPath);
}
void CStillViewDlg::FillFileList(LPTSTR pszRootDir)
{
UINT attr = 0;
// Clear current file list
m_ListFiles.ResetContent();
// Clear filter/pin/event information listboxes
m_ListFilters.ResetContent();
m_ListPinsInput.ResetContent();
m_ListPinsOutput.ResetContent();
::SetCurrentDirectory(pszRootDir);
// Add all of our known supported media types to the file list.
// Add files of each type in order.
for (int i=0; i < NUM_MEDIA_TYPES; i++)
{
m_ListFiles.Dir(attr, TypeInfo[i].pszType);
}
// Update list box title with number of items added
int nItems = m_ListFiles.GetCount();
TCHAR szTitle[64];
wsprintf(szTitle, TEXT("Media files (%d found)"), nItems);
m_StrFileList.SetWindowText(szTitle);
// If there are no messages, inform the user
if (nItems == 0)
MessageBox(TEXT("This is a valid directory, but it does not contain any ")
TEXT("media files expected by this application (BMP, GIF, JPG, TGA)."),
TEXT("No still image files!"));
// Automatically select the first file in the list once
// the dialog is displayed.
PostMessage(WM_FIRSTFILE, 0, 0L);
m_nCurrentFileSelection = -1; // No selection yet
}
void CStillViewDlg::OnClose()
{
// Release DirectShow interfaces
FreeDirectShow();
// Release COM
CoUninitialize();
CDialog::OnClose();
}
void CStillViewDlg::OnDestroy()
{
FreeDirectShow();
CDialog::OnDestroy();
}
void CStillViewDlg::OnSelectFile()
{
HRESULT hr;
TCHAR szFilename[MAX_PATH];
// If this is the currently selected file, do nothing
int nItem = m_ListFiles.GetCurSel();
if (nItem == m_nCurrentFileSelection)
return;
// Remember the current selection to speed double-click processing
m_nCurrentFileSelection = nItem;
// Read file name from list box
m_ListFiles.GetText(nItem, szFilename);
// First release any existing interfaces
ResetDirectShow();
// Clear filter/pin/event information listboxes
m_ListFilters.ResetContent();
m_ListPinsInput.ResetContent();
m_ListPinsOutput.ResetContent();
// Load the selected media file
hr = PrepareMedia(szFilename);
if (FAILED(hr))
{
MessageBeep(0);
return;
}
// Display useful information about this file
DisplayFileInfo(szFilename);
DisplayImageInfo();
// Enumerate and display filters in graph
hr = EnumFilters();
// Select the first filter in the list to display pin info
m_ListFilters.SetCurSel(0);
OnSelchangeListFilters();
}
HRESULT CStillViewDlg::PrepareMedia(LPTSTR lpszMovie)
{
USES_CONVERSION;
HRESULT hr = S_OK;
// Allow DirectShow to create the FilterGraph for this media file
hr = m_pGB->RenderFile(T2W(lpszMovie), NULL);
if (FAILED(hr)) {
RetailOutput(TEXT("*** Failed(%08lx) in RenderFile(%s)!\r\n"),
hr, lpszMovie);
return hr;
}
// Set the message drain of the video window to point to our main
// application window.
hr = m_pVW->put_MessageDrain((OAHWND) m_hWnd);
// Have the graph signal event via window callbacks
hr = m_pME->SetNotifyWindow((OAHWND)m_hWnd, WM_GRAPHNOTIFY, 0);
// Place video window within the bounding rectangle
CenterVideo();
// Finish configuring video window
hr = m_pVW->put_WindowStyle(WS_CHILD);
hr = m_pVW->put_Owner((OAHWND) m_Screen.GetSafeHwnd());
hr = m_pVW->SetWindowForeground(-1);
// Display the media file's first frame, which is the only frame
// for a still image.
hr = m_pMC->Pause();
return hr;
}
HRESULT CStillViewDlg::InitDirectShow(void)
{
HRESULT hr = S_OK;
// Zero interfaces (sanity check)
m_pVW = NULL;
m_pBV = NULL;
JIF(CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC, IID_IGraphBuilder, (void **)&m_pGB));
JIF(m_pGB->QueryInterface(IID_IMediaControl, (void **)&m_pMC));
JIF(m_pGB->QueryInterface(IID_IBasicVideo, (void **)&m_pBV));
JIF(m_pGB->QueryInterface(IID_IVideoWindow, (void **)&m_pVW));
JIF(m_pGB->QueryInterface(IID_IMediaEventEx, (void **)&m_pME));
return S_OK;
CLEANUP:
FreeDirectShow();
return(hr);
}
HRESULT CStillViewDlg::FreeDirectShow(void)
{
HRESULT hr=S_OK;
// Hide video window and remove owner. This is not necessary here,
// since we are about to destroy the filter graph, but it is included
// for demonstration purposes. Remember to hide the video window and
// clear its owner when destroying a window that plays video.
if(m_pVW)
{
hr = m_pVW->put_Visible(OAFALSE);
hr = m_pVW->put_Owner(NULL);
}
SAFE_RELEASE(m_pMC);
SAFE_RELEASE(m_pVW);
SAFE_RELEASE(m_pBV);
SAFE_RELEASE(m_pME);
SAFE_RELEASE(m_pGB);
return hr;
}
void CStillViewDlg::ResetDirectShow(void)
{
// Destroy the current filter graph its filters.
FreeDirectShow();
// Reinitialize graph builder and query for interfaces
InitDirectShow();
}
void CStillViewDlg::CenterVideo(void)
{
LONG width, height;
HRESULT hr;
if (!m_pVW)
return;
// Read coordinates of video container window
RECT rc;
m_Screen.GetClientRect(&rc);
width = rc.right - rc.left;
height = rc.bottom - rc.top;
// Ignore the video's original size and stretch to fit bounding rectangle
hr = m_pVW->SetWindowPosition(rc.left, rc.top, width, height);
if (FAILED(hr))
{
RetailOutput(TEXT("Failed to set window position! hr=0x%x\r\n"), hr);
return;
}
}
LRESULT CStillViewDlg::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
// Field notifications from the DirectShow filter graph manager
// and those posted by the application
switch (message)
{
case WM_GRAPHNOTIFY:
HandleGraphEvent();
break;
case WM_PLAYFILE:
PlaySelectedFile();
break;
case WM_NEXTFILE:
PlayNextFile();
break;
case WM_PREVIOUSFILE:
PlayPreviousFile();
break;
case WM_FIRSTFILE:
// Select the first item in the list
m_ListFiles.SetCurSel(0);
OnSelectFile();
break;
}
// Pass along this message to the video window, which exists as a child
// of the m_Screen window. This method should be used by windows that
// make a renderer window a child window. It forwards significant messages
// to the child window that the child window would not otherwise receive.
if (m_pVW)
{
m_pVW->NotifyOwnerMessage((LONG_PTR) m_hWnd, message, wParam, lParam);
}
return CDialog::WindowProc(message, wParam, lParam);
}
HRESULT CStillViewDlg::HandleGraphEvent(void)
{
LONG evCode, evParam1, evParam2;
HRESULT hr=S_OK;
while(SUCCEEDED(m_pME->GetEvent(&evCode, (LONG_PTR *) &evParam1,
(LONG_PTR *) &evParam2, 0)))
{
// Spin through the events
hr = m_pME->FreeEventParams(evCode, evParam1, evParam2);
}
return hr;
}
void CStillViewDlg::PlaySelectedFile()
{
OnSelectFile();
}
void CStillViewDlg::OnDeltaposSpinFiles(NMHDR* pNMHDR, LRESULT* pResult)
{
NM_UPDOWN* pNMUpDown = (NM_UPDOWN*)pNMHDR;
if (pNMUpDown->iDelta > 0)
PostMessage(WM_NEXTFILE, 0, 0L);
else
PostMessage(WM_PREVIOUSFILE, 0, 0L);
*pResult = 0;
}
void CStillViewDlg::PlayNextFile(void)
{
int nItems = m_ListFiles.GetCount();
// Return if the list is empty
if (!nItems)
return;
int nCurSel = m_ListFiles.GetCurSel();
int nNewSel = (nCurSel + 1) % nItems;
// Select the next item in the list, wrapping to top if needed
m_ListFiles.SetCurSel(nNewSel);
OnSelectFile();
}
void CStillViewDlg::PlayPreviousFile(void)
{
int nItems = m_ListFiles.GetCount();
// Return if the list is empty
if (!nItems)
return;
int nCurSel = m_ListFiles.GetCurSel();
int nNewSel = nCurSel - 1;
// If moved off top of list, select last item in list
if (nNewSel < 0)
nNewSel = nItems - 1;
// Select the next item in the list, wrapping to top if needed
m_ListFiles.SetCurSel(nNewSel);
OnSelectFile();
}
HRESULT CStillViewDlg::EnumFilters (void)
{
USES_CONVERSION;
HRESULT hr;
IEnumFilters *pEnum = NULL;
IBaseFilter *pFilter = NULL;
ULONG cFetched;
// Clear filters list box
m_ListFilters.ResetContent();
// Get filter enumerator
hr = m_pGB->EnumFilters(&pEnum);
if (FAILED(hr))
{
m_ListFilters.AddString(TEXT("<ERROR>"));
return hr;
}
// Enumerate all filters in the graph
while(pEnum->Next(1, &pFilter, &cFetched) == S_OK)
{
FILTER_INFO FilterInfo;
TCHAR szName[256];
hr = pFilter->QueryFilterInfo(&FilterInfo);
if (FAILED(hr))
{
m_ListFilters.AddString(TEXT("<ERROR>"));
}
else
{
// Add the filter name to the filters listbox
lstrcpy(szName, W2T(FilterInfo.achName));
m_ListFilters.AddString(szName);
FilterInfo.pGraph->Release();
}
pFilter->Release();
}
pEnum->Release();
return hr;
}
//
// The GraphBuilder interface provides a FindFilterByName() method,
// which provides similar functionality to the method below.
// This local method is provided for educational purposes.
//
IBaseFilter *CStillViewDlg::FindFilterFromName(LPTSTR szNameToFind)
{
USES_CONVERSION;
HRESULT hr;
IEnumFilters *pEnum = NULL;
IBaseFilter *pFilter = NULL;
ULONG cFetched;
BOOL bFound = FALSE;
// Get filter enumerator
hr = m_pGB->EnumFilters(&pEnum);
if (FAILED(hr))
return NULL;
// Enumerate all filters in the graph
while((pEnum->Next(1, &pFilter, &cFetched) == S_OK) && (!bFound))
{
FILTER_INFO FilterInfo;
TCHAR szName[256];
hr = pFilter->QueryFilterInfo(&FilterInfo);
if (FAILED(hr))
{
pFilter->Release();
pEnum->Release();
return NULL;
}
// Compare this filter's name with the one we want
lstrcpy(szName, W2T(FilterInfo.achName));
if (! lstrcmp(szName, szNameToFind))
{
bFound = TRUE;
}
FilterInfo.pGraph->Release();
// If we found the right filter, don't release its interface.
// The caller will use it and release it later.
if (!bFound)
pFilter->Release();
else
break;
}
pEnum->Release();
return (bFound ? pFilter : NULL);
}
HRESULT CStillViewDlg::EnumPins(IBaseFilter *pFilter, PIN_DIRECTION PinDir,
CListBox& Listbox)
{
HRESULT hr;
IEnumPins *pEnum = NULL;
IPin *pPin = NULL;
// Clear the specified listbox (input or output)
Listbox.ResetContent();
// Get pin enumerator
hr = pFilter->EnumPins(&pEnum);
if (FAILED(hr))
{
Listbox.AddString(TEXT("<ERROR>"));
return hr;
}
// Enumerate all pins on this filter
while(pEnum->Next(1, &pPin, 0) == S_OK)
{
PIN_DIRECTION PinDirThis;
hr = pPin->QueryDirection(&PinDirThis);
if (FAILED(hr))
{
Listbox.AddString(TEXT("<ERROR>"));
pPin->Release();
continue;
}
// Does the pin's direction match the requested direction?
if (PinDir == PinDirThis)
{
PIN_INFO pininfo={0};
// Direction matches, so add pin name to listbox
hr = pPin->QueryPinInfo(&pininfo);
if (SUCCEEDED(hr))
{
CString str(pininfo.achName);
Listbox.AddString(str);
}
// The pininfo structure contains a reference to an IBaseFilter,
// so you must release its reference to prevent resource a leak.
pininfo.pFilter->Release();
}
pPin->Release();
}
pEnum->Release();
return hr;
}
void CStillViewDlg::OnSelchangeListFilters()
{
HRESULT hr;
IBaseFilter *pFilter = NULL;
TCHAR szNameToFind[128];
// Read the current filter name from the list box
int nCurSel = m_ListFilters.GetCurSel();
m_ListFilters.GetText(nCurSel, szNameToFind);
// Read the current list box name and find it in the graph
pFilter = FindFilterFromName(szNameToFind);
if (!pFilter)
return;
// Now that we have filter information, enumerate pins by direction
// and add their names to the appropriate listboxes
hr = EnumPins(pFilter, PINDIR_INPUT, m_ListPinsInput);
hr = EnumPins(pFilter, PINDIR_OUTPUT, m_ListPinsOutput);
// Find out if this filter supports a property page
if (SupportsPropertyPage(pFilter))
m_ButtonProperties.EnableWindow(TRUE);
else
m_ButtonProperties.EnableWindow(FALSE);
// Must release the filter interface returned from FindFilterByName()
pFilter->Release();
}
BOOL CStillViewDlg::DisplayImageInfo(void)
{
HRESULT hr;
long lWidth, lHeight;
if (!m_pBV)
return FALSE;
hr = m_pBV->GetVideoSize(&lWidth, &lHeight);
if (SUCCEEDED(hr))
{
TCHAR szSize[64];
wsprintf(szSize, TEXT("Image size: %d x %d\0"), lWidth, lHeight);
m_StrImageSize.SetWindowText(szSize);
}
return TRUE;
}
BOOL CStillViewDlg::DisplayFileInfo(LPTSTR szFile)
{
HANDLE hFile;
LONGLONG llSize=0;
DWORD dwSizeLow=0, dwSizeHigh=0;
TCHAR szScrap[64];
// Open the specified file to read size and date information
hFile = CreateFile(szFile,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,
(DWORD) 0, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
RetailOutput(TEXT("*** Failed(0x%x) to open file (to read size)!\r\n"),
GetLastError());
return FALSE;
}
dwSizeLow = GetFileSize(hFile, &dwSizeHigh);
if ((dwSizeLow == 0xFFFFFFFF) && (GetLastError() != NO_ERROR))
{
RetailOutput(TEXT("*** Error(0x%x) reading file size!\r\n"),
GetLastError());
CloseHandle(hFile);
return FALSE;
}
// Large files will also use the upper DWORD to report size.
// Add them together for the true size if necessary.
if (dwSizeHigh)
llSize = (dwSizeHigh << 16) + dwSizeLow;
else
llSize = dwSizeLow;
// Read date information
BY_HANDLE_FILE_INFORMATION fi;
if (GetFileInformationByHandle(hFile, &fi))
{
CTime time(fi.ftLastWriteTime);
wsprintf(szScrap, TEXT("Date: %02d/%02d/%d\0"),
time.GetMonth(), time.GetDay(), time.GetYear());
m_StrFileDate.SetWindowText(szScrap);
// Set time. Note that 12am-12:59am will show as "00" instead of 12.
wsprintf(szScrap, TEXT("Time: %02d:%02d %s\0"),
(time.GetHour() % 12), time.GetMinute(),
((time.GetHour() > 12) ? TEXT("pm\0") : TEXT("am\0")));
m_StrFileTime.SetWindowText(szScrap);
}
CloseHandle(hFile);
// Update size/date windows
wsprintf(szScrap, TEXT("Size: %d bytes\0"), dwSizeLow);
m_StrFileSize.SetWindowText(szScrap);
return TRUE;
}
BOOL CStillViewDlg::SupportsPropertyPage(IBaseFilter *pFilter)
{
HRESULT hr;
TCHAR szNameToFind[128];
ISpecifyPropertyPages *pSpecify;
// Read the current filter name from the list box
int nCurSel = m_ListFilters.GetCurSel();
m_ListFilters.GetText(nCurSel, szNameToFind);
// Discover if this filter contains a property page
hr = pFilter->QueryInterface(IID_ISpecifyPropertyPages, (void **)&pSpecify);
if (SUCCEEDED(hr))
{
pSpecify->Release();
return TRUE;
}
else
return FALSE;
}
void CStillViewDlg::OnButtonProppage()
{
HRESULT hr;
IBaseFilter *pFilter = NULL;
TCHAR szNameToFind[128];
ISpecifyPropertyPages *pSpecify;
// Read the current filter name from the list box
int nCurSel = m_ListFilters.GetCurSel();
m_ListFilters.GetText(nCurSel, szNameToFind);
// Read the current list box name and find it in the graph
pFilter = FindFilterFromName(szNameToFind);
if (!pFilter)
return;
// Discover if this filter contains a property page
hr = pFilter->QueryInterface(IID_ISpecifyPropertyPages, (void **)&pSpecify);
if (SUCCEEDED(hr))
{
do
{
FILTER_INFO FilterInfo;
hr = pFilter->QueryFilterInfo(&FilterInfo);
if (FAILED(hr))
break;
CAUUID caGUID;
hr = pSpecify->GetPages(&caGUID);
if (FAILED(hr))
break;
pSpecify->Release();
// Display the filter's property page
OleCreatePropertyFrame(
m_hWnd, // Parent window
0, // x (Reserved)
0, // y (Reserved)
FilterInfo.achName, // Caption for the dialog box
1, // Number of filters
(IUnknown **)&pFilter, // Pointer to the filter
caGUID.cElems, // Number of property pages
caGUID.pElems, // Pointer to property page CLSIDs
0, // Locale identifier
0, // Reserved
NULL // Reserved
);
CoTaskMemFree(caGUID.pElems);
FilterInfo.pGraph->Release();
} while(0);
}
pFilter->Release();
}
void CStillViewDlg::OnDblclkListFilters()
{
OnButtonProppage();
}
void RetailOutput(TCHAR *tszErr, ...)
{
TCHAR tszErrOut[MAX_PATH + 256];
va_list valist;
va_start(valist,tszErr);
wvsprintf(tszErrOut, tszErr, valist);
OutputDebugString(tszErrOut);
va_end (valist);
}
LONG CStillViewDlg::GetGraphEditPath(TCHAR *szPath)
{
HKEY hKey;
DWORD dwType, dwSize = MAX_PATH;
// Open the appropriate registry key
LONG lResult = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
_T("Software\\Microsoft\\Shared Tools\\Graphedit"),
0, KEY_READ, &hKey );
if( ERROR_SUCCESS != lResult )
return -1;
// Read the full path (including .exe name) for the GraphEdit tool
lResult = RegQueryValueEx( hKey, _T("Path"), NULL,
&dwType, (BYTE*)szPath, &dwSize );
RegCloseKey( hKey );
if( ERROR_SUCCESS != lResult )
return -1;
return 0;
}
void CStillViewDlg::OnButtonGraphedit()
{
TCHAR szFilename[128], szFile[MAX_PATH];
// Read file name from list box
int nItem = m_ListFiles.GetCurSel();
m_ListFiles.GetText(nItem, szFilename);
// Build the full file name with path. The path will already have
// a '\' appended to the end.
wsprintf(szFile, TEXT("%s%s\0"), m_szCurrentDir, szFilename);
// Launch GraphEdit for the selected file
//
// First look for a registry key containing its full path
TCHAR szPath[MAX_PATH];
LONG lResult = GetGraphEditPath(szPath);
// If the DirectX SDK is not installed, just look for GraphEdit
// anywhere in the system path.
if (lResult != 0)
{
wsprintf(szPath, TEXT("%s\0"), TEXT("graphedt\0"));
}
// Lauch GraphEdit using either the full tool path or just its name
HINSTANCE rc = ShellExecute(m_hWnd, TEXT("open\0"), szPath,
szFile, NULL, SW_SHOWNORMAL);
if (rc < (HINSTANCE) 32)
{
// Failed to start the app
if ((rc == (HINSTANCE) ERROR_FILE_NOT_FOUND) ||
(rc == (HINSTANCE) ERROR_PATH_NOT_FOUND))
{
MessageBox(TEXT("Couldn't find the GraphEdit application.\r\n\r\n")
TEXT("Please copy graphedt.exe to a directory on your path."),
TEXT("Can't find GraphEdit"));
}
}
}
BOOL CStillViewDlg::OnEraseBkgnd(CDC *pDC)
{
// Intercept background erasing for the movie window, since the
// video renderer will keep the screen painted. Without this code,
// your video window might get painted over with gray (the default
// background brush) when it is obscured by another window and redrawn.
CRect rc;
// Get the bounding rectangle for the movie screen
m_Screen.GetWindowRect(&rc);
ScreenToClient(&rc);
// Exclude the clipping region occupied by our movie screen
pDC->ExcludeClipRect(&rc);
// Erase the remainder of the dialog as usual
return CDialog::OnEraseBkgnd(pDC);
}