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 "config.h" 22 23 #include <stdarg.h> 24 25 #define COBJMACROS 26 27 #include "wine/debug.h" 28 #include "windef.h" 29 #include "winbase.h" 30 #include "winreg.h" 31 #include "winuser.h" 32 #include "shlwapi.h" 33 #include "winerror.h" 34 #include "objbase.h" 35 36 #include "wine/unicode.h" 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 sprintfW(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 sprintfW(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 sprintfW(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 sprintfW(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 sprintfW(fullkey,fmt2,ctg,ctg,buf,buf2); 175 176 sprintfW(fullkey,fmt2,ctg,itm,buf2,buf); 177 RegDeleteTreeW(tipkey, fullkey); 178 sprintfW(fullkey,fmt2,ctg,itm,buf2,buf); 179 RegDeleteTreeW(tipkey, fullkey); 180 181 RegCloseKey(tipkey); 182 return S_OK; 183 } 184 185 static HRESULT WINAPI CategoryMgr_EnumCategoriesInItem ( ITfCategoryMgr *iface, 186 REFGUID rguid, IEnumGUID **ppEnum) 187 { 188 CategoryMgr *This = impl_from_ITfCategoryMgr(iface); 189 FIXME("STUB:(%p)\n",This); 190 return E_NOTIMPL; 191 } 192 193 static HRESULT WINAPI CategoryMgr_EnumItemsInCategory ( ITfCategoryMgr *iface, 194 REFGUID rcatid, IEnumGUID **ppEnum) 195 { 196 CategoryMgr *This = impl_from_ITfCategoryMgr(iface); 197 FIXME("STUB:(%p)\n",This); 198 return E_NOTIMPL; 199 } 200 201 static HRESULT WINAPI CategoryMgr_FindClosestCategory ( ITfCategoryMgr *iface, 202 REFGUID rguid, GUID *pcatid, const GUID **ppcatidList, ULONG ulCount) 203 { 204 static const WCHAR fmt[] = { '%','s','\\','%','s','\\','C','a','t','e','g','o','r','y','\\','I','t','e','m','\\','%','s',0}; 205 206 WCHAR fullkey[120]; 207 WCHAR buf[39]; 208 HKEY key; 209 HRESULT hr = S_FALSE; 210 INT index = 0; 211 CategoryMgr *This = impl_from_ITfCategoryMgr(iface); 212 213 TRACE("(%p)\n",This); 214 215 if (!pcatid || (ulCount && ppcatidList == NULL)) 216 return E_INVALIDARG; 217 218 StringFromGUID2(rguid, buf, 39); 219 sprintfW(fullkey,fmt,szwSystemTIPKey,buf,buf); 220 *pcatid = GUID_NULL; 221 222 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,fullkey, 0, KEY_READ, &key ) != 223 ERROR_SUCCESS) 224 return S_FALSE; 225 226 while (1) 227 { 228 HRESULT hr2; 229 ULONG res; 230 GUID guid; 231 WCHAR catid[39]; 232 DWORD cName; 233 234 cName = 39; 235 res = RegEnumKeyExW(key, index, catid, &cName, NULL, NULL, NULL, NULL); 236 if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) break; 237 index ++; 238 239 hr2 = CLSIDFromString(catid, &guid); 240 if (FAILED(hr2)) continue; 241 242 if (ulCount) 243 { 244 ULONG j; 245 BOOL found = FALSE; 246 for (j = 0; j < ulCount; j++) 247 if (IsEqualGUID(&guid, ppcatidList[j])) 248 { 249 found = TRUE; 250 *pcatid = guid; 251 hr = S_OK; 252 break; 253 } 254 if (found) break; 255 } 256 else 257 { 258 *pcatid = guid; 259 hr = S_OK; 260 break; 261 } 262 } 263 264 return hr; 265 } 266 267 static HRESULT WINAPI CategoryMgr_RegisterGUIDDescription ( 268 ITfCategoryMgr *iface, REFCLSID rclsid, REFGUID rguid, 269 const WCHAR *pchDesc, ULONG cch) 270 { 271 CategoryMgr *This = impl_from_ITfCategoryMgr(iface); 272 FIXME("STUB:(%p)\n",This); 273 return E_NOTIMPL; 274 } 275 276 static HRESULT WINAPI CategoryMgr_UnregisterGUIDDescription ( 277 ITfCategoryMgr *iface, REFCLSID rclsid, REFGUID rguid) 278 { 279 CategoryMgr *This = impl_from_ITfCategoryMgr(iface); 280 FIXME("STUB:(%p)\n",This); 281 return E_NOTIMPL; 282 } 283 284 static HRESULT WINAPI CategoryMgr_GetGUIDDescription ( ITfCategoryMgr *iface, 285 REFGUID rguid, BSTR *pbstrDesc) 286 { 287 CategoryMgr *This = impl_from_ITfCategoryMgr(iface); 288 FIXME("STUB:(%p)\n",This); 289 return E_NOTIMPL; 290 } 291 292 static HRESULT WINAPI CategoryMgr_RegisterGUIDDWORD ( ITfCategoryMgr *iface, 293 REFCLSID rclsid, REFGUID rguid, DWORD dw) 294 { 295 CategoryMgr *This = impl_from_ITfCategoryMgr(iface); 296 FIXME("STUB:(%p)\n",This); 297 return E_NOTIMPL; 298 } 299 300 static HRESULT WINAPI CategoryMgr_UnregisterGUIDDWORD ( ITfCategoryMgr *iface, 301 REFCLSID rclsid, REFGUID rguid) 302 { 303 CategoryMgr *This = impl_from_ITfCategoryMgr(iface); 304 FIXME("STUB:(%p)\n",This); 305 return E_NOTIMPL; 306 } 307 308 static HRESULT WINAPI CategoryMgr_GetGUIDDWORD ( ITfCategoryMgr *iface, 309 REFGUID rguid, DWORD *pdw) 310 { 311 CategoryMgr *This = impl_from_ITfCategoryMgr(iface); 312 FIXME("STUB:(%p)\n",This); 313 return E_NOTIMPL; 314 } 315 316 static HRESULT WINAPI CategoryMgr_RegisterGUID ( ITfCategoryMgr *iface, 317 REFGUID rguid, TfGuidAtom *pguidatom 318 ) 319 { 320 DWORD index; 321 GUID *checkguid; 322 DWORD id; 323 CategoryMgr *This = impl_from_ITfCategoryMgr(iface); 324 325 TRACE("(%p) %s %p\n",This,debugstr_guid(rguid),pguidatom); 326 327 if (!pguidatom) 328 return E_INVALIDARG; 329 330 index = 0; 331 do { 332 id = enumerate_Cookie(COOKIE_MAGIC_GUIDATOM,&index); 333 if (id && IsEqualGUID(rguid,get_Cookie_data(id))) 334 { 335 *pguidatom = id; 336 return S_OK; 337 } 338 } while(id); 339 340 checkguid = HeapAlloc(GetProcessHeap(),0,sizeof(GUID)); 341 *checkguid = *rguid; 342 id = generate_Cookie(COOKIE_MAGIC_GUIDATOM,checkguid); 343 344 if (!id) 345 { 346 HeapFree(GetProcessHeap(),0,checkguid); 347 return E_FAIL; 348 } 349 350 *pguidatom = id; 351 352 return S_OK; 353 } 354 355 static HRESULT WINAPI CategoryMgr_GetGUID ( ITfCategoryMgr *iface, 356 TfGuidAtom guidatom, GUID *pguid) 357 { 358 CategoryMgr *This = impl_from_ITfCategoryMgr(iface); 359 360 TRACE("(%p) %i\n",This,guidatom); 361 362 if (!pguid) 363 return E_INVALIDARG; 364 365 *pguid = GUID_NULL; 366 367 if (get_Cookie_magic(guidatom) == COOKIE_MAGIC_GUIDATOM) 368 *pguid = *((REFGUID)get_Cookie_data(guidatom)); 369 370 return S_OK; 371 } 372 373 static HRESULT WINAPI CategoryMgr_IsEqualTfGuidAtom ( ITfCategoryMgr *iface, 374 TfGuidAtom guidatom, REFGUID rguid, BOOL *pfEqual) 375 { 376 CategoryMgr *This = impl_from_ITfCategoryMgr(iface); 377 378 TRACE("(%p) %i %s %p\n",This,guidatom,debugstr_guid(rguid),pfEqual); 379 380 if (!pfEqual) 381 return E_INVALIDARG; 382 383 *pfEqual = FALSE; 384 if (get_Cookie_magic(guidatom) == COOKIE_MAGIC_GUIDATOM) 385 { 386 if (IsEqualGUID(rguid,get_Cookie_data(guidatom))) 387 *pfEqual = TRUE; 388 } 389 390 return S_OK; 391 } 392 393 394 static const ITfCategoryMgrVtbl CategoryMgrVtbl = 395 { 396 CategoryMgr_QueryInterface, 397 CategoryMgr_AddRef, 398 CategoryMgr_Release, 399 CategoryMgr_RegisterCategory, 400 CategoryMgr_UnregisterCategory, 401 CategoryMgr_EnumCategoriesInItem, 402 CategoryMgr_EnumItemsInCategory, 403 CategoryMgr_FindClosestCategory, 404 CategoryMgr_RegisterGUIDDescription, 405 CategoryMgr_UnregisterGUIDDescription, 406 CategoryMgr_GetGUIDDescription, 407 CategoryMgr_RegisterGUIDDWORD, 408 CategoryMgr_UnregisterGUIDDWORD, 409 CategoryMgr_GetGUIDDWORD, 410 CategoryMgr_RegisterGUID, 411 CategoryMgr_GetGUID, 412 CategoryMgr_IsEqualTfGuidAtom 413 }; 414 415 HRESULT CategoryMgr_Constructor(IUnknown *pUnkOuter, IUnknown **ppOut) 416 { 417 CategoryMgr *This; 418 if (pUnkOuter) 419 return CLASS_E_NOAGGREGATION; 420 421 This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(CategoryMgr)); 422 if (This == NULL) 423 return E_OUTOFMEMORY; 424 425 This->ITfCategoryMgr_iface.lpVtbl = &CategoryMgrVtbl; 426 This->refCount = 1; 427 428 *ppOut = (IUnknown *)&This->ITfCategoryMgr_iface; 429 TRACE("returning %p\n", *ppOut); 430 return S_OK; 431 } 432