| // Copyright (c) 2010 The WebM project authors. All Rights Reserved. | |
| // | |
| // Use of this source code is governed by a BSD-style license | |
| // that can be found in the LICENSE file in the root of the source | |
| // tree. An additional intellectual property rights grant can be found | |
| // in the file PATENTS. All contributing project authors may | |
| // be found in the AUTHORS file in the root of the source tree. | |
| #include "comreg.hpp" | |
| #include "registry.hpp" | |
| #include <malloc.h> | |
| #include <cassert> | |
| #include <sstream> | |
| //#if (_WIN32_WINNT >= 0x0601) | |
| //#include <sfc.h> | |
| //#pragma comment(lib, "sfc") | |
| //#endif | |
| using std::wstring; | |
| using std::wostringstream; | |
| GUID ComReg::GUIDFromString(const wchar_t* const_str) | |
| { | |
| wchar_t* const str = const_cast<wchar_t*>(const_str); | |
| GUID guid; | |
| const HRESULT hr = CLSIDFromString(str, &guid); | |
| assert(SUCCEEDED(hr)); //TODO | |
| hr; | |
| return guid; | |
| } | |
| HRESULT ComReg::ComRegGetModuleFileName(HMODULE h, std::wstring& result) | |
| { | |
| DWORD n = 256; //number of TCHARS | |
| for (;;) | |
| { | |
| void* const pv = _alloca(n * sizeof(wchar_t)); | |
| wchar_t* const buf = (wchar_t*)pv; | |
| const DWORD dw = GetModuleFileNameW(h, buf, n); | |
| if (dw == 0) //error | |
| { | |
| result.clear(); | |
| const DWORD e = GetLastError(); | |
| return HRESULT_FROM_WIN32(e); | |
| } | |
| if (dw >= n) //truncation | |
| { | |
| n *= 2; | |
| continue; | |
| } | |
| result = buf; | |
| return S_OK; | |
| } | |
| } | |
| HRESULT ComReg::RegisterCustomFileType( | |
| const wchar_t* ext, | |
| const GUID& filter, | |
| const GUID& mediatype, | |
| const GUID& subtype) | |
| { | |
| Registry::Key parent, key; | |
| LONG e = parent.open( | |
| HKEY_CLASSES_ROOT, | |
| L"Media Type\\Extensions", | |
| KEY_CREATE_SUB_KEY); | |
| if (e) | |
| return HRESULT_FROM_WIN32(e); | |
| e = key.create<wchar_t>(parent, ext, 0, 0, KEY_SET_VALUE, 0); | |
| if (e) | |
| return HRESULT_FROM_WIN32(e); | |
| wchar_t buf[guid_buflen]; | |
| int n = StringFromGUID2(filter, buf, guid_buflen); | |
| assert(n == guid_buflen); | |
| e = key.set(L"Source Filter", buf); | |
| if (e) | |
| return HRESULT_FROM_WIN32(e); | |
| if (mediatype != GUID_NULL) | |
| { | |
| n = StringFromGUID2(mediatype, buf, guid_buflen); | |
| assert(n == guid_buflen); | |
| e = key.set(L"Media Type", buf); | |
| if (e) | |
| return HRESULT_FROM_WIN32(e); | |
| } | |
| if (subtype != GUID_NULL) | |
| { | |
| n = StringFromGUID2(subtype, buf, guid_buflen); | |
| assert(n == guid_buflen); | |
| e = key.set(L"Subtype", buf); | |
| if (e) | |
| return HRESULT_FROM_WIN32(e); | |
| } | |
| return S_OK; | |
| } | |
| HRESULT ComReg::UnRegisterCustomFileType( | |
| const wchar_t* ext, | |
| const GUID& filter) | |
| { | |
| Registry::Key parent, key; | |
| LONG e = parent.open( | |
| HKEY_CLASSES_ROOT, | |
| L"Media Type\\Extensions", | |
| KEY_ALL_ACCESS); | |
| if (e == ERROR_FILE_NOT_FOUND) //weird | |
| return S_FALSE; | |
| if (e) | |
| return HRESULT_FROM_WIN32(e); | |
| e = key.open(parent, ext, KEY_ALL_ACCESS); | |
| if (e == ERROR_FILE_NOT_FOUND) //normal | |
| return S_FALSE; //not an error if key does not already exist | |
| if (e) //indicates a deeper problem | |
| return HRESULT_FROM_WIN32(e); | |
| wstring clsidstr; | |
| e = key.query(L"Source Filter", clsidstr); | |
| if (e) | |
| return HRESULT_FROM_WIN32(e); | |
| const wchar_t* const const_str = clsidstr.c_str(); | |
| wchar_t* const str = const_cast<wchar_t*>(const_str); | |
| CLSID clsid; | |
| const HRESULT hr = CLSIDFromString(str, &clsid); | |
| hr; | |
| assert(SUCCEEDED(hr)); | |
| if (clsid != filter) | |
| return S_FALSE; | |
| //const wstring key_ = wstring(L"Media Type\\Extensions") + ext; | |
| //const DWORD dw = Registry::SHDeleteKey(HKEY_CLASSES_ROOT, key_.c_str()); | |
| //assert(dw == ERROR_SUCCESS); | |
| key.close(); | |
| e = Registry::DeleteKey(parent, ext); | |
| if (e) | |
| return HRESULT_FROM_WIN32(e); | |
| return S_OK; | |
| } | |
| HRESULT ComReg::RegisterCustomFileType( | |
| const wchar_t* const* argv, //array of check-byte strings | |
| const GUID& filter, | |
| const GUID& mediatype, | |
| const GUID& subtype) | |
| { | |
| assert(argv); | |
| assert(*argv); | |
| assert(filter != GUID_NULL); | |
| assert(mediatype != GUID_NULL); | |
| assert(subtype != GUID_NULL); | |
| Registry::Key parent, key1, key2; | |
| LONG e = parent.open( | |
| HKEY_CLASSES_ROOT, | |
| L"Media Type", | |
| KEY_CREATE_SUB_KEY); | |
| if (e) | |
| return HRESULT_FROM_WIN32(e); | |
| wchar_t buf[guid_buflen]; | |
| int n = StringFromGUID2(mediatype, buf, guid_buflen); | |
| assert(n == guid_buflen); | |
| e = key1.create<wchar_t>(parent, buf, 0, 0, KEY_SET_VALUE, 0); | |
| if (e) | |
| return HRESULT_FROM_WIN32(e); | |
| n = StringFromGUID2(subtype, buf, guid_buflen); | |
| assert(n == guid_buflen); | |
| e = key2.create<wchar_t>(key1, buf, 0, 0, KEY_SET_VALUE, 0); | |
| if (e) | |
| return HRESULT_FROM_WIN32(e); | |
| const wchar_t* arg = *argv; | |
| assert(arg); | |
| int i = 0; | |
| for (;;) | |
| { | |
| wostringstream os; | |
| os << i; | |
| const wstring name_ = os.str(); | |
| const wchar_t* const name = name_.c_str(); | |
| e = key2.set(name, arg); | |
| if (e) | |
| return HRESULT_FROM_WIN32(e); | |
| arg = *++argv; | |
| if (arg == 0) | |
| break; | |
| ++i; | |
| } | |
| n = StringFromGUID2(filter, buf, guid_buflen); | |
| assert(n == guid_buflen); | |
| e = key2.set(L"Source Filter", buf); | |
| if (e) | |
| return HRESULT_FROM_WIN32(e); | |
| return S_OK; | |
| } | |
| static HRESULT CreateClsidKey( | |
| const wstring& clsid_keyname, | |
| const wchar_t* friendlyname, | |
| const wchar_t* inprocserver, | |
| const wchar_t* versionindependentprogid, | |
| const wchar_t* progid, | |
| bool insertable, | |
| bool control, | |
| ComReg::ThreadingModel threadingmodel, | |
| const GUID& typelib, | |
| const wchar_t* version, | |
| int toolboxbitmap) | |
| { | |
| Registry::Key clsid_key; | |
| LONG e = clsid_key.create(HKEY_CLASSES_ROOT, clsid_keyname); | |
| if (e) | |
| return HRESULT_FROM_WIN32(e); | |
| if (friendlyname) | |
| { | |
| e = clsid_key.set(friendlyname); | |
| if (e) | |
| return HRESULT_FROM_WIN32(e); | |
| } | |
| if (insertable) | |
| { | |
| Registry::Key subkey; | |
| e = subkey.create(clsid_key, L"Insertable"); | |
| if (e) | |
| return HRESULT_FROM_WIN32(e); | |
| } | |
| if (control) | |
| { | |
| Registry::Key subkey; | |
| e = subkey.create(clsid_key, L"Control"); | |
| if (e) | |
| return HRESULT_FROM_WIN32(e); | |
| } | |
| if (versionindependentprogid) | |
| { | |
| Registry::Key subkey; | |
| e = subkey.create(clsid_key, L"VersionIndependentProgID"); | |
| if (e) | |
| return HRESULT_FROM_WIN32(e); | |
| e = subkey.set(versionindependentprogid); | |
| if (e) | |
| return HRESULT_FROM_WIN32(e); | |
| } | |
| if (progid) | |
| { | |
| Registry::Key subkey; | |
| e = subkey.create(clsid_key, L"ProgID"); | |
| if (e) | |
| return HRESULT_FROM_WIN32(e); | |
| e = subkey.set(progid); | |
| if (e) | |
| return HRESULT_FROM_WIN32(e); | |
| } | |
| if (inprocserver) | |
| { | |
| Registry::Key subkey; | |
| e = subkey.create(clsid_key, L"InprocServer32"); | |
| if (e) | |
| return HRESULT_FROM_WIN32(e); | |
| e = subkey.set(inprocserver); | |
| if (e) | |
| return HRESULT_FROM_WIN32(e); | |
| if (threadingmodel != ComReg::kSingleThreading) | |
| { | |
| const wchar_t* const a[3] = | |
| { | |
| L"Apartment", | |
| L"Free", | |
| L"Both" | |
| }; | |
| const wchar_t* const val = a[threadingmodel]; | |
| e = subkey.set(L"ThreadingModel", val); | |
| if (e) | |
| return HRESULT_FROM_WIN32(e); | |
| } | |
| } | |
| if (typelib != GUID_NULL) | |
| { | |
| wchar_t guid_str[ComReg::guid_buflen]; | |
| const int n = StringFromGUID2(typelib, guid_str, ComReg::guid_buflen); | |
| assert(n == ComReg::guid_buflen); | |
| n; | |
| Registry::Key subkey; | |
| e = subkey.create(clsid_key, L"TypeLib"); | |
| if (e) | |
| return HRESULT_FROM_WIN32(e); | |
| e = subkey.set(guid_str); | |
| if (e) | |
| return HRESULT_FROM_WIN32(e); | |
| } | |
| if (version) | |
| { | |
| Registry::Key subkey; | |
| e = subkey.create(clsid_key, L"Version"); | |
| if (e) | |
| return HRESULT_FROM_WIN32(e); | |
| e = subkey.set(version); | |
| if (e) | |
| return HRESULT_FROM_WIN32(e); | |
| } | |
| if ((toolboxbitmap > 0) && (inprocserver != 0)) | |
| { | |
| Registry::Key subkey; | |
| e = subkey.create(clsid_key, L"ToolBoxBitmap32"); | |
| if (e) | |
| return HRESULT_FROM_WIN32(e); | |
| std::wostringstream os; | |
| os << inprocserver << L", " << toolboxbitmap; | |
| e = subkey.set(os.str().c_str()); //TODO: fix registry.hpp | |
| if (e) | |
| return HRESULT_FROM_WIN32(e); | |
| } | |
| return S_OK; | |
| } | |
| static HRESULT CreateProgidKey( | |
| const wstring& clsid_str, | |
| const wchar_t* friendlyname, | |
| const wchar_t* progid, | |
| const wchar_t* curver, //only for versionindependentprogid | |
| bool insertable) | |
| { | |
| assert(progid); | |
| Registry::Key progid_key; | |
| LONG e = progid_key.create(HKEY_CLASSES_ROOT, progid); | |
| if (e) | |
| return HRESULT_FROM_WIN32(e); | |
| if (friendlyname) | |
| { | |
| e = progid_key.set(friendlyname); | |
| if (e) | |
| return HRESULT_FROM_WIN32(e); | |
| } | |
| Registry::Key subkey; | |
| e = subkey.create(progid_key, L"CLSID"); | |
| if (e) | |
| return HRESULT_FROM_WIN32(e); | |
| e = subkey.set<wchar_t>(0, clsid_str); //TODO: fix registry.hpp | |
| if (insertable) | |
| { | |
| e = subkey.create(progid_key, L"Insertable"); | |
| if (e) | |
| return HRESULT_FROM_WIN32(e); | |
| } | |
| if (curver) | |
| { | |
| e = subkey.create(progid_key, L"CurVer"); | |
| if (e) | |
| return HRESULT_FROM_WIN32(e); | |
| e = subkey.set(curver); | |
| if (e) | |
| return HRESULT_FROM_WIN32(e); | |
| } | |
| return S_OK; | |
| } | |
| HRESULT ComReg::RegisterCoclass( | |
| const GUID& clsid, | |
| const wchar_t* friendlyname, | |
| const wchar_t* inprocserver, | |
| const wchar_t* versionindependentprogid, | |
| const wchar_t* progid, | |
| bool insertable, | |
| bool control, | |
| ThreadingModel threadingmodel, | |
| const GUID& typelib, | |
| const wchar_t* version, | |
| int toolboxbitmap) | |
| { | |
| wchar_t clsid_str[guid_buflen]; | |
| const int n = StringFromGUID2(clsid, clsid_str, guid_buflen); | |
| assert(n == guid_buflen); | |
| n; | |
| const wstring clsid_keyname = wstring(L"CLSID\\") + clsid_str; | |
| HRESULT hr = CreateClsidKey( | |
| clsid_keyname, | |
| friendlyname, | |
| inprocserver, | |
| versionindependentprogid, | |
| progid, | |
| insertable, | |
| control, | |
| threadingmodel, | |
| typelib, | |
| version, | |
| toolboxbitmap); | |
| if (hr != S_OK) | |
| return hr; | |
| if (versionindependentprogid) | |
| { | |
| hr = CreateProgidKey( | |
| clsid_str, | |
| friendlyname, | |
| versionindependentprogid, | |
| progid, | |
| insertable); //TODO: pass false here? | |
| if (hr != S_OK) | |
| return hr; | |
| } | |
| if (progid) | |
| { | |
| hr = CreateProgidKey( | |
| clsid_str, | |
| friendlyname, | |
| progid, | |
| 0, //no CurVer for progid | |
| insertable); | |
| if (hr != S_OK) | |
| return hr; | |
| } | |
| return S_OK; | |
| } | |
| HRESULT ComReg::UnRegisterCoclass(const GUID& clsid) | |
| { | |
| enum { clsid_strlen = 39 }; | |
| wchar_t clsid_str[clsid_strlen]; | |
| const int n = StringFromGUID2(clsid, clsid_str, clsid_strlen); | |
| assert(n == clsid_strlen); | |
| n; | |
| const wstring clsid_keyname = wstring(L"CLSID\\") + clsid_str; | |
| Registry::Key clsid_key(HKEY_CLASSES_ROOT, clsid_keyname); | |
| //TODO: KEY_QUERY_VALUE | KEY_SET_VALUE); | |
| if (!clsid_key.is_open()) | |
| return S_OK; | |
| Registry::Key subkey(clsid_key, L"VersionIndependentProgID"); //open | |
| if (subkey.is_open()) | |
| { | |
| wstring val; | |
| if (subkey(val)) | |
| { | |
| const DWORD dw = Registry::SHDeleteKey(HKEY_CLASSES_ROOT, val); | |
| assert((dw == ERROR_SUCCESS) || (dw == ERROR_FILE_NOT_FOUND)); | |
| dw; | |
| //TODO: delete subkey from clsid_key | |
| } | |
| } | |
| subkey.open(clsid_key, L"ProgID"); | |
| if (subkey.is_open()) | |
| { | |
| wstring val; | |
| if (subkey(val)) | |
| { | |
| const DWORD dw = Registry::SHDeleteKey(HKEY_CLASSES_ROOT, val); | |
| assert((dw == ERROR_SUCCESS) || (dw == ERROR_FILE_NOT_FOUND)); | |
| dw; | |
| //TODO: delete subkey | |
| } | |
| } | |
| subkey.close(); | |
| clsid_key.close(); | |
| const DWORD dw = Registry::SHDeleteKey(HKEY_CLASSES_ROOT, clsid_keyname); | |
| assert((dw == ERROR_SUCCESS) || (dw == ERROR_FILE_NOT_FOUND)); | |
| dw; | |
| return S_OK; | |
| } | |
| HRESULT ComReg::RegisterTypeLibResource( | |
| const wchar_t* fullpath_, | |
| const wchar_t* helpdir_) | |
| { | |
| ITypeLib* pTypeLib; | |
| HRESULT hr = LoadTypeLib(fullpath_, &pTypeLib); | |
| //Does not register if filename is a full path, which is what we want. | |
| if (FAILED(hr)) | |
| return hr; | |
| assert(pTypeLib); | |
| wchar_t* const fullpath = const_cast<wchar_t*>(fullpath_); | |
| wchar_t* const helpdir = const_cast<wchar_t*>(helpdir_); | |
| hr = RegisterTypeLib(pTypeLib, fullpath, helpdir); | |
| pTypeLib->Release(); | |
| pTypeLib = 0; | |
| return hr; | |
| } | |
| HRESULT ComReg::UnRegisterTypeLibResource(const wchar_t* fullpath) | |
| { | |
| ITypeLib* pTypeLib; | |
| HRESULT hr = LoadTypeLib(fullpath, &pTypeLib); | |
| //Does not register if filename is a full path, which is what we want. | |
| if (FAILED(hr)) | |
| return hr; | |
| assert(pTypeLib); | |
| TLIBATTR* pLibAttr; | |
| hr = pTypeLib->GetLibAttr(&pLibAttr); | |
| if (FAILED(hr)) | |
| { | |
| pTypeLib->Release(); | |
| pTypeLib = 0; | |
| return hr; | |
| } | |
| assert(pLibAttr); | |
| const TLIBATTR a(*pLibAttr); | |
| pTypeLib->ReleaseTLibAttr(pLibAttr); | |
| pTypeLib->Release(); | |
| pTypeLib = 0; | |
| hr = UnRegisterTypeLib( | |
| a.guid, | |
| a.wMajorVerNum, | |
| a.wMinorVerNum, | |
| a.lcid, | |
| a.syskind); | |
| return hr; | |
| } | |
| HRESULT ComReg::GetTypeLibAttr( | |
| const wchar_t* fullpath, | |
| TLIBATTR& a) | |
| { | |
| ITypeLib* pTypeLib; | |
| HRESULT hr = LoadTypeLib(fullpath, &pTypeLib); | |
| //Does not register if filename is a full path, which is what we want. | |
| if (FAILED(hr)) | |
| return hr; | |
| assert(pTypeLib); | |
| TLIBATTR* pLibAttr; | |
| hr = pTypeLib->GetLibAttr(&pLibAttr); | |
| if (FAILED(hr)) | |
| { | |
| pTypeLib->Release(); | |
| pTypeLib = 0; | |
| return hr; | |
| } | |
| assert(pLibAttr); | |
| a = *pLibAttr; | |
| pTypeLib->ReleaseTLibAttr(pLibAttr); | |
| pTypeLib->Release(); | |
| pTypeLib = 0; | |
| return S_OK; | |
| } | |
| #if (_WIN32_WINNT >= 0x0601) | |
| HRESULT ComReg::RegisterByteStreamHandler( | |
| const wchar_t* ext, | |
| const GUID& clsid, | |
| const wchar_t* friendly_name) | |
| { | |
| const wchar_t parent_subkey[] = | |
| L"Software\\Microsoft\\Windows Media Foundation\\ByteStreamHandlers"; | |
| #if 0 | |
| const BOOL bProtected = SfcIsKeyProtected( | |
| HKEY_LOCAL_MACHINE, | |
| parent_subkey, | |
| 0); | |
| if (bProtected) | |
| return E_ACCESSDENIED; | |
| Registry::Key parent; | |
| LONG e = parent.open( | |
| HKEY_LOCAL_MACHINE, | |
| parent_subkey, | |
| KEY_WRITE); //KEY_CREATE_SUB_KEY? | |
| if (e) | |
| return HRESULT_FROM_WIN32(e); | |
| Registry::Key key; | |
| e = key.create<wchar_t>(parent, ext, 0, 0, KEY_SET_VALUE, 0); | |
| if (e) | |
| return HRESULT_FROM_WIN32(e); | |
| #else | |
| const wstring subkey = wstring(parent_subkey) + L"\\" + ext; | |
| Registry::Key key; | |
| LONG e = key.create<wchar_t>( | |
| HKEY_LOCAL_MACHINE, | |
| subkey.c_str(), | |
| 0, | |
| 0, | |
| KEY_WRITE, | |
| 0); | |
| if (e) | |
| return HRESULT_FROM_WIN32(e); | |
| #endif | |
| wchar_t buf[guid_buflen]; | |
| const int n = StringFromGUID2(clsid, buf, guid_buflen); | |
| n; | |
| assert(n == guid_buflen); | |
| e = key.set(buf, friendly_name); | |
| if (e) | |
| return HRESULT_FROM_WIN32(e); | |
| return S_OK; | |
| } | |
| HRESULT ComReg::UnRegisterByteStreamHandler( | |
| const wchar_t* ext, | |
| const GUID& clsid) | |
| { | |
| Registry::Key parent, key; | |
| LONG e = parent.open( | |
| HKEY_LOCAL_MACHINE, | |
| L"Software\\Microsoft" | |
| L"\\Windows Media Foundation\\ByteStreamHandlers", | |
| KEY_ALL_ACCESS); | |
| if (e == ERROR_FILE_NOT_FOUND) //weird | |
| return S_FALSE; | |
| if (e) | |
| return HRESULT_FROM_WIN32(e); | |
| e = key.open(parent, ext, KEY_ALL_ACCESS); | |
| if (e == ERROR_FILE_NOT_FOUND) //normal | |
| return S_FALSE; //not an error if key does not already exist | |
| if (e) //indicates a deeper problem | |
| return HRESULT_FROM_WIN32(e); | |
| wchar_t clsidstr[guid_buflen]; //name | |
| const int n = StringFromGUID2(clsid, clsidstr, guid_buflen); | |
| n; | |
| assert(n == guid_buflen); | |
| wstring value; | |
| e = key.query(clsidstr, value); | |
| if (e == ERROR_FILE_NOT_FOUND) | |
| return S_FALSE; | |
| if (e) | |
| return HRESULT_FROM_WIN32(e); | |
| key.close(); | |
| e = Registry::DeleteKey(parent, ext); | |
| if (e) | |
| return HRESULT_FROM_WIN32(e); | |
| return S_OK; | |
| } | |
| #endif | |
| HRESULT ComReg::RegisterProtocolSource( | |
| const wchar_t* protocol, | |
| const wchar_t* ext, | |
| const GUID& filter) | |
| { | |
| if (protocol == 0) | |
| return E_INVALIDARG; | |
| if (ext == 0) | |
| return E_INVALIDARG; | |
| if (filter == GUID_NULL) | |
| return E_INVALIDARG; | |
| Registry::Key pk; //protocol | |
| LONG e = pk.open(HKEY_CLASSES_ROOT, protocol, KEY_READ | KEY_WRITE); | |
| if (e) | |
| return HRESULT_FROM_WIN32(e); | |
| Registry::Key ek; //extensions | |
| e = ek.open(pk, L"Extensions", KEY_READ | KEY_WRITE); | |
| if (e) | |
| return HRESULT_FROM_WIN32(e); | |
| wchar_t buf[guid_buflen]; | |
| const int n = StringFromGUID2(filter, buf, guid_buflen); | |
| assert(n == guid_buflen); | |
| n; | |
| e = ek.set(ext, buf); | |
| if (e) | |
| return HRESULT_FROM_WIN32(e); | |
| return S_OK; | |
| } | |
| HRESULT ComReg::UnRegisterProtocolSource( | |
| const wchar_t* protocol, | |
| const wchar_t* ext, | |
| const GUID& filter) | |
| { | |
| if (protocol == 0) | |
| return E_INVALIDARG; | |
| if (ext == 0) | |
| return E_INVALIDARG; | |
| if (filter == GUID_NULL) | |
| return E_INVALIDARG; | |
| Registry::Key pk; //protocol | |
| LONG e = pk.open(HKEY_CLASSES_ROOT, protocol, KEY_READ | KEY_WRITE); | |
| if (e == ERROR_FILE_NOT_FOUND) | |
| return S_FALSE; | |
| if (e) | |
| return HRESULT_FROM_WIN32(e); | |
| Registry::Key ek; //extensions | |
| e = ek.open(pk, L"Extensions", KEY_READ | KEY_WRITE); | |
| if (e == ERROR_FILE_NOT_FOUND) | |
| return S_FALSE; | |
| if (e) | |
| return HRESULT_FROM_WIN32(e); | |
| wstring val; | |
| e = ek.query(ext, val); | |
| if (e == ERROR_FILE_NOT_FOUND) | |
| return S_FALSE; | |
| if (e) | |
| return HRESULT_FROM_WIN32(e); | |
| GUID guid; | |
| const HRESULT hr = ::CLSIDFromString(val.c_str(), &guid); | |
| if (FAILED(hr)) | |
| return S_FALSE; | |
| if (guid != filter) | |
| return S_FALSE; | |
| e = ::RegDeleteValue(ek, ext); | |
| if (e) | |
| return HRESULT_FROM_WIN32(e); | |
| return S_OK; | |
| } | |