/////////////////////////////////////////////////////////////////////////////// // // File: gfxui.c // // This file defines the functions that are used by the Global // Effects (GFX) page to drive manipulate the effects for a // mixer. // // History: // 10 June 2000 RogerW // Created. // // Copyright (C) 2000 Microsoft Corporation All Rights Reserved. // // Microsoft Confidential // /////////////////////////////////////////////////////////////////////////////// //============================================================================= // Include files //============================================================================= #include #include #include "mmcpl.h" #include #include #include #include "gfxui.h" #define ADDGFX #define REGSTR_VAL_FRIENDLYNAME TEXT("FriendlyName") // // IDataObject Implementation // class GFXDataObject : public IDataObject { public: GFXDataObject (DWORD dwGfxID) { m_cRef = 1; m_dwGfxID = dwGfxID; } // IUnknown interface STDMETHODIMP QueryInterface (REFIID riid, LPVOID *ppv); STDMETHODIMP_(ULONG) AddRef () { return ++m_cRef; } STDMETHODIMP_(ULONG) Release () { return --m_cRef; } STDMETHODIMP GetData (FORMATETC * pformatetcIn, STGMEDIUM * pmedium); STDMETHODIMP GetDataHere (FORMATETC * pformatetc, STGMEDIUM *pmedium) { return E_NOTIMPL; } STDMETHODIMP QueryGetData (FORMATETC * pformatetc) { return E_NOTIMPL; } STDMETHODIMP GetCanonicalFormatEtc (FORMATETC * pformatetcIn, FORMATETC * pFormatetcOut) { return E_NOTIMPL; } STDMETHODIMP SetData (FORMATETC * pformatetc, STGMEDIUM * pmedium, BOOL fRelease) { return E_NOTIMPL; } STDMETHODIMP EnumFormatEtc (DWORD dwDirection, IEnumFORMATETC ** ppenumFormatEtc ) { return E_NOTIMPL; } STDMETHODIMP DAdvise (FORMATETC * pformatetc, DWORD advf, IAdviseSink* pAdvSnk, DWORD * pdwConnection) { return E_NOTIMPL; } STDMETHODIMP DUnadvise (DWORD dwConnection) { return E_NOTIMPL; } STDMETHODIMP EnumDAdvise (IEnumSTATDATA ** ppenumAdvise) { return E_NOTIMPL; } private: UINT m_cRef; DWORD m_dwGfxID; }; STDMETHODIMP GFXDataObject::QueryInterface (REFIID riid, LPVOID * ppvObj) { if (!ppvObj) return E_POINTER; *ppvObj = NULL; if (IsEqualIID(riid,IID_IDataObject) || IsEqualIID(riid,IID_IUnknown)) *ppvObj = (IDataObject *) this; else return E_NOINTERFACE; ((IUnknown *) *ppvObj) -> AddRef (); return S_OK; } STDMETHODIMP GFXDataObject::GetData (LPFORMATETC pformatetc, LPSTGMEDIUM pmedium) // @parm Storage to be created. { HRESULT hr = E_INVALIDARG; if (pformatetc && pmedium && TYMED_HGLOBAL == pformatetc -> tymed) { HANDLE hGfx = NULL; #ifdef ADDGFX hr = gfxOpenGfx (m_dwGfxID, &hGfx); #endif // ADDGFX if (SUCCEEDED (hr)) { pmedium -> tymed = TYMED_HGLOBAL; pmedium -> pUnkForRelease = NULL; pmedium -> hGlobal = hGfx; } } return hr; } HRESULT InitList (DWORD dwMixID, DWORD dwType, PPGFXUILIST ppList) { HRESULT hr = E_INVALIDARG; if (ppList) { PGFXUILIST pList = (PGFXUILIST) LocalAlloc (LPTR, sizeof (GFXUILIST)); *ppList = NULL; // Init pointer if (pList) { hr = S_OK; pList -> dwType = dwType; pList -> puiList = NULL; #ifdef UNICODE pList -> pszZoneDi = (PWSTR) GetInterfaceName (dwMixID); #else pList -> pszZoneDi = NULL; // This should not happen #endif if (pList -> pszZoneDi) { // Return new list *ppList = pList; } else { // Error! LocalFree (pList); hr = E_OUTOFMEMORY; } } else hr = E_OUTOFMEMORY; } return hr; } void GFXUI_FreeList (PPGFXUILIST ppList) { if (ppList) { PGFXUILIST pList = *ppList; if (pList) { // Free Zone if (pList -> pszZoneDi) GlobalFreePtr (pList -> pszZoneDi); pList -> pszZoneDi = NULL; // Free GFX List FreeListNodes (&(pList -> puiList)); // Free list LocalFree (pList); *ppList = NULL; } } } void FreeListNodes (PPGFXUI ppuiList) { if (ppuiList) { PGFXUI pNodeDelete; PGFXUI puiList = *ppuiList; // Free list nodes while (puiList) { pNodeDelete = puiList; puiList = puiList -> pNext; FreeNode (&pNodeDelete); } *ppuiList = NULL; } } void FreeNode (PPGFXUI ppNode) { if (ppNode && *ppNode) { PGFXUI pNode = *ppNode; // Free the strings if (pNode -> pszName) LocalFree (pNode -> pszName); if (pNode -> pszFactoryDi) LocalFree (pNode -> pszFactoryDi); // Free the node LocalFree (pNode); *ppNode = NULL; } } HKEY OpenGfxRegKey (PCWSTR pszGfxFactoryDi, REGSAM sam) { HKEY hkeyGfx = NULL; if (pszGfxFactoryDi) { HDEVINFO DeviceInfoSet = SetupDiCreateDeviceInfoList (NULL, NULL); if (INVALID_HANDLE_VALUE != DeviceInfoSet) { SP_DEVICE_INTERFACE_DATA DeviceInterfaceData; DeviceInterfaceData.cbSize = sizeof (SP_DEVICE_INTERFACE_DATA); if (SetupDiOpenDeviceInterface (DeviceInfoSet, pszGfxFactoryDi, 0, &DeviceInterfaceData)) { hkeyGfx = SetupDiOpenDeviceInterfaceRegKey ( DeviceInfoSet, &DeviceInterfaceData, 0, sam); } SetupDiDestroyDeviceInfoList (DeviceInfoSet); } } return hkeyGfx; } HRESULT GetFriendlyName (PCWSTR pszGfxFactoryDi, PWSTR* ppszName) { HRESULT hr = E_INVALIDARG; HKEY hkeyGfx = NULL; // Check parameters if (ppszName && pszGfxFactoryDi) { HKEY hkeyGfx = OpenGfxRegKey (pszGfxFactoryDi, KEY_READ); *ppszName = NULL; if (hkeyGfx) { WCHAR szBuffer[MAX_PATH]; DWORD dwType = REG_SZ; DWORD cb = sizeof (szBuffer) / sizeof (szBuffer[0]); hr = S_OK; if (ERROR_SUCCESS == RegQueryValueEx (hkeyGfx, REGSTR_VAL_FRIENDLYNAME, NULL, &dwType, (LPBYTE)szBuffer, &cb)) { *ppszName = (PWSTR) LocalAlloc (LPTR, lstrlen (szBuffer)*2+2); if (*ppszName) wcscpy (*ppszName, szBuffer); else hr = E_OUTOFMEMORY; } else hr = REGDB_E_READREGDB; RegCloseKey (hkeyGfx); } } return hr; } HRESULT AddFactoryNode (PCWSTR pszGfxFactoryDi, PPGFXUILIST ppList) { return AddNode (pszGfxFactoryDi, 0, GUID_NULL, 0, 0, 0, ppList); } HRESULT AddNode (PCWSTR pszGfxFactoryDi, DWORD Id, REFCLSID rclsid, DWORD Type, DWORD Order, DWORD nFlags, PPGFXUILIST ppList) { PGFXUI pNode = NULL; HRESULT hr = S_OK; // Check parameters if (!ppList || !(*ppList) || !pszGfxFactoryDi) return E_INVALIDARG; // Create node if (SUCCEEDED (hr = CreateNode (NULL, pszGfxFactoryDi, &pNode))) { if (pNode) { // Initilize the rest of the values pNode -> Id = Id; pNode -> Type = Type; pNode -> Order = Order; pNode -> nFlags = nFlags; pNode -> clsidUI = rclsid; if (FAILED (hr = AttachNode (ppList, pNode))) FreeNode (&pNode); } else hr = E_UNEXPECTED; } return hr; } // Note: This function always adds the node to the list IN ORDER // IFF (pNode -> nFlags & GFX_CREATED). HRESULT AttachNode (PPGFXUILIST ppList, PGFXUI pNode) { HRESULT hr = E_INVALIDARG; // Check parameters if (ppList && (*ppList) && pNode) { PGFXUI puiList = (*ppList) -> puiList; hr = S_OK; // Make sure our next pointer starts out null.. pNode -> pNext = NULL; if (puiList) { if (!(pNode -> nFlags & GFX_CREATED) || (puiList -> Order >= pNode -> Order)) { // Order is not available, just stick it on the front or // the order happens to put the node at the front. pNode -> pNext = puiList; puiList = pNode; } else { PGFXUI pSearch = puiList; if (!(puiList -> pNext)) { // One element list. We know the new node doesn't belong // at the head of the list, so it is behind. puiList -> pNext = pNode; } else { while (pSearch -> pNext) { if (!(pSearch -> pNext -> nFlags & GFX_CREATED)) { hr = E_INVALIDARG; break; // Cannot mix list types } if (pSearch -> pNext -> Order >= pNode -> Order) { // We found the insertion point! pNode -> pNext = pSearch -> pNext; pSearch -> pNext = pNode; break; } if (!(pSearch -> pNext -> pNext)) { // At end of list, attach node to end pSearch -> pNext -> pNext = pNode; break; } // Move to next element pSearch = pSearch -> pNext; } } } } else { // First element of the list puiList = pNode; } if (SUCCEEDED (hr)) { // Ensure we pass back the correct list pointer (*ppList) -> puiList = puiList; } } return hr; } LONG GFXEnum (PVOID Context, DWORD Id, PCWSTR GfxFactoryDi, REFCLSID rclsid, DWORD Type, DWORD Order) { PGFXUILIST pList = (PGFXUILIST) Context; HRESULT hr = E_INVALIDARG; if (pList) { if (Type == pList->dwType) { if (FAILED (hr = AddNode (GfxFactoryDi, Id, rclsid, Type, Order, GFX_CREATED, &pList))) { // Error, free the list GFXUI_FreeList (&pList); Context = NULL; } } else hr = NOERROR; } return hr; } BOOL GFXUI_CheckDevice (DWORD dwMixID, DWORD dwType) { HRESULT hr = S_OK; BOOL fRet = FALSE; PGFXUILIST pList = NULL; if (SUCCEEDED (hr = InitList (dwMixID, dwType, &pList))) { if (pList && pList -> pszZoneDi) { PDEVICEINTERFACELIST pdiList = NULL; LONG lResult = NO_ERROR; lResult = gfxCreateGfxFactoriesList (pList -> pszZoneDi, &pdiList); if ((lResult == NO_ERROR) && pdiList) { fRet = TRUE; gfxDestroyDeviceInterfaceList (pdiList); } GFXUI_FreeList (&pList); } } return fRet; } HRESULT GFXUI_CreateList (DWORD dwMixID, DWORD dwType, BOOL fAll, PPGFXUILIST ppList) { HRESULT hr = E_INVALIDARG; if (ppList) { hr = S_OK; if (SUCCEEDED (hr = InitList (dwMixID, dwType, ppList))) { if (*ppList && (*ppList) -> pszZoneDi) { if (!fAll) { hr = gfxEnumerateGfxs ((*ppList) -> pszZoneDi, GFXEnum, (*ppList)); } else { PDEVICEINTERFACELIST pdiList = NULL; hr = gfxCreateGfxFactoriesList ((*ppList) -> pszZoneDi, &pdiList); if (SUCCEEDED (hr) && pdiList) { LONG lIndex; for (lIndex = 0; lIndex < pdiList -> Count; lIndex++) { hr = AddFactoryNode ((pdiList -> DeviceInterface)[lIndex], ppList); if (FAILED (hr)) { GFXUI_FreeList (ppList); break; } } gfxDestroyDeviceInterfaceList (pdiList); } else { GFXUI_FreeList (ppList); hr = E_OUTOFMEMORY; } } } else hr = E_UNEXPECTED; } } return hr; } HRESULT GFXUI_Properties (PGFXUI puiGFX, HWND hWndOwner) { HRESULT hr = E_INVALIDARG; if (puiGFX && GFXUI_CanShowProperties (puiGFX) && IsWindow (hWndOwner)) { ISpecifyPropertyPages* pISpecifyPropertyPages = NULL; // Get the Vendor UI Property Pages Interface hr = CoCreateInstance (puiGFX -> clsidUI, NULL, CLSCTX_INPROC_SERVER, IID_ISpecifyPropertyPages, (void**)&pISpecifyPropertyPages); if (SUCCEEDED (hr) && !pISpecifyPropertyPages) hr = E_UNEXPECTED; if (SUCCEEDED (hr)) { CAUUID Pages; ZeroMemory (&Pages, sizeof (Pages)); // Get the VendorUI Property Page CLSID's hr = pISpecifyPropertyPages -> GetPages (&Pages); if (SUCCEEDED (hr) && (Pages.cElems == 0 || !Pages.pElems)) hr = E_UNEXPECTED; if (SUCCEEDED (hr)) { RECT rcWindow; if (GetWindowRect (hWndOwner, &rcWindow)) { TCHAR szCaption[MAX_PATH]; GFXDataObject DataObject (puiGFX -> Id); IUnknown* punkDataObject = &DataObject; // Load the VendorUI caption LoadString (ghInstance, IDS_EFFECTS_PROPERTY_CAPTION, szCaption, sizeof (szCaption)/sizeof(TCHAR)); // Bring up the Vendor UI hr = OleCreatePropertyFrame (hWndOwner, rcWindow.left + 10, rcWindow.top + 10, szCaption, 1, &punkDataObject, Pages.cElems, Pages.pElems, GetSystemDefaultLangID (), 0, NULL); } else hr = E_FAIL; CoTaskMemFree (Pages.pElems); } pISpecifyPropertyPages -> Release (); } } return hr; } UINT GetListSize (PGFXUI puiList) { UINT uiSize = 0; PGFXUI puiListSeek = puiList; while (puiListSeek) { puiListSeek = puiListSeek -> pNext; uiSize++; } return uiSize; } HRESULT GFXUI_Apply (PPGFXUILIST ppListApply, PPGFXUI ppuiListDelete) { HRESULT hr = E_INVALIDARG; PGFXUILIST pListApply = (ppListApply ? *ppListApply : NULL); PGFXUI puiListDelete = (ppuiListDelete ? *ppuiListDelete : NULL); if ((pListApply && pListApply -> puiList) || puiListDelete) { PGFXREMOVEREQUEST paGfxRemoveRequests = NULL; PGFXMODIFYREQUEST paGfxModifyRequests = NULL; PGFXADDREQUEST paGfxAddRequests = NULL; ULONG cGfxRemoveRequests = 0; ULONG cGfxModifyRequests = 0; ULONG cGfxAddRequests = 0; ULONG cApplyList = GetListSize (pListApply ? pListApply -> puiList : NULL); ULONG cDeleteList = GetListSize (puiListDelete); PGFXUI puiListSeek = NULL; hr = S_OK; // This function needs to create: // - Deleted Array of GFXREMOVEREQUEST's // - Modify Array of GFXMODIFYREQUEST's // - Add Array of GFXADDREQUEST's // // The deleted array is fairly easy, just pull out the // marked ones. With the remaining, we need to loop through // them comparing order and create modify records as needed // to modify their order (except for the add records where // we must save the nessary order in the add request array). // Then we create the add array (perhaps with the modify array) // and fill in everything else (other than order). // // Then call GFX_BatchChange(). // // Afterword, we need to update our list accordingly (i.e. delete // nodes, update order, etc). // Create our parameters // Note: These buffers are really upper bounds on the memory we will need. // We will count the actual requests we make and pass that value to // the GFX function call. if (0 < cDeleteList) { paGfxRemoveRequests = (PGFXREMOVEREQUEST) LocalAlloc (LPTR, sizeof (*paGfxRemoveRequests) * cDeleteList); if (!paGfxRemoveRequests) hr = E_OUTOFMEMORY; } if (0 < cApplyList) { paGfxModifyRequests = (PGFXMODIFYREQUEST) LocalAlloc (LPTR, sizeof (*paGfxModifyRequests) * cApplyList); paGfxAddRequests = (PGFXADDREQUEST) LocalAlloc (LPTR, sizeof (*paGfxAddRequests) * cApplyList); if (!paGfxModifyRequests || !paGfxAddRequests) hr = E_OUTOFMEMORY; } if (SUCCEEDED (hr)) { UINT uiIndx; DWORD dwOrder = 0; // Create the remove parameter puiListSeek = puiListDelete; for (uiIndx = 0; uiIndx < cDeleteList; uiIndx++) { // Make sure this is created before we ask to delete it. // (It may be an AddNode that was deleted before creation). if (puiListSeek -> nFlags & GFX_CREATED) { (paGfxRemoveRequests + cGfxRemoveRequests) -> IdToRemove = puiListSeek -> Id; (paGfxRemoveRequests + cGfxRemoveRequests) -> Error = S_OK; cGfxRemoveRequests++; } puiListSeek = puiListSeek -> pNext; } // Create the modify and add parameters puiListSeek = pListApply ? pListApply -> puiList : NULL; for (uiIndx = 0; uiIndx < cApplyList; uiIndx++) { if (puiListSeek -> nFlags & GFX_ADD) { (paGfxAddRequests + cGfxAddRequests) -> ZoneFactoryDi = pListApply -> pszZoneDi; (paGfxAddRequests + cGfxAddRequests) -> GfxFactoryDi = puiListSeek -> pszFactoryDi; (paGfxAddRequests + cGfxAddRequests) -> Type = pListApply -> dwType; (paGfxAddRequests + cGfxAddRequests) -> Order = dwOrder++; (paGfxAddRequests + cGfxAddRequests) -> NewId = 0; (paGfxAddRequests + cGfxAddRequests) -> Error = S_OK; cGfxAddRequests++; } else { if (puiListSeek -> nFlags & GFX_CREATED) { // We only need to add modify records for GFX'es // that are no longer in order. if (puiListSeek -> Order < dwOrder) { (paGfxModifyRequests + cGfxModifyRequests) -> IdToModify = puiListSeek -> Id; (paGfxModifyRequests + cGfxModifyRequests) -> NewOrder = dwOrder++; (paGfxModifyRequests + cGfxModifyRequests) -> Error = S_OK; cGfxModifyRequests++; } else dwOrder = (puiListSeek -> Order + 1); } else { // Bogus list entry, abort everything! hr = E_INVALIDARG; break; } } puiListSeek = puiListSeek -> pNext; } if (SUCCEEDED (hr)) { #ifdef ADDGFX hr = gfxBatchChange (paGfxRemoveRequests, cGfxRemoveRequests, paGfxModifyRequests, cGfxModifyRequests, paGfxAddRequests, cGfxAddRequests); #endif // ADDGFX if (SUCCEEDED (hr)) { PGFXMODIFYREQUEST paGfxModifySeek = paGfxModifyRequests; PGFXADDREQUEST paGfxAddSeek = paGfxAddRequests; // Update the passed arrays FreeListNodes (ppuiListDelete); puiListSeek = pListApply ? pListApply -> puiList : NULL; for (uiIndx = 0; uiIndx < cApplyList; uiIndx++) { // Update the list items. if (puiListSeek -> nFlags & GFX_ADD) { // Update the newly create GFX puiListSeek -> nFlags = GFX_CREATED; puiListSeek -> Id = paGfxAddSeek -> NewId; puiListSeek -> Type = paGfxAddSeek -> Type; puiListSeek -> Order = paGfxAddSeek -> Order; paGfxAddSeek++; } else // must be (puiListSeek -> nFlags & GFX_CREATED) { // Update the order puiListSeek -> Order = paGfxModifySeek -> NewOrder; paGfxModifySeek++; } } } } } // Free parameters if (paGfxRemoveRequests) LocalFree (paGfxRemoveRequests); if (paGfxModifyRequests) LocalFree (paGfxModifyRequests); if (paGfxAddRequests) LocalFree (paGfxAddRequests); } return hr; } /////////////////////////////////////////////////////////////////////////////////////////// // Microsoft Confidential - DO NOT COPY THIS METHOD INTO ANY APPLICATION, THIS MEANS YOU!!! /////////////////////////////////////////////////////////////////////////////////////////// PTCHAR GetInterfaceName (DWORD dwMixerID) { MMRESULT mmr; ULONG cbSize=0; TCHAR *szInterfaceName=NULL; //Query for the Device interface name mmr = mixerMessage(HMIXER_INDEX(dwMixerID), DRV_QUERYDEVICEINTERFACESIZE, (DWORD_PTR)&cbSize, 0L); if(MMSYSERR_NOERROR == mmr) { szInterfaceName = (TCHAR *)GlobalAllocPtr(GHND, (cbSize+1)*sizeof(TCHAR)); if(!szInterfaceName) { return NULL; } mmr = mixerMessage(HMIXER_INDEX(dwMixerID), DRV_QUERYDEVICEINTERFACE, (DWORD_PTR)szInterfaceName, cbSize); if(MMSYSERR_NOERROR != mmr) { GlobalFreePtr(szInterfaceName); return NULL; } } return szInterfaceName; } BOOL GFXUI_CanShowProperties (PGFXUI puiGFX) { return (puiGFX && (puiGFX -> nFlags & GFX_CREATED) && (puiGFX -> clsidUI != GUID_NULL)); } HRESULT CreateNode (PCWSTR pszName, PCWSTR pszGfxFactoryDi, PPGFXUI ppNode) { HRESULT hr = E_INVALIDARG; if (ppNode) { // Create node PGFXUI pNode = (PGFXUI) LocalAlloc (LPTR, sizeof (GFXUI)); hr = S_OK; if (pNode) { ZeroMemory (pNode, sizeof (GFXUI)); // Create the strings if (pszName) { pNode -> pszName = (PWSTR) LocalAlloc (LPTR, lstrlen (pszName)*2+2); if (pNode -> pszName) wcscpy (pNode -> pszName, pszName); else hr = E_OUTOFMEMORY; } else { // If there is no name, get it from the factory pNode -> pszName = NULL; if (pszGfxFactoryDi) hr = GetFriendlyName (pszGfxFactoryDi, &(pNode -> pszName)); } if (SUCCEEDED (hr) && pszGfxFactoryDi) { pNode -> pszFactoryDi = (PWSTR) LocalAlloc (LPTR, lstrlen (pszGfxFactoryDi)*2+2); if (pNode -> pszFactoryDi) wcscpy (pNode -> pszFactoryDi, pszGfxFactoryDi); else hr = E_OUTOFMEMORY; } if (SUCCEEDED (hr)) // Return node *ppNode = pNode; else // Free node FreeNode (&pNode); } else hr = E_OUTOFMEMORY; } return hr; } // This function creates an "addable" GFXUI element that will be able // to create a new GFX when you call GFXUI_Apply() with this new element // in the list. HRESULT GFXUI_CreateAddGFX (PPGFXUI ppuiGFXAdd, PGFXUI puiGFXSource) { HRESULT hr = E_INVALIDARG; if (ppuiGFXAdd && puiGFXSource) { *ppuiGFXAdd = NULL; hr = CreateNode (puiGFXSource -> pszName, puiGFXSource -> pszFactoryDi, ppuiGFXAdd); if (SUCCEEDED (hr)) { if (*ppuiGFXAdd) { // Indicate that this is a new 'Add' node. (*ppuiGFXAdd) -> nFlags = GFX_ADD; } else hr = E_UNEXPECTED; } } return hr; }