Skip to content

Commit 56f1420

Browse files
committed
Added checks if TypeLib is registered on system or for current user. If TyleLib is not already registered, then we assume that we can silence error 0x8002801c (TYPE_E_REGISTRYACCESS).
1 parent 00add9a commit 56f1420

File tree

3 files changed

+101
-21
lines changed

3 files changed

+101
-21
lines changed

src/shellextension/TypeLibHelper.cpp

Lines changed: 61 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,49 @@
44
#include <strsafe.h> // for StringCchPrintf()
55

66
using namespace ATL;
7-
extern HRESULT GetHKCRRegistryKeyAndValue(PCWSTR pszSubKey, PCWSTR pszValueName, PWSTR pszData, DWORD cbData); // from Reg.cpp
7+
8+
//
9+
// FUNCTION: GetHKEYRegistryKeyAndValue
10+
//
11+
// PURPOSE: The function opens the given HKEY (HKCR, HKCU, etc) registry key and gets the data for the
12+
// specified registry value name.
13+
//
14+
// PARAMETERS:
15+
// * hRootKey - One of the reserved root key handles. For example:
16+
// HKEY_CLASSES_ROOT, HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE, HKEY_USERS or
17+
// * pszSubKey - specifies the registry key under HKCR. If the key does not
18+
// exist, the function returns an error.
19+
// * pszValueName - specifies the registry value to be retrieved. If
20+
// pszValueName is NULL, the function will get the default value.
21+
// * pszData - a pointer to a buffer that receives the value's string data.
22+
// * cbData - specifies the size of the buffer in bytes.
23+
//
24+
// RETURN VALUE:
25+
// If the function succeeds, it returns S_OK. Otherwise, it returns an
26+
// HRESULT error code. For example, if the specified registry key does not
27+
// exist or the data for the specified value name was not set, the function
28+
// returns COR_E_FILENOTFOUND (0x80070002).
29+
//
30+
HRESULT GetHKEYRegistryKeyAndValue(HKEY hRootKey, PCWSTR pszSubKey, PCWSTR pszValueName, PWSTR pszData, DWORD cbData)
31+
{
32+
HRESULT hr;
33+
HKEY hKey = NULL;
34+
35+
// Try to open the specified registry key.
36+
hr = HRESULT_FROM_WIN32(RegOpenKeyEx(hRootKey, pszSubKey, 0,
37+
KEY_READ, &hKey));
38+
39+
if (SUCCEEDED(hr))
40+
{
41+
// Get the data for the specified value name.
42+
hr = HRESULT_FROM_WIN32(RegQueryValueEx(hKey, pszValueName, NULL,
43+
NULL, reinterpret_cast<LPBYTE>(pszData), &cbData));
44+
45+
RegCloseKey(hKey);
46+
}
47+
48+
return hr;
49+
}
850

951
HRESULT GetTypeLibGuid(_In_ HINSTANCE hInstTypeLib, _In_opt_z_ LPCOLESTR lpszIndex, GUID& guid)
1052
{
@@ -53,7 +95,7 @@ HRESULT IsTypeLibRegisteredOnSystem(const GUID& guid, PCWSTR szVersion)
5395
return hr;
5496
}
5597

56-
HRESULT IsTypeLibRegisteredOnSystem(_In_ LPTLIBATTR pTLibAttr)
98+
HRESULT IsTypeLibRegisteredUnderKey(HKEY hRootKey, _In_ const LPTLIBATTR pTLibAttr)
5799
{
58100
if (NULL == pTLibAttr)
59101
return E_INVALIDARG;
@@ -84,15 +126,15 @@ HRESULT IsTypeLibRegisteredOnSystem(_In_ LPTLIBATTR pTLibAttr)
84126
return HRESULT_FROM_WIN32(ERROR_INVALID_FLAGS);
85127
};
86128

87-
// Check for the "HKCR\TypeLib\{guid}\{version}" key.
129+
// Check for the "HKEY_CLASSES_ROOT\TypeLib\{guid}\{version}" key.
88130
wchar_t szSubkey[MAX_PATH];
89131
hr = StringCchPrintf(szSubkey, ARRAYSIZE(szSubkey), L"TypeLib\\%s\\%s", szGUID, szVersion);
90132
if (FAILED(hr))
91133
return hr;
92134

93135
// Get the TypeLib name
94136
wchar_t szTypeLibName[MAX_PATH];
95-
hr = GetHKCRRegistryKeyAndValue(szSubkey, nullptr, szTypeLibName, sizeof(szTypeLibName));
137+
hr = GetHKEYRegistryKeyAndValue(hRootKey, szSubkey, nullptr, szTypeLibName, sizeof(szTypeLibName));
96138
if (FAILED(hr))
97139
{
98140
if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
@@ -104,14 +146,14 @@ HRESULT IsTypeLibRegisteredOnSystem(_In_ LPTLIBATTR pTLibAttr)
104146
if (szTypeLibName[0] == L'\0')
105147
return S_FALSE;
106148

107-
// Check for the "HKCR\TypeLib\{guid}\{version}\0\{syskind}" key.
149+
// Check for the "HKEY_CLASSES_ROOT\TypeLib\{guid}\{version}\0\{syskind}" key.
108150
hr = StringCchPrintf(szSubkey, ARRAYSIZE(szSubkey), L"TypeLib\\%s\\%s\\0\\%s", szGUID, szVersion, szSysKind);
109151
if (FAILED(hr))
110152
return hr;
111153

112154
// Get the TypeLib dll path
113155
wchar_t szDllPath[MAX_PATH];
114-
hr = GetHKCRRegistryKeyAndValue(szSubkey, nullptr, szDllPath, sizeof(szDllPath));
156+
hr = GetHKEYRegistryKeyAndValue(hRootKey, szSubkey, nullptr, szDllPath, sizeof(szDllPath));
115157
if (FAILED(hr))
116158
{
117159
if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
@@ -138,4 +180,16 @@ HRESULT IsTypeLibRegisteredOnSystem(_In_ LPTLIBATTR pTLibAttr)
138180
// return S_FALSE;
139181

140182
return S_OK;
141-
}
183+
}
184+
185+
HRESULT IsTypeLibRegisteredOnSystem(_In_ const LPTLIBATTR pTLibAttr)
186+
{
187+
HRESULT hr = IsTypeLibRegisteredUnderKey(HKEY_CLASSES_ROOT, pTLibAttr);
188+
return hr;
189+
}
190+
191+
HRESULT IsTypeLibRegisteredForCurrentUser(_In_ const LPTLIBATTR pTLibAttr)
192+
{
193+
HRESULT hr = IsTypeLibRegisteredUnderKey(HKEY_CURRENT_USER, pTLibAttr);
194+
return hr;
195+
}

