////////////////////////////////////////////////////////////////////////// // // winmain.cpp : Application entry-point // // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A // PARTICULAR PURPOSE. // // Copyright (c) Microsoft Corporation. All rights reserved. // ////////////////////////////////////////////////////////////////////////// #include "MFCaptureD3D.h" #include "resource.h" // Include the v6 common controls in the manifest #pragma comment(linker, \ "\"/manifestdependency:type='Win32' "\ "name='Microsoft.Windows.Common-Controls' "\ "version='6.0.0.0' "\ "processorArchitecture='*' "\ "publicKeyToken='6595b64144ccf1df' "\ "language='*'\"") // // ChooseDeviceParam structure // // Holds an array of IMFActivate pointers that represent video // capture devices. // struct ChooseDeviceParam { IMFActivate **ppDevices; // Array of IMFActivate pointers. UINT32 count; // Number of elements in the array. UINT32 selection; // Selected device, by array index. }; BOOL InitializeApplication(); BOOL InitializeWindow(HWND *pHwnd); void CleanUp(); INT MessageLoop(HWND hwnd); LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); INT_PTR CALLBACK DlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); void ShowErrorMessage(PCWSTR format, HRESULT hr); // Window message handlers BOOL OnCreate(HWND hwnd, LPCREATESTRUCT lpCreateStruct); void OnClose(HWND hwnd); void OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify); void OnSize(HWND hwnd, UINT state, int cx, int cy); void OnDeviceChange(HWND hwnd, DEV_BROADCAST_HDR *pHdr); // Command handlers void OnChooseDevice(HWND hwnd, BOOL bPrompt); // Constants const WCHAR CLASS_NAME[] = L"MFCapture Window Class"; const WCHAR WINDOW_NAME[] = L"MFCapture Sample Application"; // Global variables CPreview *g_pPreview = NULL; HDEVNOTIFY g_hdevnotify = NULL; //------------------------------------------------------------------- // WinMain // // Application entry-point. //------------------------------------------------------------------- INT WINAPI wWinMain(HINSTANCE,HINSTANCE,LPWSTR,INT) { HWND hwnd = 0; (void)HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0); if (InitializeApplication() && InitializeWindow(&hwnd)) { MessageLoop(hwnd); } CleanUp(); return 0; } //------------------------------------------------------------------- // WindowProc // // Window procedure. //------------------------------------------------------------------- LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { HANDLE_MSG(hwnd, WM_CREATE, OnCreate); HANDLE_MSG(hwnd, WM_CLOSE, OnClose); HANDLE_MSG(hwnd, WM_COMMAND, OnCommand); HANDLE_MSG(hwnd, WM_SIZE, OnSize); case WM_APP_PREVIEW_ERROR: ShowErrorMessage(L"Error", (HRESULT)wParam); break; case WM_DEVICECHANGE: OnDeviceChange(hwnd, (PDEV_BROADCAST_HDR)lParam); break; case WM_ERASEBKGND: return 1; } return DefWindowProc(hwnd, uMsg, wParam, lParam); } //------------------------------------------------------------------- // InitializeApplication // // Initializes the application. //------------------------------------------------------------------- BOOL InitializeApplication() { HRESULT hr = S_OK; hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); if (SUCCEEDED(hr)) { hr = MFStartup(MF_VERSION); } return (SUCCEEDED(hr)); } //------------------------------------------------------------------- // CleanUp // // Releases resources. //------------------------------------------------------------------- void CleanUp() { if (g_hdevnotify) { UnregisterDeviceNotification(g_hdevnotify); } if (g_pPreview) { g_pPreview->CloseDevice(); } SafeRelease(&g_pPreview); MFShutdown(); CoUninitialize(); } //------------------------------------------------------------------- // InitializeWindow // // Creates the application window. //------------------------------------------------------------------- BOOL InitializeWindow(HWND *pHwnd) { WNDCLASS wc = {0}; wc.lpfnWndProc = WindowProc; wc.hInstance = GetModuleHandle(NULL); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.lpszClassName = CLASS_NAME; wc.lpszMenuName = MAKEINTRESOURCE(IDR_MENU1); if (!RegisterClass(&wc)) { return FALSE; } HWND hwnd = CreateWindow( CLASS_NAME, WINDOW_NAME, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, GetModuleHandle(NULL), NULL ); if (!hwnd) { return FALSE; } ShowWindow(hwnd, SW_SHOWDEFAULT); UpdateWindow(hwnd); *pHwnd = hwnd; return TRUE; } //------------------------------------------------------------------- // MessageLoop // // Implements the window message loop. //------------------------------------------------------------------- INT MessageLoop(HWND hwnd) { MSG msg = {0}; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } DestroyWindow(hwnd); return INT(msg.wParam); } //------------------------------------------------------------------- // OnCreate // // Handles the WM_CREATE message. //------------------------------------------------------------------- BOOL OnCreate(HWND hwnd, LPCREATESTRUCT) { HRESULT hr = S_OK; // Register this window to get device notification messages. DEV_BROADCAST_DEVICEINTERFACE di = { 0 }; di.dbcc_size = sizeof(di); di.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE; di.dbcc_classguid = KSCATEGORY_CAPTURE; g_hdevnotify = RegisterDeviceNotification( hwnd, &di, DEVICE_NOTIFY_WINDOW_HANDLE ); if (g_hdevnotify == NULL) { ShowErrorMessage(L"RegisterDeviceNotification failed.", HRESULT_FROM_WIN32(GetLastError())); return FALSE; } // Create the object that manages video preview. hr = CPreview::CreateInstance(hwnd, hwnd, &g_pPreview); if (FAILED(hr)) { ShowErrorMessage(L"CPreview::CreateInstance failed.", hr); return FALSE; } // Select the first available device (if any). OnChooseDevice(hwnd, FALSE); return TRUE; } //------------------------------------------------------------------- // OnClose // // Handles WM_CLOSE messages. //------------------------------------------------------------------- void OnClose(HWND /*hwnd*/) { PostQuitMessage(0); } //------------------------------------------------------------------- // OnSize // // Handles WM_SIZE messages. //------------------------------------------------------------------- void OnSize(HWND hwnd, UINT /*state */, int cx, int cy) { if (g_pPreview) { g_pPreview->ResizeVideo((WORD)cx, (WORD)cy); InvalidateRect(hwnd, NULL, FALSE); } } //------------------------------------------------------------------- // OnCommand // // Handles WM_COMMAND messages //------------------------------------------------------------------- void OnCommand(HWND hwnd, int id, HWND /*hwndCtl*/, UINT /*codeNotify*/) { switch (id) { case ID_FILE_CHOOSEDEVICE: OnChooseDevice(hwnd, TRUE); break; } } //------------------------------------------------------------------- // OnChooseDevice // // Select a video capture device. // // hwnd: A handle to the application window. /// bPrompt: If TRUE, prompt to user to select the device. Otherwise, // select the first device in the list. //------------------------------------------------------------------- void OnChooseDevice(HWND hwnd, BOOL bPrompt) { HRESULT hr = S_OK; ChooseDeviceParam param = { 0 }; UINT iDevice = 0; // Index into the array of devices BOOL bCancel = FALSE; IMFAttributes *pAttributes = NULL; // Initialize an attribute store to specify enumeration parameters. hr = MFCreateAttributes(&pAttributes, 1); if (FAILED(hr)) { goto done; } // Ask for source type = video capture devices. hr = pAttributes->SetGUID( MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE, MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID ); if (FAILED(hr)) { goto done; } // Enumerate devices. hr = MFEnumDeviceSources(pAttributes, ¶m.ppDevices, ¶m.count); if (FAILED(hr)) { goto done; } // NOTE: param.count might be zero. if (bPrompt) { // Ask the user to select a device. INT_PTR result = DialogBoxParam( GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_CHOOSE_DEVICE), hwnd, DlgProc, (LPARAM)¶m ); if (result == IDOK) { iDevice = param.selection; } else { bCancel = TRUE; // User cancelled } } if (!bCancel && (param.count > 0)) { // Give this source to the CPlayer object for preview. hr = g_pPreview->SetDevice( param.ppDevices[iDevice] ); } done: SafeRelease(&pAttributes); for (DWORD i = 0; i < param.count; i++) { SafeRelease(¶m.ppDevices[i]); } CoTaskMemFree(param.ppDevices); if (FAILED(hr)) { ShowErrorMessage(L"Cannot create a video capture device", hr); } } //------------------------------------------------------------------- // OnDeviceChange // // Handles WM_DEVICECHANGE messages. //------------------------------------------------------------------- void OnDeviceChange(HWND hwnd, DEV_BROADCAST_HDR *pHdr) { if (g_pPreview == NULL || pHdr == NULL) { return; } HRESULT hr = S_OK; BOOL bDeviceLost = FALSE; // Check if the current device was lost. hr = g_pPreview->CheckDeviceLost(pHdr, &bDeviceLost); if (FAILED(hr) || bDeviceLost) { g_pPreview->CloseDevice(); MessageBox(hwnd, L"Lost the capture device.", WINDOW_NAME, MB_OK); } } ///////////////////////////////////////////////////////////////////// // Dialog functions void OnInitDialog(HWND hwnd, ChooseDeviceParam *pParam); HRESULT OnOK(HWND hwnd, ChooseDeviceParam *pParam); //------------------------------------------------------------------- // DlgProc // // Dialog procedure for the "Select Device" dialog. //------------------------------------------------------------------- INT_PTR CALLBACK DlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { static ChooseDeviceParam *pParam = NULL; switch (msg) { case WM_INITDIALOG: pParam = (ChooseDeviceParam*)lParam; OnInitDialog(hwnd, pParam); return TRUE; case WM_COMMAND: switch(LOWORD(wParam)) { case IDOK: OnOK(hwnd, pParam); EndDialog(hwnd, LOWORD(wParam)); return TRUE; case IDCANCEL: EndDialog(hwnd, LOWORD(wParam)); return TRUE; } break; } return FALSE; } //------------------------------------------------------------------- // OnInitDialog // // Handles the WM_INITDIALOG message. //------------------------------------------------------------------- void OnInitDialog(HWND hwnd, ChooseDeviceParam *pParam) { HRESULT hr = S_OK; // Populate the list with the friendly names of the devices. HWND hList = GetDlgItem(hwnd, IDC_DEVICE_LIST); for (DWORD i = 0; i < pParam->count; i++) { WCHAR *szFriendlyName = NULL; hr = pParam->ppDevices[i]->GetAllocatedString( MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME, &szFriendlyName, NULL ); if (FAILED(hr)) { break; } int index = ListBox_AddString(hList, szFriendlyName); ListBox_SetItemData(hList, index, i); CoTaskMemFree(szFriendlyName); } // Assume no selection for now. pParam->selection = (UINT32)-1; if (pParam->count == 0) { // If there are no devices, disable the "OK" button. EnableWindow(GetDlgItem(hwnd, IDOK), FALSE); } } HRESULT OnOK(HWND hwnd, ChooseDeviceParam *pParam) { HWND hList = GetDlgItem(hwnd, IDC_DEVICE_LIST); int sel = ListBox_GetCurSel(hList); if (sel != LB_ERR) { pParam->selection = (UINT32)ListBox_GetItemData(hList, sel); } return S_OK; } void ShowErrorMessage(PCWSTR format, HRESULT hrErr) { HRESULT hr = S_OK; WCHAR msg[MAX_PATH]; hr = StringCbPrintf(msg, sizeof(msg), L"%s (hr=0x%X)", format, hrErr); if (SUCCEEDED(hr)) { MessageBox(NULL, msg, L"Error", MB_ICONERROR); } else { DebugBreak(); } }