1 /* 2 * ITfCategoryMgr implementation 3 * 4 * Copyright 2009 Aric Stewart, CodeWeavers 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 19 */ 20 21 #include <stdarg.h> 22 #ifdef __REACTOS__ 23 #include <wchar.h> 24 #endif 25 26 #define COBJMACROS 27 28 #include "wine/debug.h" 29 #include "windef.h" 30 #include "winbase.h" 31 #include "winreg.h" 32 #include "winuser.h" 33 #include "shlwapi.h" 34 #include "winerror.h" 35 #include "objbase.h" 36 37 38 #include "msctf.h" 39 #include "msctf_internal.h" 40 41 WINE_DEFAULT_DEBUG_CHANNEL(msctf); 42 43 typedef struct tagCategoryMgr { 44 ITfCategoryMgr ITfCategoryMgr_iface; 45 LONG refCount; 46 } CategoryMgr; 47 48 static inline CategoryMgr *impl_from_ITfCategoryMgr(ITfCategoryMgr *iface) 49 { 50 return CONTAINING_RECORD(iface, CategoryMgr, ITfCategoryMgr_iface); 51 } 52 53 static void CategoryMgr_Destructor(CategoryMgr *This) 54 { 55 TRACE("destroying %p\n", This); 56 HeapFree(GetProcessHeap(),0,This); 57 } 58 59 static HRESULT WINAPI CategoryMgr_QueryInterface(ITfCategoryMgr *iface, REFIID iid, LPVOID *ppvOut) 60 { 61 CategoryMgr *This = impl_from_ITfCategoryMgr(iface); 62 *ppvOut = NULL; 63 64 if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_ITfCategoryMgr)) 65 { 66 *ppvOut = &This->ITfCategoryMgr_iface; 67 } 68 69 if (*ppvOut) 70 { 71 ITfCategoryMgr_AddRef(iface); 72 return S_OK; 73 } 74 75 WARN("unsupported interface: %s\n", debugstr_guid(iid)); 76 return E_NOINTERFACE; 77 } 78 79 static ULONG WINAPI CategoryMgr_AddRef(ITfCategoryMgr *iface) 80 { 81 CategoryMgr *This = impl_from_ITfCategoryMgr(iface); 82 return InterlockedIncrement(&This->refCount); 83 } 84 85 static ULONG WINAPI CategoryMgr_Release(ITfCategoryMgr *iface) 86 { 87 CategoryMgr *This = impl_from_ITfCategoryMgr(iface); 88 ULONG ret; 89 90 ret = InterlockedDecrement(&This->refCount); 91 if (ret == 0) 92 CategoryMgr_Destructor(This); 93 return ret; 94 } 95 96 /***************************************************** 97 * ITfCategoryMgr functions 98 *****************************************************/ 99 100 static HRESULT WINAPI CategoryMgr_RegisterCategory ( ITfCategoryMgr *iface, 101 REFCLSID rclsid, REFGUID rcatid, REFGUID rguid) 102 { 103 WCHAR fullkey[110]; 104 WCHAR buf[39]; 105 WCHAR buf2[39]; 106 ULONG res; 107 HKEY tipkey,catkey,itmkey; 108 CategoryMgr *This = impl_from_ITfCategoryMgr(iface); 109 110 static const WCHAR ctg[] = {'C','a','t','e','g','o','r','y',0}; 111 static const WCHAR itm[] = {'I','t','e','m',0}; 112 static const WCHAR fmt[] = {'%','s','\\','%','s',0}; 113 static const WCHAR fmt2[] = {'%','s','\\','%','s','\\','%','s','\\','%','s',0}; 114 115 TRACE("(%p) %s %s %s\n",This,debugstr_guid(rclsid), debugstr_guid(rcatid), debugstr_guid(rguid)); 116 117 StringFromGUID2(rclsid, buf, 39); 118 swprintf(fullkey,fmt,szwSystemTIPKey,buf); 119 120 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,fullkey, 0, KEY_READ | KEY_WRITE, 121 &tipkey ) != ERROR_SUCCESS) 122 return E_FAIL; 123 124 StringFromGUID2(rcatid, buf, 39); 125 StringFromGUID2(rguid, buf2, 39); 126 swprintf(fullkey,fmt2,ctg,ctg,buf,buf2); 127 128 res = RegCreateKeyExW(tipkey, fullkey, 0, NULL, 0, KEY_READ | KEY_WRITE, 129 NULL, &catkey, NULL); 130 RegCloseKey(catkey); 131 132 if (!res) 133 { 134 swprintf(fullkey,fmt2,ctg,itm,buf2,buf); 135 res = RegCreateKeyExW(tipkey, fullkey, 0, NULL, 0, KEY_READ | KEY_WRITE, 136 NULL, &itmkey, NULL); 137 138 RegCloseKey(itmkey); 139 } 140 141 RegCloseKey(tipkey); 142 143 if (!res) 144 return S_OK; 145 else 146 return E_FAIL; 147 } 148 149 static HRESULT WINAPI CategoryMgr_UnregisterCategory ( ITfCategoryMgr *iface, 150 REFCLSID rclsid, REFGUID rcatid, REFGUID rguid) 151 { 152 WCHAR fullkey[110]; 153 WCHAR buf[39]; 154 WCHAR buf2[39]; 155 HKEY tipkey; 156 CategoryMgr *This = impl_from_ITfCategoryMgr(iface); 157 158 static const WCHAR ctg[] = {'C','a','t','e','g','o','r','y',0}; 159 static const WCHAR itm[] = {'I','t','e','m',0}; 160 static const WCHAR fmt[] = {'%','s','\\','%','s',0}; 161 static const WCHAR fmt2[] = {'%','s','\\','%','s','\\','%','s','\\','%','s',0}; 162 163 TRACE("(%p) %s %s %s\n",This,debugstr_guid(rclsid), debugstr_guid(rcatid), debugstr_guid(rguid)); 164 165 StringFromGUID2(rclsid, buf, 39); 166 swprintf(fullkey,fmt,szwSystemTIPKey,buf); 167 168 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,fullkey, 0, KEY_READ | KEY_WRITE, 169 &tipkey ) != ERROR_SUCCESS) 170 return E_FAIL; 171 172 StringFromGUID2(rcatid, buf, 39); 173 StringFromGUID2(rguid, buf2, 39); 174 swprintf(fullkey,fmt2,ctg,ctg,buf,buf2); 175 RegDeleteTreeW(tipkey, fullkey); 176 swprintf(fullkey,fmt2,ctg,itm,buf2,buf); 177 RegDeleteTreeW(tipkey, fullkey); 178 179 RegCloseKey(tipkey); 180 return S_OK; 181 } 182 183 static HRESULT WINAPI CategoryMgr_EnumCategoriesInItem ( ITfCategoryMgr *iface, 184 REFGUID rguid, IEnumGUID **ppEnum) 185 { 186 CategoryMgr *This = impl_from_ITfCategoryMgr(iface); 187 FIXME("STUB:(%p)\n",This); 188 return E_NOTIMPL; 189 } 190 191 static HRESULT WINAPI CategoryMgr_EnumItemsInCategory ( ITfCategoryMgr *iface, 192 REFGUID rcatid, IEnumGUID **ppEnum) 193 { 194 CategoryMgr *This = impl_from_ITfCategoryMgr(iface); 195 FIXME("STUB:(%p)\n",This); 196 return E_NOTIMPL; 197 } 198 199 static HRESULT WINAPI CategoryMgr_FindClosestCategory ( ITfCategoryMgr *iface, 200 REFGUID rguid, GUID *pcatid, const GUID **ppcatidList, ULONG ulCount) 201 { 202 static const WCHAR fmt[] = { '%','s','\\','%','s','\\','C','a','t','e','g','o','r','y','\\','I','t','e','m','\\','%','s',0}; 203 204 WCHAR fullkey[120]; 205 WCHAR buf[39]; 206 HKEY key; 207 HRESULT hr = S_FALSE; 208 INT index = 0; 209 CategoryMgr *This = impl_from_ITfCategoryMgr(iface); 210 211 TRACE("(%p)\n",This); 212 213 if (!pcatid || (ulCount && ppcatidList == NULL)) 214 return E_INVALIDARG; 215 216 StringFromGUID2(rguid, buf, 39); 217 swprintf(fullkey,fmt,szwSystemTIPKey,buf,buf); 218 *pcatid = GUID_NULL; 219 220 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,fullkey, 0, KEY_READ, &key ) != 221 ERROR_SUCCESS) 222 return S_FALSE; 223 224 while (1) 225 { 226 HRESULT hr2; 227 ULONG res; 228 GUID guid; 229 WCHAR catid[39]; 230 DWORD cName; 231 232 cName = 39; 233 res = RegEnumKeyExW(key, index, catid, &cName, NULL, NULL, NULL, NULL); 234 if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) break; 235 index ++; 236 237 hr2 = CLSIDFromString(catid, &guid); 238 if (FAILED(hr2)) continue; 239 240 if (ulCount) 241 { 242 ULONG j; 243 BOOL found = FALSE; 244 for (j = 0; j < ulCount; j++) 245 if (IsEqualGUID(&guid, ppcatidList[j])) 246 { 247 found = TRUE; 248 *pcatid = guid; 249 hr = S_OK; 250 break; 251 } 252 if (found) break; 253 } 254 else 255 { 256 *pcatid = guid; 257 hr = S_OK; 258 break; 259 } 260 } 261 262 return hr; 263 } 264 265 static HRESULT WINAPI CategoryMgr_RegisterGUIDDescription ( 266 ITfCategoryMgr *iface, REFCLSID rclsid, REFGUID rguid, 267 const WCHAR *pchDesc, ULONG cch) 268 { 269 CategoryMgr *This = impl_from_ITfCategoryMgr(iface); 270 FIXME("STUB:(%p)\n",This); 271 return E_NOTIMPL; 272 } 273 274 static HRESULT WINAPI CategoryMgr_UnregisterGUIDDescription ( 275 ITfCategoryMgr *iface, REFCLSID rclsid, REFGUID rguid) 276 { 277 CategoryMgr *This = impl_from_ITfCategoryMgr(iface); 278 FIXME("STUB:(%p)\n",This); 279 return E_NOTIMPL; 280 } 281 282 static HRESULT WINAPI CategoryMgr_GetGUIDDescription ( ITfCategoryMgr *iface, 283 REFGUID rguid, BSTR *pbstrDesc) 284 { 285 CategoryMgr *This = impl_from_ITfCategoryMgr(iface); 286 FIXME("STUB:(%p)\n",This); 287 return E_NOTIMPL; 288 } 289 290 static HRESULT WINAPI CategoryMgr_RegisterGUIDDWORD ( ITfCategoryMgr *iface, 291 REFCLSID rclsid, REFGUID rguid, DWORD dw) 292 { 293 CategoryMgr *This = impl_from_ITfCategoryMgr(iface); 294 FIXME("STUB:(%p)\n",This); 295 return E_NOTIMPL; 296 } 297 298 static HRESULT WINAPI CategoryMgr_UnregisterGUIDDWORD ( ITfCategoryMgr *iface, 299 REFCLSID rclsid, REFGUID rguid) 300 { 301 CategoryMgr *This = impl_from_ITfCategoryMgr(iface); 302 FIXME("STUB:(%p)\n",This); 303 return E_NOTIMPL; 304 } 305 306 static HRESULT WINAPI CategoryMgr_GetGUIDDWORD ( ITfCategoryMgr *iface, 307 REFGUID rguid, DWORD *pdw) 308 { 309 CategoryMgr *This = impl_from_ITfCategoryMgr(iface); 310 FIXME("STUB:(%p)\n",This); 311 return E_NOTIMPL; 312 } 313 314 static HRESULT WINAPI CategoryMgr_RegisterGUID ( ITfCategoryMgr *iface, 315 REFGUID rguid, TfGuidAtom *pguidatom 316 ) 317 { 318 DWORD index; 319 GUID *checkguid; 320 DWORD id; 321 CategoryMgr *This = impl_from_ITfCategoryMgr(iface); 322 323 TRACE("(%p) %s %p\n",This,debugstr_guid(rguid),pguidatom); 324 325 if (!pguidatom) 326 return E_INVALIDARG; 327 328 index = 0; 329 do { 330 id = enumerate_Cookie(COOKIE_MAGIC_GUIDATOM,&index); 331 if (id && IsEqualGUID(rguid,get_Cookie_data(id))) 332 { 333 *pguidatom = id; 334 return S_OK; 335 } 336 } while(id); 337 338 checkguid = HeapAlloc(GetProcessHeap(),0,sizeof(GUID)); 339 *checkguid = *rguid; 340 id = generate_Cookie(COOKIE_MAGIC_GUIDATOM,checkguid); 341 342 if (!id) 343 { 344 HeapFree(GetProcessHeap(),0,checkguid); 345 return E_FAIL; 346 } 347 348 *pguidatom = id; 349 350 return S_OK; 351 } 352 353 static HRESULT WINAPI CategoryMgr_GetGUID ( ITfCategoryMgr *iface, 354 TfGuidAtom guidatom, GUID *pguid) 355 { 356 CategoryMgr *This = impl_from_ITfCategoryMgr(iface); 357 358 TRACE("(%p) %i\n",This,guidatom); 359 360 if (!pguid) 361 return E_INVALIDARG; 362 363 *pguid = GUID_NULL; 364 365 if (get_Cookie_magic(guidatom) == COOKIE_MAGIC_GUIDATOM) 366 *pguid = *((REFGUID)get_Cookie_data(guidatom)); 367 368 return S_OK; 369 } 370 371 static HRESULT WINAPI CategoryMgr_IsEqualTfGuidAtom ( ITfCategoryMgr *iface, 372 TfGuidAtom guidatom, REFGUID rguid, BOOL *pfEqual) 373 { 374 CategoryMgr *This = impl_from_ITfCategoryMgr(iface); 375 376 TRACE("(%p) %i %s %p\n",This,guidatom,debugstr_guid(rguid),pfEqual); 377 378 if (!pfEqual) 379 return E_INVALIDARG; 380 381 *pfEqual = FALSE; 382 if (get_Cookie_magic(guidatom) == COOKIE_MAGIC_GUIDATOM) 383 { 384 if (IsEqualGUID(rguid,get_Cookie_data(guidatom))) 385 *pfEqual = TRUE; 386 } 387 388 return S_OK; 389 } 390 391 392 static const ITfCategoryMgrVtbl CategoryMgrVtbl = 393 { 394 CategoryMgr_QueryInterface, 395 CategoryMgr_AddRef, 396 CategoryMgr_Release, 397 CategoryMgr_RegisterCategory, 398 CategoryMgr_UnregisterCategory, 399 CategoryMgr_EnumCategoriesInItem, 400 CategoryMgr_EnumItemsInCategory, 401 CategoryMgr_FindClosestCategory, 402 CategoryMgr_RegisterGUIDDescription, 403 CategoryMgr_UnregisterGUIDDescription, 404 CategoryMgr_GetGUIDDescription, 405 CategoryMgr_RegisterGUIDDWORD, 406 CategoryMgr_UnregisterGUIDDWORD, 407 CategoryMgr_GetGUIDDWORD, 408 CategoryMgr_RegisterGUID, 409 CategoryMgr_GetGUID, 410 CategoryMgr_IsEqualTfGuidAtom 411 }; 412 413 HRESULT CategoryMgr_Constructor(IUnknown *pUnkOuter, IUnknown **ppOut) 414 { 415 CategoryMgr *This; 416 if (pUnkOuter) 417 return CLASS_E_NOAGGREGATION; 418 419 This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(CategoryMgr)); 420 if (This == NULL) 421 return E_OUTOFMEMORY; 422 423 This->ITfCategoryMgr_iface.lpVtbl = &CategoryMgrVtbl; 424 This->refCount = 1; 425 426 *ppOut = (IUnknown *)&This->ITfCategoryMgr_iface; 427 TRACE("returning %p\n", *ppOut); 428 return S_OK; 429 } 430