1+ /* ***************************** Module Header ******************************\
2+ Module Name: Reg.cpp
3+ Project: CppShellExtContextMenuHandler
4+ Copyright (c) Microsoft Corporation.
5+
6+ The file implements the reusable helper functions to register and unregister
7+ in-process COM components and shell context menu handlers in the registry.
8+
9+ RegisterInprocServer - register the in-process component in the registry.
10+ UnregisterInprocServer - unregister the in-process component in the registry.
11+ RegisterShellExtContextMenuHandler - register the context menu handler.
12+ UnregisterShellExtContextMenuHandler - unregister the context menu handler.
13+
14+ This source is subject to the Microsoft Public License.
15+ See http://www.microsoft.com/opensource/licenses.mspx#Ms-PL.
16+ All other rights reserved.
17+
18+ THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
19+ EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
20+ WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
21+ \***************************************************************************/
22+
23+ #include " Reg.h"
24+ #include < strsafe.h>
25+ #include < Shlwapi.h>
26+
27+
28+ #pragma region Registry Helper Functions
29+
30+ //
31+ // FUNCTION: SetHKCRRegistryKeyAndValue
32+ //
33+ // PURPOSE: The function creates a HKCR registry key and sets the specified
34+ // registry value.
35+ //
36+ // PARAMETERS:
37+ // * pszSubKey - specifies the registry key under HKCR. If the key does not
38+ // exist, the function will create the registry key.
39+ // * pszValueName - specifies the registry value to be set. If pszValueName
40+ // is NULL, the function will set the default value.
41+ // * pszData - specifies the string data of the registry value.
42+ //
43+ // RETURN VALUE:
44+ // If the function succeeds, it returns S_OK. Otherwise, it returns an
45+ // HRESULT error code.
46+ //
47+ HRESULT SetHKCRRegistryKeyAndValue (PCWSTR pszSubKey, PCWSTR pszValueName,
48+ PCWSTR pszData)
49+ {
50+ HRESULT hr;
51+ HKEY hKey = NULL ;
52+
53+ // Creates the specified registry key. If the key already exists, the
54+ // function opens it.
55+ hr = HRESULT_FROM_WIN32 (RegCreateKeyEx (HKEY_CLASSES_ROOT, pszSubKey, 0 ,
56+ NULL , REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL , &hKey, NULL ));
57+
58+ if (SUCCEEDED (hr))
59+ {
60+ if (pszData != NULL )
61+ {
62+ // Set the specified value of the key.
63+ DWORD cbData = lstrlen (pszData) * sizeof (*pszData);
64+ hr = HRESULT_FROM_WIN32 (RegSetValueEx (hKey, pszValueName, 0 ,
65+ REG_SZ, reinterpret_cast <const BYTE *>(pszData), cbData));
66+ }
67+
68+ RegCloseKey (hKey);
69+ }
70+
71+ return hr;
72+ }
73+
74+
75+ //
76+ // FUNCTION: GetHKCRRegistryKeyAndValue
77+ //
78+ // PURPOSE: The function opens a HKCR registry key and gets the data for the
79+ // specified registry value name.
80+ //
81+ // PARAMETERS:
82+ // * pszSubKey - specifies the registry key under HKCR. If the key does not
83+ // exist, the function returns an error.
84+ // * pszValueName - specifies the registry value to be retrieved. If
85+ // pszValueName is NULL, the function will get the default value.
86+ // * pszData - a pointer to a buffer that receives the value's string data.
87+ // * cbData - specifies the size of the buffer in bytes.
88+ //
89+ // RETURN VALUE:
90+ // If the function succeeds, it returns S_OK. Otherwise, it returns an
91+ // HRESULT error code. For example, if the specified registry key does not
92+ // exist or the data for the specified value name was not set, the function
93+ // returns COR_E_FILENOTFOUND (0x80070002).
94+ //
95+ HRESULT GetHKCRRegistryKeyAndValue (PCWSTR pszSubKey, PCWSTR pszValueName,
96+ PWSTR pszData, DWORD cbData)
97+ {
98+ HRESULT hr;
99+ HKEY hKey = NULL ;
100+
101+ // Try to open the specified registry key.
102+ hr = HRESULT_FROM_WIN32 (RegOpenKeyEx (HKEY_CLASSES_ROOT, pszSubKey, 0 ,
103+ KEY_READ, &hKey));
104+
105+ if (SUCCEEDED (hr))
106+ {
107+ // Get the data for the specified value name.
108+ hr = HRESULT_FROM_WIN32 (RegQueryValueEx (hKey, pszValueName, NULL ,
109+ NULL , reinterpret_cast <LPBYTE>(pszData), &cbData));
110+
111+ RegCloseKey (hKey);
112+ }
113+
114+ return hr;
115+ }
116+
117+ #pragma endregion
118+
119+
120+ //
121+ // FUNCTION: RegisterInprocServer
122+ //
123+ // PURPOSE: Register the in-process component in the registry.
124+ //
125+ // PARAMETERS:
126+ // * pszModule - Path of the module that contains the component
127+ // * clsid - Class ID of the component
128+ // * pszFriendlyName - Friendly name
129+ // * pszThreadModel - Threading model
130+ //
131+ // NOTE: The function creates the HKCR\CLSID\{<CLSID>} key in the registry.
132+ //
133+ // HKCR
134+ // {
135+ // NoRemove CLSID
136+ // {
137+ // ForceRemove {<CLSID>} = s '<Friendly Name>'
138+ // {
139+ // InprocServer32 = s '%MODULE%'
140+ // {
141+ // val ThreadingModel = s '<Thread Model>'
142+ // }
143+ // }
144+ // }
145+ // }
146+ //
147+ HRESULT RegisterInprocServer (PCWSTR pszModule, const CLSID& clsid,
148+ PCWSTR pszFriendlyName, PCWSTR pszThreadModel)
149+ {
150+ if (pszModule == NULL || pszThreadModel == NULL )
151+ {
152+ return E_INVALIDARG;
153+ }
154+
155+ HRESULT hr;
156+
157+ wchar_t szCLSID[MAX_PATH];
158+ StringFromGUID2 (clsid, szCLSID, ARRAYSIZE (szCLSID));
159+
160+ wchar_t szSubkey[MAX_PATH];
161+
162+ // Create the HKCR\CLSID\{<CLSID>} key.
163+ hr = StringCchPrintf (szSubkey, ARRAYSIZE (szSubkey), L" CLSID\\ %s" , szCLSID);
164+ if (SUCCEEDED (hr))
165+ {
166+ hr = SetHKCRRegistryKeyAndValue (szSubkey, NULL , pszFriendlyName);
167+
168+ // Create the HKCR\CLSID\{<CLSID>}\InprocServer32 key.
169+ if (SUCCEEDED (hr))
170+ {
171+ hr = StringCchPrintf (szSubkey, ARRAYSIZE (szSubkey),
172+ L" CLSID\\ %s\\ InprocServer32" , szCLSID);
173+ if (SUCCEEDED (hr))
174+ {
175+ // Set the default value of the InprocServer32 key to the
176+ // path of the COM module.
177+ hr = SetHKCRRegistryKeyAndValue (szSubkey, NULL , pszModule);
178+ if (SUCCEEDED (hr))
179+ {
180+ // Set the threading model of the component.
181+ hr = SetHKCRRegistryKeyAndValue (szSubkey,
182+ L" ThreadingModel" , pszThreadModel);
183+ }
184+ }
185+ }
186+ }
187+
188+ return hr;
189+ }
190+
191+
192+ //
193+ // FUNCTION: UnregisterInprocServer
194+ //
195+ // PURPOSE: Unegister the in-process component in the registry.
196+ //
197+ // PARAMETERS:
198+ // * clsid - Class ID of the component
199+ //
200+ // NOTE: The function deletes the HKCR\CLSID\{<CLSID>} key in the registry.
201+ //
202+ HRESULT UnregisterInprocServer (const CLSID& clsid)
203+ {
204+ HRESULT hr = S_OK;
205+
206+ wchar_t szCLSID[MAX_PATH];
207+ StringFromGUID2 (clsid, szCLSID, ARRAYSIZE (szCLSID));
208+
209+ wchar_t szSubkey[MAX_PATH];
210+
211+ // Delete the HKCR\CLSID\{<CLSID>} key.
212+ hr = StringCchPrintf (szSubkey, ARRAYSIZE (szSubkey), L" CLSID\\ %s" , szCLSID);
213+ if (SUCCEEDED (hr))
214+ {
215+ hr = HRESULT_FROM_WIN32 (SHDeleteKey (HKEY_CLASSES_ROOT, szSubkey));
216+ }
217+
218+ return hr;
219+ }
220+
221+
222+ //
223+ // FUNCTION: RegisterShellExtContextMenuHandler
224+ //
225+ // PURPOSE: Register the context menu handler.
226+ //
227+ // PARAMETERS:
228+ // * pszFileType - The file type that the context menu handler is
229+ // associated with. For example, '*' means all file types; '.txt' means
230+ // all .txt files. The parameter must not be NULL.
231+ // * clsid - Class ID of the component
232+ // * pszFriendlyName - Friendly name
233+ //
234+ // NOTE: The function creates the following key in the registry.
235+ //
236+ // HKCR
237+ // {
238+ // NoRemove <File Type>
239+ // {
240+ // NoRemove shellex
241+ // {
242+ // NoRemove ContextMenuHandlers
243+ // {
244+ // {<CLSID>} = s '<Friendly Name>'
245+ // }
246+ // }
247+ // }
248+ // }
249+ //
250+ HRESULT RegisterShellExtContextMenuHandler (
251+ PCWSTR pszFileType, const CLSID& clsid, PCWSTR pszFriendlyName)
252+ {
253+ if (pszFileType == NULL )
254+ {
255+ return E_INVALIDARG;
256+ }
257+
258+ HRESULT hr;
259+
260+ wchar_t szCLSID[MAX_PATH];
261+ StringFromGUID2 (clsid, szCLSID, ARRAYSIZE (szCLSID));
262+
263+ wchar_t szSubkey[MAX_PATH];
264+
265+ // If pszFileType starts with '.', try to read the default value of the
266+ // HKCR\<File Type> key which contains the ProgID to which the file type
267+ // is linked.
268+ if (*pszFileType == L' .' )
269+ {
270+ wchar_t szDefaultVal[260 ];
271+ hr = GetHKCRRegistryKeyAndValue (pszFileType, NULL , szDefaultVal,
272+ sizeof (szDefaultVal));
273+
274+ // If the key exists and its default value is not empty, use the
275+ // ProgID as the file type.
276+ if (SUCCEEDED (hr) && szDefaultVal[0 ] != L' \0 ' )
277+ {
278+ pszFileType = szDefaultVal;
279+ }
280+ }
281+
282+ // Create the key HKCR\<File Type>\shellex\ContextMenuHandlers\{<CLSID>}
283+ hr = StringCchPrintf (szSubkey, ARRAYSIZE (szSubkey),
284+ L" %s\\ shellex\\ ContextMenuHandlers\\ %s" , pszFileType, szCLSID);
285+ if (SUCCEEDED (hr))
286+ {
287+ // Set the default value of the key.
288+ hr = SetHKCRRegistryKeyAndValue (szSubkey, NULL , pszFriendlyName);
289+ }
290+
291+ return hr;
292+ }
293+
294+
295+ //
296+ // FUNCTION: UnregisterShellExtContextMenuHandler
297+ //
298+ // PURPOSE: Unregister the context menu handler.
299+ //
300+ // PARAMETERS:
301+ // * pszFileType - The file type that the context menu handler is
302+ // associated with. For example, '*' means all file types; '.txt' means
303+ // all .txt files. The parameter must not be NULL.
304+ // * clsid - Class ID of the component
305+ //
306+ // NOTE: The function removes the {<CLSID>} key under
307+ // HKCR\<File Type>\shellex\ContextMenuHandlers in the registry.
308+ //
309+ HRESULT UnregisterShellExtContextMenuHandler (
310+ PCWSTR pszFileType, const CLSID& clsid)
311+ {
312+ if (pszFileType == NULL )
313+ {
314+ return E_INVALIDARG;
315+ }
316+
317+ HRESULT hr;
318+
319+ wchar_t szCLSID[MAX_PATH];
320+ StringFromGUID2 (clsid, szCLSID, ARRAYSIZE (szCLSID));
321+
322+ wchar_t szSubkey[MAX_PATH];
323+
324+ // If pszFileType starts with '.', try to read the default value of the
325+ // HKCR\<File Type> key which contains the ProgID to which the file type
326+ // is linked.
327+ if (*pszFileType == L' .' )
328+ {
329+ wchar_t szDefaultVal[260 ];
330+ hr = GetHKCRRegistryKeyAndValue (pszFileType, NULL , szDefaultVal,
331+ sizeof (szDefaultVal));
332+
333+ // If the key exists and its default value is not empty, use the
334+ // ProgID as the file type.
335+ if (SUCCEEDED (hr) && szDefaultVal[0 ] != L' \0 ' )
336+ {
337+ pszFileType = szDefaultVal;
338+ }
339+ }
340+
341+ // Remove the HKCR\<File Type>\shellex\ContextMenuHandlers\{<CLSID>} key.
342+ hr = StringCchPrintf (szSubkey, ARRAYSIZE (szSubkey),
343+ L" %s\\ shellex\\ ContextMenuHandlers\\ %s" , pszFileType, szCLSID);
344+ if (SUCCEEDED (hr))
345+ {
346+ hr = HRESULT_FROM_WIN32 (SHDeleteKey (HKEY_CLASSES_ROOT, szSubkey));
347+ }
348+
349+ return hr;
350+ }
0 commit comments