src/shellextension/TypeLibHelper.h

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,4 +47,18 @@ HRESULT IsTypeLibRegisteredOnSystem(const GUID& guid, PCWSTR szVersion);
4747
/// </remarks>
4848
/// <param name="pTLibAttr">A pointer to the typelib's attributes.</param>
4949
/// <returns>Returns S_OK if the typelib is registered on system. Returns S_FALSE if the typelib is not registered on system. Returns an HRESULT matching an error code otherwise.</returns>
50-
HRESULT IsTypeLibRegisteredOnSystem(_In_ LPTLIBATTR pTLibAttr);
50+
HRESULT IsTypeLibRegisteredOnSystem(_In_ const LPTLIBATTR pTLibAttr);
51+
52+
/// <summary>
53+
/// Check if the given typelib is registered for the current user.
54+
/// </summary>
55+
/// <remarks>
56+
/// The following registry keys and values are present for a registered typelib:
57+
/// [HKEY_CURRENT_USER\TypeLib\{guid}\{version}]
58+
/// @ = "MyClassNameLib"
59+
/// [HKEY_CURRENT_USER\TypeLib\{guid}\{version}\0\win64]
60+
/// @ = "Z:\\path\\to\\current\\file.dll"
61+
/// </remarks>
62+
/// <param name="pTLibAttr">A pointer to the typelib's attributes.</param>
63+
/// <returns>Returns S_OK if the typelib is registered on system. Returns S_FALSE if the typelib is not registered on system. Returns an HRESULT matching an error code otherwise.</returns>
64+
HRESULT IsTypeLibRegisteredForCurrentUser(_In_ const LPTLIBATTR pTLibAttr);

src/shellextension/dllmain.cpp

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -143,24 +143,36 @@ STDAPI DllUnregisterServer(void)
143143
// See issue #148 for details.
144144
// Is this failure because the TypeLib is not registered?
145145

146+
HRESULT hr2 = S_OK;
147+
146148
// Get typelib attributes
147149
TLIBATTR sTLibAttr;
148150
ZeroMemory(&sTLibAttr, sizeof(TLIBATTR));
149-
if (FAILED(GetTypeLibAttribute(_AtlComModule.m_hInstTypeLib, 0, &sTLibAttr)))
151+
hr2 = GetTypeLibAttribute(_AtlComModule.m_hInstTypeLib, 0, &sTLibAttr);
152+
if (FAILED(hr2))
150153
return hr; // return original error
151154

152-
// Silence the original error only if the TypeLib is not registered on system.
153-
HRESULT hr2 = IsTypeLibRegisteredOnSystem(&sTLibAttr);
154-
if (SUCCEEDED(hr2) && hr2 == S_FALSE)
155-
{
156-
// We could assume the error is because the typelib is not registered.
157-
// To be certain, we should register the typelib and retry the unregistration:
158-
// _AtlModule.DllRegisterServer(); // don't care about the actual result
159-
// hr = _AtlModule.DllUnregisterServer();
160-
// but that could mess up the system if another software is listening for new typelib registrations events.
161-
// So we just overrides the original result.
162-
return S_OK;
163-
}
155+
// Check if typelib is registered on system.
156+
hr2 = IsTypeLibRegisteredOnSystem(&sTLibAttr);
157+
if (FAILED(hr2))
158+
return hr; // We don't know if typelib is registered or not. Return original error.
159+
if (hr2 == S_OK)
160+
return hr; // Yes, the typelib is registered, hr is a legit error.
161+
162+
// Check if typelib is registered for current user.
163+
hr2 = IsTypeLibRegisteredForCurrentUser(&sTLibAttr);
164+
if (FAILED(hr2))
165+
return hr; // We don't know if typelib is registered or not. Return original error.
166+
if (hr2 == S_OK)
167+
return hr; // Yes, the typelib is registered, hr is a legit error.
168+
169+
// At this point, assume error 0x8002801c (TYPE_E_REGISTRYACCESS) is because the typelib is not registered.
170+
// To be certain, we should register the typelib and retry the unregistration:
171+
// _AtlModule.DllRegisterServer(); // don't care about the actual result
172+
// hr = _AtlModule.DllUnregisterServer();
173+
// but that could mess up the system if another software is listening for new typelib registrations events.
174+
// So we just silence the original error.
175+
return S_OK;
164176
}
165177

166178
if (SUCCEEDED(hr))

0 commit comments

Comments
 (0)