Reactos
at master 428 lines 11 kB view raw
1/* 2 * PROJECT: ReactOS CTF 3 * LICENSE: LGPL-2.0-or-later (https://spdx.org/licenses/LGPL-2.0-or-later) 4 * PURPOSE: ITfCategoryMgr implementation 5 * COPYRIGHT: Copyright 2009 Aric Stewart, CodeWeavers 6 * Copyright 2025 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com> 7 */ 8 9#include "precomp.h" 10 11#include <wine/debug.h> 12WINE_DEFAULT_DEBUG_CHANNEL(msctf); 13 14//////////////////////////////////////////////////////////////////////////// 15 16class CCategoryMgr 17 : public ITfCategoryMgr 18{ 19public: 20 CCategoryMgr(); 21 virtual ~CCategoryMgr(); 22 23 // ** IUnknown methods ** 24 STDMETHODIMP QueryInterface(REFIID riid, void **ppvObj) override; 25 STDMETHODIMP_(ULONG) AddRef() override; 26 STDMETHODIMP_(ULONG) Release() override; 27 28 // ** ITfCategoryMgr methods ** 29 STDMETHODIMP RegisterCategory( 30 _In_ REFCLSID rclsid, 31 _In_ REFGUID rcatid, 32 _In_ REFGUID rguid) override; 33 STDMETHODIMP UnregisterCategory( 34 _In_ REFCLSID rclsid, 35 _In_ REFGUID rcatid, 36 _In_ REFGUID rguid) override; 37 STDMETHODIMP EnumCategoriesInItem( 38 _In_ REFGUID rguid, 39 _Out_ IEnumGUID **ppEnum) override; 40 STDMETHODIMP EnumItemsInCategory( 41 _In_ REFGUID rcatid, 42 _Out_ IEnumGUID **ppEnum) override; 43 STDMETHODIMP FindClosestCategory( 44 _In_ REFGUID rguid, 45 _Out_ GUID *pcatid, 46 _In_ const GUID **ppcatidList, 47 _In_ ULONG ulCount) override; 48 STDMETHODIMP RegisterGUIDDescription( 49 _In_ REFCLSID rclsid, 50 _In_ REFGUID rguid, 51 _In_ const WCHAR *pchDesc, 52 _In_ ULONG cch) override; 53 STDMETHODIMP UnregisterGUIDDescription( 54 _In_ REFCLSID rclsid, 55 _In_ REFGUID rguid) override; 56 STDMETHODIMP GetGUIDDescription( 57 _In_ REFGUID rguid, 58 _Out_ BSTR *pbstrDesc) override; 59 STDMETHODIMP RegisterGUIDDWORD( 60 _In_ REFCLSID rclsid, 61 _In_ REFGUID rguid, 62 _In_ DWORD dw) override; 63 STDMETHODIMP UnregisterGUIDDWORD( 64 _In_ REFCLSID rclsid, 65 _In_ REFGUID rguid) override; 66 STDMETHODIMP GetGUIDDWORD( 67 _In_ REFGUID rguid, 68 _Out_ DWORD *pdw) override; 69 STDMETHODIMP RegisterGUID( 70 _In_ REFGUID rguid, 71 _Out_ TfGuidAtom *pguidatom) override; 72 STDMETHODIMP GetGUID( 73 _In_ TfGuidAtom guidatom, 74 _Out_ GUID *pguid) override; 75 STDMETHODIMP IsEqualTfGuidAtom( 76 _In_ TfGuidAtom guidatom, 77 _In_ REFGUID rguid, 78 _Out_ BOOL *pfEqual) override; 79 80protected: 81 LONG m_cRefs; 82}; 83 84//////////////////////////////////////////////////////////////////////////// 85 86CCategoryMgr::CCategoryMgr() 87 : m_cRefs(1) 88{ 89} 90 91CCategoryMgr::~CCategoryMgr() 92{ 93 TRACE("destroying %p\n", this); 94} 95 96STDMETHODIMP CCategoryMgr::QueryInterface(REFIID riid, void **ppvObj) 97{ 98 if (!ppvObj) 99 return E_INVALIDARG; 100 101 *ppvObj = NULL; 102 103 if (riid == IID_IUnknown || riid == IID_ITfCategoryMgr) 104 *ppvObj = this; 105 106 if (*ppvObj) 107 { 108 AddRef(); 109 return S_OK; 110 } 111 112 WARN("unsupported interface: %s\n", debugstr_guid(&riid)); 113 return E_NOINTERFACE; 114} 115 116STDMETHODIMP_(ULONG) CCategoryMgr::AddRef() 117{ 118 return ::InterlockedIncrement(&m_cRefs); 119} 120 121STDMETHODIMP_(ULONG) CCategoryMgr::Release() 122{ 123 ULONG ret = ::InterlockedDecrement(&m_cRefs); 124 if (!ret) 125 delete this; 126 return ret; 127} 128 129STDMETHODIMP CCategoryMgr::RegisterCategory( 130 _In_ REFCLSID rclsid, 131 _In_ REFGUID rcatid, 132 _In_ REFGUID rguid) 133{ 134 WCHAR szFullKey[110], szClsid[39], szCatid[39], szGuid[39]; 135 HKEY hTipKey = NULL, hCatKey = NULL, hItemKey = NULL; 136 LSTATUS error; 137 HRESULT hr = E_FAIL; 138 139 TRACE("%p -> (%s, %s, %s)\n", this, debugstr_guid(&rclsid), debugstr_guid(&rcatid), 140 debugstr_guid(&rguid)); 141 142 StringFromGUID2(rclsid, szClsid, _countof(szClsid)); 143 StringFromGUID2(rcatid, szCatid, _countof(szCatid)); 144 StringFromGUID2(rguid, szGuid, _countof(szGuid)); 145 146 StringCchPrintfW(szFullKey, _countof(szFullKey), L"%s\\%s", szwSystemTIPKey, szClsid); 147 error = RegOpenKeyExW(HKEY_LOCAL_MACHINE, szFullKey, 0, KEY_READ | KEY_WRITE, &hTipKey); 148 if (error != ERROR_SUCCESS) 149 return E_FAIL; 150 151 StringCchPrintfW(szFullKey, _countof(szFullKey), L"Category\\Category\\%s\\%s", szCatid, szGuid); 152 error = RegCreateKeyExW(hTipKey, szFullKey, 0, NULL, 0, KEY_READ | KEY_WRITE, NULL, 153 &hCatKey, NULL); 154 if (error == ERROR_SUCCESS) 155 { 156 RegCloseKey(hCatKey); 157 158 StringCchPrintfW(szFullKey, _countof(szFullKey), L"Category\\Item\\%s\\%s", szGuid, szCatid); 159 error = RegCreateKeyExW(hTipKey, szFullKey, 0, NULL, 0, KEY_READ | KEY_WRITE, NULL, 160 &hItemKey, NULL); 161 if (error == ERROR_SUCCESS) 162 { 163 RegCloseKey(hItemKey); 164 hr = S_OK; 165 } 166 } 167 168 RegCloseKey(hTipKey); 169 return hr; 170} 171 172STDMETHODIMP CCategoryMgr::UnregisterCategory( 173 _In_ REFCLSID rclsid, 174 _In_ REFGUID rcatid, 175 _In_ REFGUID rguid) 176{ 177 WCHAR szFullKey[110], szClsid[39], szCatid[39], szGuid[39]; 178 HKEY hTipKey = NULL; 179 LSTATUS error; 180 181 TRACE("%p -> (%s %s %s)\n", this, debugstr_guid(&rclsid), debugstr_guid(&rcatid), 182 debugstr_guid(&rguid)); 183 184 StringFromGUID2(rclsid, szClsid, _countof(szClsid)); 185 StringFromGUID2(rcatid, szCatid, _countof(szCatid)); 186 StringFromGUID2(rguid, szGuid, _countof(szGuid)); 187 188 StringCchPrintfW(szFullKey, _countof(szFullKey), L"%s\\%s", szwSystemTIPKey, szClsid); 189 error = RegOpenKeyExW(HKEY_LOCAL_MACHINE, szFullKey, 0, KEY_READ | KEY_WRITE, &hTipKey); 190 if (error != ERROR_SUCCESS) 191 return E_FAIL; 192 193 StringCchPrintfW(szFullKey, _countof(szFullKey), L"Category\\Category\\%s\\%s", szCatid, szGuid); 194 RegDeleteTreeW(hTipKey, szFullKey); 195 196 StringCchPrintfW(szFullKey, _countof(szFullKey), L"Category\\Item\\%s\\%s", szGuid, szCatid); 197 RegDeleteTreeW(hTipKey, szFullKey); 198 199 RegCloseKey(hTipKey); 200 return S_OK; 201} 202 203STDMETHODIMP CCategoryMgr::EnumCategoriesInItem( 204 _In_ REFGUID rguid, 205 _Out_ IEnumGUID **ppEnum) 206{ 207 FIXME("STUB:(%p)\n", this); 208 return E_NOTIMPL; 209} 210 211STDMETHODIMP CCategoryMgr::EnumItemsInCategory( 212 _In_ REFGUID rcatid, 213 _Out_ IEnumGUID **ppEnum) 214{ 215 FIXME("STUB:(%p)\n", this); 216 return E_NOTIMPL; 217} 218 219STDMETHODIMP CCategoryMgr::FindClosestCategory( 220 _In_ REFGUID rguid, 221 _Out_ GUID *pcatid, 222 _In_ const GUID **ppcatidList, 223 _In_ ULONG ulCount) 224{ 225 WCHAR szFullKey[120], szGuid[39]; 226 HKEY hKey = NULL; 227 HRESULT hr = S_FALSE; 228 DWORD dwIndex = 0; 229 LSTATUS error; 230 231 TRACE("(%p)\n", this); 232 233 if (!pcatid || (ulCount && !ppcatidList)) 234 return E_INVALIDARG; 235 236 StringFromGUID2(rguid, szGuid, _countof(szGuid)); 237 StringCchPrintfW(szFullKey, _countof(szFullKey), L"%s\\%s\\Category\\Item\\%s", szwSystemTIPKey, szGuid, szGuid); 238 *pcatid = GUID_NULL; 239 240 error = RegOpenKeyExW(HKEY_LOCAL_MACHINE, szFullKey, 0, KEY_READ, &hKey); 241 if (error != ERROR_SUCCESS) 242 return S_FALSE; 243 244 // Enumerate subkeys to find the closest category 245 while (TRUE) 246 { 247 WCHAR szCatidName[39]; 248 DWORD cchCatidName = _countof(szCatidName); 249 GUID currentCatid; 250 251 error = RegEnumKeyExW(hKey, dwIndex, szCatidName, &cchCatidName, NULL, NULL, NULL, NULL); 252 if (error != ERROR_SUCCESS || error == ERROR_NO_MORE_ITEMS) 253 break; 254 255 dwIndex++; 256 257 HRESULT hr2 = CLSIDFromString(szCatidName, &currentCatid); 258 if (FAILED(hr2)) 259 continue; // Skip invalid GUID strings 260 261 if (ulCount <= 0) 262 { 263 *pcatid = currentCatid; 264 hr = S_OK; // Found a category 265 break; 266 } 267 268 // If a list of categories is provided, check if the current one is in the list 269 BOOL bFound = FALSE; 270 for (ULONG j = 0; j < ulCount; j++) 271 { 272 if (currentCatid == *ppcatidList[j]) 273 { 274 bFound = TRUE; 275 *pcatid = currentCatid; 276 hr = S_OK; // Found a matching category 277 break; 278 } 279 } 280 if (bFound) 281 break; // Found and matched, so stop searching 282 } 283 284 RegCloseKey(hKey); 285 return hr; 286} 287 288STDMETHODIMP CCategoryMgr::RegisterGUIDDescription( 289 _In_ REFCLSID rclsid, 290 _In_ REFGUID rguid, 291 _In_ const WCHAR *pchDesc, 292 _In_ ULONG cch) 293{ 294 FIXME("STUB:(%p)\n", this); 295 return E_NOTIMPL; 296} 297 298STDMETHODIMP CCategoryMgr::UnregisterGUIDDescription( 299 _In_ REFCLSID rclsid, 300 _In_ REFGUID rguid) 301{ 302 FIXME("STUB:(%p)\n", this); 303 return E_NOTIMPL; 304} 305 306STDMETHODIMP CCategoryMgr::GetGUIDDescription( 307 _In_ REFGUID rguid, 308 _Out_ BSTR *pbstrDesc) 309{ 310 FIXME("STUB:(%p)\n", this); 311 return E_NOTIMPL; 312} 313 314STDMETHODIMP CCategoryMgr::RegisterGUIDDWORD( 315 _In_ REFCLSID rclsid, 316 _In_ REFGUID rguid, 317 _In_ DWORD dw) 318{ 319 FIXME("STUB:(%p)\n", this); 320 return E_NOTIMPL; 321} 322 323STDMETHODIMP CCategoryMgr::UnregisterGUIDDWORD( 324 _In_ REFCLSID rclsid, 325 _In_ REFGUID rguid) 326{ 327 FIXME("STUB:(%p)\n", this); 328 return E_NOTIMPL; 329} 330 331STDMETHODIMP CCategoryMgr::GetGUIDDWORD( 332 _In_ REFGUID rguid, 333 _Out_ DWORD *pdw) 334{ 335 FIXME("STUB:(%p)\n", this); 336 return E_NOTIMPL; 337} 338 339STDMETHODIMP CCategoryMgr::RegisterGUID( 340 _In_ REFGUID rguid, 341 _Out_ TfGuidAtom *pguidatom) 342{ 343 TRACE("%p -> (%s, %p)\n", this, debugstr_guid(&rguid), pguidatom); 344 345 if (!pguidatom) 346 return E_INVALIDARG; 347 348 DWORD dwCookieId = 0, dwEnumIndex = 0; 349 do 350 { 351 dwCookieId = enumerate_Cookie(COOKIE_MAGIC_GUIDATOM, &dwEnumIndex); 352 if (dwCookieId && rguid == *(const GUID *)get_Cookie_data(dwCookieId)) 353 { 354 *pguidatom = dwCookieId; 355 return S_OK; 356 } 357 } while (dwCookieId != 0); 358 359 GUID *pNewGuid = (GUID *)cicMemAlloc(sizeof(GUID)); 360 if (!pNewGuid) 361 return E_OUTOFMEMORY; 362 363 *pNewGuid = rguid; 364 365 dwCookieId = generate_Cookie(COOKIE_MAGIC_GUIDATOM, pNewGuid); 366 if (dwCookieId == 0) 367 { 368 cicMemFree(pNewGuid); 369 return E_FAIL; 370 } 371 372 *pguidatom = dwCookieId; 373 return S_OK; 374} 375 376STDMETHODIMP CCategoryMgr::GetGUID( 377 _In_ TfGuidAtom guidatom, 378 _Out_ GUID *pguid) 379{ 380 TRACE("%p -> (%d, %p)\n", this, guidatom, pguid); 381 382 if (!pguid) 383 return E_INVALIDARG; 384 385 *pguid = GUID_NULL; 386 387 if (get_Cookie_magic(guidatom) == COOKIE_MAGIC_GUIDATOM) 388 *pguid = *(const GUID *)get_Cookie_data(guidatom); 389 390 return S_OK; 391} 392 393STDMETHODIMP CCategoryMgr::IsEqualTfGuidAtom( 394 _In_ TfGuidAtom guidatom, 395 _In_ REFGUID rguid, 396 _Out_ BOOL *pfEqual) 397{ 398 TRACE("%p -> (%d %s %p)\n", this, guidatom, debugstr_guid(&rguid), pfEqual); 399 400 if (!pfEqual) 401 return E_INVALIDARG; 402 403 *pfEqual = FALSE; 404 if (get_Cookie_magic(guidatom) == COOKIE_MAGIC_GUIDATOM) 405 { 406 if (rguid == *(const GUID *)get_Cookie_data(guidatom)) 407 *pfEqual = TRUE; 408 } 409 410 return S_OK; 411} 412 413//////////////////////////////////////////////////////////////////////////// 414 415EXTERN_C 416HRESULT CategoryMgr_Constructor(IUnknown *pUnkOuter, IUnknown **ppOut) 417{ 418 if (pUnkOuter) 419 return CLASS_E_NOAGGREGATION; 420 421 CCategoryMgr *This = new(cicNoThrow) CCategoryMgr(); 422 if (!This) 423 return E_OUTOFMEMORY; 424 425 *ppOut = static_cast<ITfCategoryMgr *>(This); 426 TRACE("returning %p\n", *ppOut); 427 return S_OK; 428}