blob: 82e83fe9d534372f853f1c5ce8714ee3a8e89f0e [file] [log] [blame]
// 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.h"
#include <malloc.h>
#include <cassert>
#include <sstream>
#include "registry.h"
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)
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;
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.h
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.h
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);
// TYPE_E_REGISTRYACCESS is returned when the type lib was not registered.
// Since DShow filters are supposed to call DllUnregisterServer() from
// DllRegisterServer(), and DllUnregisterServer() must (attempt to) unregister
// type libraries, suppress this error because it's going to be returned every
// time a filter is registered for the first time on a system.
if (hr == TYPE_E_REGISTRYACCESS)
hr = S_FALSE;
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";
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);
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;
}