d3d10/effect: Add support for 'imul' instruction.
[wine.git] / dlls / adsldp / adsldp.c
blob9cc5c6cdc2bd3b113d1adeeb5b0a9d845ddfcf17
1 /*
2 * Active Directory services LDAP Provider
4 * Copyright 2018 Dmitry Timoshkov
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.
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.
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
21 #include <stdarg.h>
23 #define COBJMACROS
24 #include "windef.h"
25 #include "winbase.h"
26 #include "initguid.h"
27 #include "objbase.h"
28 #include "rpcproxy.h"
29 #include "rpc.h"
30 #include "iads.h"
31 #include "adshlp.h"
32 #include "adserr.h"
33 #define SECURITY_WIN32
34 #include "security.h"
35 #include "dsgetdc.h"
36 #include "lmcons.h"
37 #include "lmapibuf.h"
38 #include "winldap.h"
39 #include "winber.h"
41 #include "adsldp_private.h"
43 #include "wine/debug.h"
45 WINE_DEFAULT_DEBUG_CHANNEL(adsldp);
47 #ifndef LDAP_OPT_SERVER_CONTROLS
48 #define LDAP_OPT_SERVER_CONTROLS 0x0012
49 #endif
51 DEFINE_GUID(CLSID_LDAP,0x228d9a81,0xc302,0x11cf,0x9a,0xa4,0x00,0xaa,0x00,0x4a,0x56,0x91);
52 DEFINE_GUID(CLSID_LDAPNamespace,0x228d9a82,0xc302,0x11cf,0x9a,0xa4,0x00,0xaa,0x00,0x4a,0x56,0x91);
54 static HRESULT LDAPNamespace_create(REFIID riid, void **obj);
56 typedef struct
58 IParseDisplayName IParseDisplayName_iface;
59 LONG ref;
60 } LDAP_PARSE;
62 static inline LDAP_PARSE *impl_from_IParseDisplayName(IParseDisplayName *iface)
64 return CONTAINING_RECORD(iface, LDAP_PARSE, IParseDisplayName_iface);
67 static HRESULT WINAPI ldap_QueryInterface(IParseDisplayName *iface, REFIID riid, void **obj)
69 TRACE("%p,%s,%p\n", iface, debugstr_guid(riid), obj);
71 if (!riid || !obj) return E_INVALIDARG;
73 if (IsEqualGUID(riid, &IID_IUnknown) ||
74 IsEqualGUID(riid, &IID_IParseDisplayName))
76 IParseDisplayName_AddRef(iface);
77 *obj = iface;
78 return S_OK;
81 *obj = NULL;
82 FIXME("interface %s is not implemented\n", debugstr_guid(riid));
83 return E_NOINTERFACE;
86 static ULONG WINAPI ldap_AddRef(IParseDisplayName *iface)
88 LDAP_PARSE *ldap = impl_from_IParseDisplayName(iface);
89 return InterlockedIncrement(&ldap->ref);
92 static ULONG WINAPI ldap_Release(IParseDisplayName *iface)
94 LDAP_PARSE *ldap = impl_from_IParseDisplayName(iface);
95 LONG ref = InterlockedDecrement(&ldap->ref);
97 if (!ref)
99 TRACE("destroying %p\n", iface);
100 free(ldap);
103 return ref;
106 static HRESULT WINAPI ldap_ParseDisplayName(IParseDisplayName *iface, IBindCtx *bc,
107 LPOLESTR name, ULONG *eaten, IMoniker **mk)
109 HRESULT hr;
110 IADsOpenDSObject *ads_open;
111 IDispatch *disp;
113 TRACE("%p,%p,%s,%p,%p\n", iface, bc, debugstr_w(name), eaten, mk);
115 hr = LDAPNamespace_create(&IID_IADsOpenDSObject, (void **)&ads_open);
116 if (hr != S_OK) return hr;
118 hr = IADsOpenDSObject_OpenDSObject(ads_open, name, NULL, NULL, ADS_SECURE_AUTHENTICATION, &disp);
119 if (hr != S_OK)
120 hr = IADsOpenDSObject_OpenDSObject(ads_open, name, NULL, NULL, 0, &disp);
121 if (hr == S_OK)
123 hr = CreatePointerMoniker((IUnknown *)disp, mk);
124 if (hr == S_OK)
125 *eaten = wcslen(name);
127 IDispatch_Release(disp);
130 IADsOpenDSObject_Release(ads_open);
132 return hr;
135 static const IParseDisplayNameVtbl LDAP_PARSE_vtbl =
137 ldap_QueryInterface,
138 ldap_AddRef,
139 ldap_Release,
140 ldap_ParseDisplayName
143 static HRESULT LDAP_create(REFIID riid, void **obj)
145 LDAP_PARSE *ldap;
146 HRESULT hr;
148 ldap = malloc(sizeof(*ldap));
149 if (!ldap) return E_OUTOFMEMORY;
151 ldap->IParseDisplayName_iface.lpVtbl = &LDAP_PARSE_vtbl;
152 ldap->ref = 1;
154 hr = IParseDisplayName_QueryInterface(&ldap->IParseDisplayName_iface, riid, obj);
155 IParseDisplayName_Release(&ldap->IParseDisplayName_iface);
157 return hr;
160 typedef struct
162 IADsADSystemInfo IADsADSystemInfo_iface;
163 LONG ref;
164 } AD_sysinfo;
166 static inline AD_sysinfo *impl_from_IADsADSystemInfo(IADsADSystemInfo *iface)
168 return CONTAINING_RECORD(iface, AD_sysinfo, IADsADSystemInfo_iface);
171 static HRESULT WINAPI sysinfo_QueryInterface(IADsADSystemInfo *iface, REFIID riid, void **obj)
173 TRACE("%p,%s,%p\n", iface, debugstr_guid(riid), obj);
175 if (!riid || !obj) return E_INVALIDARG;
177 if (IsEqualGUID(riid, &IID_IADsADSystemInfo) ||
178 IsEqualGUID(riid, &IID_IDispatch) ||
179 IsEqualGUID(riid, &IID_IUnknown))
181 IADsADSystemInfo_AddRef(iface);
182 *obj = iface;
183 return S_OK;
186 *obj = NULL;
187 FIXME("interface %s is not implemented\n", debugstr_guid(riid));
188 return E_NOINTERFACE;
191 static ULONG WINAPI sysinfo_AddRef(IADsADSystemInfo *iface)
193 AD_sysinfo *sysinfo = impl_from_IADsADSystemInfo(iface);
194 return InterlockedIncrement(&sysinfo->ref);
197 static ULONG WINAPI sysinfo_Release(IADsADSystemInfo *iface)
199 AD_sysinfo *sysinfo = impl_from_IADsADSystemInfo(iface);
200 LONG ref = InterlockedDecrement(&sysinfo->ref);
202 if (!ref)
204 TRACE("destroying %p\n", iface);
205 free(sysinfo);
208 return ref;
211 static HRESULT WINAPI sysinfo_GetTypeInfoCount(IADsADSystemInfo *iface, UINT *count)
213 FIXME("%p,%p: stub\n", iface, count);
214 return E_NOTIMPL;
217 static HRESULT WINAPI sysinfo_GetTypeInfo(IADsADSystemInfo *iface, UINT index, LCID lcid, ITypeInfo **info)
219 FIXME("%p,%u,%#lx,%p: stub\n", iface, index, lcid, info);
220 return E_NOTIMPL;
223 static HRESULT WINAPI sysinfo_GetIDsOfNames(IADsADSystemInfo *iface, REFIID riid, LPOLESTR *names,
224 UINT count, LCID lcid, DISPID *dispid)
226 FIXME("%p,%s,%p,%u,%lu,%p: stub\n", iface, debugstr_guid(riid), names, count, lcid, dispid);
227 return E_NOTIMPL;
230 static HRESULT WINAPI sysinfo_Invoke(IADsADSystemInfo *iface, DISPID dispid, REFIID riid, LCID lcid, WORD flags,
231 DISPPARAMS *params, VARIANT *result, EXCEPINFO *excepinfo, UINT *argerr)
233 FIXME("%p,%ld,%s,%04lx,%04x,%p,%p,%p,%p: stub\n", iface, dispid, debugstr_guid(riid), lcid, flags,
234 params, result, excepinfo, argerr);
235 return E_NOTIMPL;
238 static HRESULT WINAPI sysinfo_get_UserName(IADsADSystemInfo *iface, BSTR *retval)
240 FIXME("%p,%p: stub\n", iface, retval);
241 return E_NOTIMPL;
244 static HRESULT WINAPI sysinfo_get_ComputerName(IADsADSystemInfo *iface, BSTR *retval)
246 ULONG size;
247 WCHAR *name;
249 TRACE("%p,%p\n", iface, retval);
251 size = 0;
252 GetComputerObjectNameW(NameFullyQualifiedDN, NULL, &size);
253 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
254 return HRESULT_FROM_WIN32(GetLastError());
256 name = SysAllocStringLen(NULL, size);
257 if (!name) return E_OUTOFMEMORY;
259 if (!GetComputerObjectNameW(NameFullyQualifiedDN, name, &size))
261 SysFreeString(name);
262 return HRESULT_FROM_WIN32(GetLastError());
265 *retval = name;
266 return S_OK;
269 static HRESULT WINAPI sysinfo_get_SiteName(IADsADSystemInfo *iface, BSTR *retval)
271 FIXME("%p,%p: stub\n", iface, retval);
272 return E_NOTIMPL;
275 static HRESULT WINAPI sysinfo_get_DomainShortName(IADsADSystemInfo *iface, BSTR *retval)
277 FIXME("%p,%p: stub\n", iface, retval);
278 return E_NOTIMPL;
281 static HRESULT WINAPI sysinfo_get_DomainDNSName(IADsADSystemInfo *iface, BSTR *retval)
283 FIXME("%p,%p: stub\n", iface, retval);
284 return E_NOTIMPL;
287 static HRESULT WINAPI sysinfo_get_ForestDNSName(IADsADSystemInfo *iface, BSTR *retval)
289 FIXME("%p,%p: stub\n", iface, retval);
290 return E_NOTIMPL;
293 static HRESULT WINAPI sysinfo_get_PDCRoleOwner(IADsADSystemInfo *iface, BSTR *retval)
295 FIXME("%p,%p: stub\n", iface, retval);
296 return E_NOTIMPL;
299 static HRESULT WINAPI sysinfo_get_SchemaRoleOwner(IADsADSystemInfo *iface, BSTR *retval)
301 FIXME("%p,%p: stub\n", iface, retval);
302 return E_NOTIMPL;
305 static HRESULT WINAPI sysinfo_get_IsNativeMode(IADsADSystemInfo *iface, VARIANT_BOOL *retval)
307 FIXME("%p,%p: stub\n", iface, retval);
308 return E_NOTIMPL;
311 static HRESULT WINAPI sysinfo_GetAnyDCName(IADsADSystemInfo *iface, BSTR *retval)
313 FIXME("%p,%p: stub\n", iface, retval);
314 return E_NOTIMPL;
317 static HRESULT WINAPI sysinfo_GetDCSiteName(IADsADSystemInfo *iface, BSTR server, BSTR *retval)
319 FIXME("%p,%s,%p: stub\n", iface, debugstr_w(server), retval);
320 return E_NOTIMPL;
323 static HRESULT WINAPI sysinfo_RefreshSchemaCache(IADsADSystemInfo *iface)
325 FIXME("%p: stub\n", iface);
326 return E_NOTIMPL;
329 static HRESULT WINAPI sysinfo_GetTrees(IADsADSystemInfo *iface, VARIANT *retval)
331 FIXME("%p,%p: stub\n", iface, retval);
332 return E_NOTIMPL;
335 static const IADsADSystemInfoVtbl IADsADSystemInfo_vtbl =
337 sysinfo_QueryInterface,
338 sysinfo_AddRef,
339 sysinfo_Release,
340 sysinfo_GetTypeInfoCount,
341 sysinfo_GetTypeInfo,
342 sysinfo_GetIDsOfNames,
343 sysinfo_Invoke,
344 sysinfo_get_UserName,
345 sysinfo_get_ComputerName,
346 sysinfo_get_SiteName,
347 sysinfo_get_DomainShortName,
348 sysinfo_get_DomainDNSName,
349 sysinfo_get_ForestDNSName,
350 sysinfo_get_PDCRoleOwner,
351 sysinfo_get_SchemaRoleOwner,
352 sysinfo_get_IsNativeMode,
353 sysinfo_GetAnyDCName,
354 sysinfo_GetDCSiteName,
355 sysinfo_RefreshSchemaCache,
356 sysinfo_GetTrees
359 static HRESULT ADSystemInfo_create(REFIID riid, void **obj)
361 AD_sysinfo *sysinfo;
362 HRESULT hr;
364 sysinfo = malloc(sizeof(*sysinfo));
365 if (!sysinfo) return E_OUTOFMEMORY;
367 sysinfo->IADsADSystemInfo_iface.lpVtbl = &IADsADSystemInfo_vtbl;
368 sysinfo->ref = 1;
370 hr = IADsADSystemInfo_QueryInterface(&sysinfo->IADsADSystemInfo_iface, riid, obj);
371 IADsADSystemInfo_Release(&sysinfo->IADsADSystemInfo_iface);
373 return hr;
376 struct ldap_attribute
378 WCHAR *name;
379 WCHAR **values;
382 typedef struct
384 IADs IADs_iface;
385 IADsOpenDSObject IADsOpenDSObject_iface;
386 IDirectorySearch IDirectorySearch_iface;
387 IDirectoryObject IDirectoryObject_iface;
388 LONG ref;
389 LDAP *ld;
390 BSTR host;
391 BSTR object;
392 ULONG port;
393 ULONG attrs_count, attrs_count_allocated;
394 struct ldap_attribute *attrs;
395 struct attribute_type *at;
396 ULONG at_single_count, at_multiple_count;
397 struct
399 ADS_SCOPEENUM scope;
400 int pagesize;
401 int size_limit;
402 BOOL cache_results;
403 BOOL attribtypes_only;
404 BOOL tombstone;
405 } search;
406 } LDAP_namespace;
408 struct ldap_search_context
410 LDAPSearch *page;
411 LDAPMessage *res, *entry;
412 BerElement *ber;
413 ULONG count, pos;
414 BOOL add_ADsPath;
417 static inline LDAP_namespace *impl_from_IADs(IADs *iface)
419 return CONTAINING_RECORD(iface, LDAP_namespace, IADs_iface);
422 static HRESULT WINAPI ldapns_QueryInterface(IADs *iface, REFIID riid, void **obj)
424 LDAP_namespace *ldap = impl_from_IADs(iface);
426 TRACE("%p,%s,%p\n", iface, debugstr_guid(riid), obj);
428 if (!riid || !obj) return E_INVALIDARG;
430 if (IsEqualGUID(riid, &IID_IUnknown) ||
431 IsEqualGUID(riid, &IID_IDispatch) ||
432 IsEqualGUID(riid, &IID_IADs))
434 IADs_AddRef(iface);
435 *obj = iface;
436 return S_OK;
439 if (IsEqualGUID(riid, &IID_IADsOpenDSObject))
441 IADs_AddRef(iface);
442 *obj = &ldap->IADsOpenDSObject_iface;
443 return S_OK;
446 if (IsEqualGUID(riid, &IID_IDirectorySearch))
448 if (!ldap->ld || (ldap->object && !wcsicmp(ldap->object, L"rootDSE")))
449 return E_NOINTERFACE;
451 IADs_AddRef(iface);
452 *obj = &ldap->IDirectorySearch_iface;
453 return S_OK;
456 if (IsEqualGUID(riid, &IID_IDirectoryObject))
458 IADs_AddRef(iface);
459 *obj = &ldap->IDirectoryObject_iface;
460 return S_OK;
463 FIXME("interface %s is not implemented\n", debugstr_guid(riid));
464 return E_NOINTERFACE;
467 static ULONG WINAPI ldapns_AddRef(IADs *iface)
469 LDAP_namespace *ldap = impl_from_IADs(iface);
470 return InterlockedIncrement(&ldap->ref);
473 static void free_attributes(LDAP_namespace *ldap)
475 ULONG i;
477 if (!ldap->attrs) return;
479 for (i = 0; i < ldap->attrs_count; i++)
481 ldap_memfreeW(ldap->attrs[i].name);
482 ldap_value_freeW(ldap->attrs[i].values);
485 free(ldap->attrs);
486 ldap->attrs = NULL;
487 ldap->attrs_count = 0;
490 static ULONG WINAPI ldapns_Release(IADs *iface)
492 LDAP_namespace *ldap = impl_from_IADs(iface);
493 LONG ref = InterlockedDecrement(&ldap->ref);
495 if (!ref)
497 TRACE("destroying %p\n", iface);
498 if (ldap->ld) ldap_unbind(ldap->ld);
499 SysFreeString(ldap->host);
500 SysFreeString(ldap->object);
501 free_attributes(ldap);
502 free_attribute_types(ldap->at, ldap->at_single_count + ldap->at_multiple_count);
503 free(ldap);
506 return ref;
509 static HRESULT WINAPI ldapns_GetTypeInfoCount(IADs *iface, UINT *count)
511 FIXME("%p,%p: stub\n", iface, count);
512 return E_NOTIMPL;
515 static HRESULT WINAPI ldapns_GetTypeInfo(IADs *iface, UINT index, LCID lcid, ITypeInfo **info)
517 FIXME("%p,%u,%#lx,%p: stub\n", iface, index, lcid, info);
518 return E_NOTIMPL;
521 static HRESULT WINAPI ldapns_GetIDsOfNames(IADs *iface, REFIID riid, LPOLESTR *names,
522 UINT count, LCID lcid, DISPID *dispid)
524 FIXME("%p,%s,%p,%u,%lu,%p: stub\n", iface, debugstr_guid(riid), names, count, lcid, dispid);
525 return E_NOTIMPL;
528 static HRESULT WINAPI ldapns_Invoke(IADs *iface, DISPID dispid, REFIID riid, LCID lcid, WORD flags,
529 DISPPARAMS *params, VARIANT *result, EXCEPINFO *excepinfo, UINT *argerr)
531 FIXME("%p,%ld,%s,%04lx,%04x,%p,%p,%p,%p: stub\n", iface, dispid, debugstr_guid(riid), lcid, flags,
532 params, result, excepinfo, argerr);
533 return E_NOTIMPL;
536 static HRESULT WINAPI ldapns_get_Name(IADs *iface, BSTR *retval)
538 FIXME("%p,%p: stub\n", iface, retval);
539 return E_NOTIMPL;
542 static HRESULT WINAPI ldapns_get_Class(IADs *iface, BSTR *retval)
544 FIXME("%p,%p: stub\n", iface, retval);
545 return E_NOTIMPL;
548 static HRESULT WINAPI ldapns_get_GUID(IADs *iface, BSTR *retval)
550 FIXME("%p,%p: stub\n", iface, retval);
551 return E_NOTIMPL;
554 static HRESULT WINAPI ldapns_get_ADsPath(IADs *iface, BSTR *retval)
556 FIXME("%p,%p: stub\n", iface, retval);
557 return E_NOTIMPL;
560 static HRESULT WINAPI ldapns_get_Parent(IADs *iface, BSTR *retval)
562 FIXME("%p,%p: stub\n", iface, retval);
563 return E_NOTIMPL;
566 static HRESULT WINAPI ldapns_get_Schema(IADs *iface, BSTR *retval)
568 FIXME("%p,%p: stub\n", iface, retval);
569 return E_NOTIMPL;
572 static HRESULT WINAPI ldapns_GetInfo(IADs *iface)
574 HRESULT hr;
575 VARIANT var;
577 TRACE("%p\n", iface);
579 hr = ADsBuildVarArrayStr(NULL, 0, &var);
580 if (hr == S_OK)
582 hr = IADs_GetInfoEx(iface, var, 0);
583 VariantClear(&var);
585 return hr;
588 static HRESULT WINAPI ldapns_SetInfo(IADs *iface)
590 FIXME("%p: stub\n", iface);
591 return E_NOTIMPL;
594 static HRESULT WINAPI ldapns_Get(IADs *iface, BSTR name, VARIANT *prop)
596 LDAP_namespace *ldap = impl_from_IADs(iface);
597 HRESULT hr;
598 ULONG i;
600 TRACE("%p,%s,%p\n", iface, debugstr_w(name), prop);
602 if (!name || !prop) return E_ADS_BAD_PARAMETER;
604 if (!ldap->attrs_count)
606 hr = IADs_GetInfo(iface);
607 if (hr != S_OK) return hr;
610 for (i = 0; i < ldap->attrs_count; i++)
612 if (!wcsicmp(name, ldap->attrs[i].name))
614 LONG count = ldap_count_valuesW(ldap->attrs[i].values);
615 if (!count)
617 V_BSTR(prop) = NULL;
618 V_VT(prop) = VT_BSTR;
619 return S_OK;
622 if (count > 1)
624 SAFEARRAY *sa;
625 VARIANT item;
626 LONG idx;
628 TRACE("attr %s has %lu values\n", debugstr_w(ldap->attrs[i].name), count);
630 sa = SafeArrayCreateVector(VT_VARIANT, 0, count);
631 if (!sa) return E_OUTOFMEMORY;
633 for (idx = 0; idx < count; idx++)
635 TRACE("=> %s\n", debugstr_w(ldap->attrs[i].values[idx]));
636 V_VT(&item) = VT_BSTR;
637 V_BSTR(&item) = SysAllocString(ldap->attrs[i].values[idx]);
638 if (!V_BSTR(&item))
640 hr = E_OUTOFMEMORY;
641 goto fail;
644 hr = SafeArrayPutElement(sa, &idx, &item);
645 SysFreeString(V_BSTR(&item));
646 if (hr != S_OK) goto fail;
649 V_VT(prop) = VT_ARRAY | VT_VARIANT;
650 V_ARRAY(prop) = sa;
651 return S_OK;
652 fail:
653 SafeArrayDestroy(sa);
654 return hr;
656 else
658 TRACE("=> %s\n", debugstr_w(ldap->attrs[i].values[0]));
659 V_BSTR(prop) = SysAllocString(ldap->attrs[i].values[0]);
660 if (!V_BSTR(prop)) return E_OUTOFMEMORY;
661 V_VT(prop) = VT_BSTR;
662 return S_OK;
667 return E_ADS_PROPERTY_NOT_FOUND;
670 static HRESULT WINAPI ldapns_Put(IADs *iface, BSTR name, VARIANT prop)
672 FIXME("%p,%s,%s: stub\n", iface, debugstr_w(name), wine_dbgstr_variant(&prop));
673 return E_NOTIMPL;
676 static HRESULT WINAPI ldapns_GetEx(IADs *iface, BSTR name, VARIANT *prop)
678 FIXME("%p,%s,%p: stub\n", iface, debugstr_w(name), prop);
679 return E_NOTIMPL;
682 static HRESULT WINAPI ldapns_PutEx(IADs *iface, LONG code, BSTR name, VARIANT prop)
684 FIXME("%p,%ld,%s,%s: stub\n", iface, code, debugstr_w(name), wine_dbgstr_variant(&prop));
685 return E_NOTIMPL;
688 static HRESULT add_attribute(LDAP_namespace *ldap, WCHAR *name, WCHAR **values)
690 struct ldap_attribute *new_attrs;
692 if (!ldap->attrs)
694 ldap->attrs = malloc(256 * sizeof(ldap->attrs[0]));
695 if (!ldap->attrs) return E_OUTOFMEMORY;
696 ldap->attrs_count_allocated = 256;
698 else if (ldap->attrs_count_allocated < ldap->attrs_count + 1)
700 new_attrs = realloc(ldap->attrs, (ldap->attrs_count_allocated * 2) * sizeof(*new_attrs));
701 if (!new_attrs) return E_OUTOFMEMORY;
703 ldap->attrs_count_allocated *= 2;
704 ldap->attrs = new_attrs;
707 ldap->attrs[ldap->attrs_count].name = name;
708 ldap->attrs[ldap->attrs_count].values = values;
709 ldap->attrs_count++;
711 return S_OK;
714 static HRESULT WINAPI ldapns_GetInfoEx(IADs *iface, VARIANT prop, LONG reserved)
716 LDAP_namespace *ldap = impl_from_IADs(iface);
717 HRESULT hr;
718 SAFEARRAY *sa;
719 VARIANT *item;
720 WCHAR **props = NULL, *attr, **values;
721 DWORD i, count, err;
722 LDAPMessage *res = NULL, *entry;
723 BerElement *ber;
725 TRACE("%p,%s,%ld\n", iface, wine_dbgstr_variant(&prop), reserved);
727 free_attributes(ldap);
729 if (!ldap->ld) return E_NOTIMPL;
731 if (V_VT(&prop) != (VT_ARRAY | VT_VARIANT))
732 return E_ADS_BAD_PARAMETER;
734 sa = V_ARRAY(&prop);
735 if (sa->cDims != 1)
736 return E_ADS_BAD_PARAMETER;
738 hr = SafeArrayAccessData(sa, (void *)&item);
739 if (hr != S_OK) return hr;
741 count = sa->rgsabound[0].cElements;
742 if (count)
744 props = malloc((count + 1) * sizeof(props[0]));
745 if (!props)
747 hr = E_OUTOFMEMORY;
748 goto exit;
751 for (i = 0; i < count; i++)
753 if (V_VT(&item[i]) != VT_BSTR)
755 hr = E_ADS_BAD_PARAMETER;
756 goto exit;
758 props[i] = V_BSTR(&item[i]);
760 props[sa->rgsabound[0].cElements] = NULL;
763 err = ldap_search_sW(ldap->ld, NULL, LDAP_SCOPE_BASE, (WCHAR *)L"(objectClass=*)", props, FALSE, &res);
764 if (err != LDAP_SUCCESS)
766 TRACE("ldap_search_sW error %#lx\n", err);
767 hr = HRESULT_FROM_WIN32(map_ldap_error(err));
768 goto exit;
771 entry = ldap_first_entry(ldap->ld, res);
772 while (entry)
774 attr = ldap_first_attributeW(ldap->ld, entry, &ber);
775 while (attr)
777 TRACE("attr: %s\n", debugstr_w(attr));
779 values = ldap_get_valuesW(ldap->ld, entry, attr);
781 hr = add_attribute(ldap, attr, values);
782 if (hr != S_OK)
784 ldap_value_freeW(values);
785 ldap_memfreeW(attr);
786 ber_free(ber, 0);
787 goto exit;
790 attr = ldap_next_attributeW(ldap->ld, entry, ber);
793 ber_free(ber, 0);
794 entry = ldap_next_entry(ldap->ld, res);
797 exit:
798 if (res) ldap_msgfree(res);
799 free(props);
800 SafeArrayUnaccessData(sa);
801 return hr;
804 static const IADsVtbl IADs_vtbl =
806 ldapns_QueryInterface,
807 ldapns_AddRef,
808 ldapns_Release,
809 ldapns_GetTypeInfoCount,
810 ldapns_GetTypeInfo,
811 ldapns_GetIDsOfNames,
812 ldapns_Invoke,
813 ldapns_get_Name,
814 ldapns_get_Class,
815 ldapns_get_GUID,
816 ldapns_get_ADsPath,
817 ldapns_get_Parent,
818 ldapns_get_Schema,
819 ldapns_GetInfo,
820 ldapns_SetInfo,
821 ldapns_Get,
822 ldapns_Put,
823 ldapns_GetEx,
824 ldapns_PutEx,
825 ldapns_GetInfoEx
828 static inline LDAP_namespace *impl_from_IADsOpenDSObject(IADsOpenDSObject *iface)
830 return CONTAINING_RECORD(iface, LDAP_namespace, IADsOpenDSObject_iface);
833 static HRESULT WINAPI openobj_QueryInterface(IADsOpenDSObject *iface, REFIID riid, void **obj)
835 TRACE("%p,%s,%p\n", iface, debugstr_guid(riid), obj);
837 if (!riid || !obj) return E_INVALIDARG;
839 if (IsEqualGUID(riid, &IID_IADsOpenDSObject) ||
840 IsEqualGUID(riid, &IID_IDispatch) ||
841 IsEqualGUID(riid, &IID_IUnknown))
843 IADsOpenDSObject_AddRef(iface);
844 *obj = iface;
845 return S_OK;
848 FIXME("interface %s is not implemented\n", debugstr_guid(riid));
849 return E_NOINTERFACE;
852 static ULONG WINAPI openobj_AddRef(IADsOpenDSObject *iface)
854 LDAP_namespace *ldap = impl_from_IADsOpenDSObject(iface);
855 return IADs_AddRef(&ldap->IADs_iface);
858 static ULONG WINAPI openobj_Release(IADsOpenDSObject *iface)
860 LDAP_namespace *ldap = impl_from_IADsOpenDSObject(iface);
861 return IADs_Release(&ldap->IADs_iface);
864 static HRESULT WINAPI openobj_GetTypeInfoCount(IADsOpenDSObject *iface, UINT *count)
866 FIXME("%p,%p: stub\n", iface, count);
867 return E_NOTIMPL;
870 static HRESULT WINAPI openobj_GetTypeInfo(IADsOpenDSObject *iface, UINT index, LCID lcid, ITypeInfo **info)
872 FIXME("%p,%u,%#lx,%p: stub\n", iface, index, lcid, info);
873 return E_NOTIMPL;
876 static HRESULT WINAPI openobj_GetIDsOfNames(IADsOpenDSObject *iface, REFIID riid, LPOLESTR *names,
877 UINT count, LCID lcid, DISPID *dispid)
879 FIXME("%p,%s,%p,%u,%lu,%p: stub\n", iface, debugstr_guid(riid), names, count, lcid, dispid);
880 return E_NOTIMPL;
883 static HRESULT WINAPI openobj_Invoke(IADsOpenDSObject *iface, DISPID dispid, REFIID riid, LCID lcid, WORD flags,
884 DISPPARAMS *params, VARIANT *result, EXCEPINFO *excepinfo, UINT *argerr)
886 FIXME("%p,%ld,%s,%04lx,%04x,%p,%p,%p,%p: stub\n", iface, dispid, debugstr_guid(riid), lcid, flags,
887 params, result, excepinfo, argerr);
888 return E_NOTIMPL;
891 static HRESULT parse_path(WCHAR *path, BSTR *host, ULONG *port, BSTR *object)
893 WCHAR *p, *p_host;
894 int host_len;
896 if (host) *host = NULL;
897 if (port) *port = 0;
898 if (object) *object = NULL;
900 if (wcsnicmp(path, L"LDAP:", 5) != 0)
901 return E_ADS_BAD_PATHNAME;
903 p = path + 5;
904 if (!*p) return S_OK;
906 if (*p++ != '/' || *p++ != '/' || !*p)
907 return E_ADS_BAD_PATHNAME;
909 p_host = p;
910 host_len = 0;
911 while (*p && *p != '/')
913 if (*p == ':')
915 ULONG dummy;
916 if (!port) port = &dummy;
917 *port = wcstol(p + 1, &p, 10);
918 if (*p && *p != '/') return E_ADS_BAD_PATHNAME;
920 else
922 p++;
923 host_len++;
926 if (host_len == 0) return E_ADS_BAD_PATHNAME;
928 if (host)
930 *host = SysAllocStringLen(p_host, host_len);
931 if (!*host) return E_OUTOFMEMORY;
934 if (!*p) return S_OK;
936 if (*p++ != '/' || !*p)
938 SysFreeString(*host);
939 return E_ADS_BAD_PATHNAME;
942 if (object)
944 *object = SysAllocString(p);
945 if (!*object)
947 SysFreeString(*host);
948 return E_OUTOFMEMORY;
952 return S_OK;
955 static HRESULT WINAPI openobj_OpenDSObject(IADsOpenDSObject *iface, BSTR path, BSTR user, BSTR password,
956 LONG flags, IDispatch **obj)
958 BSTR host, object;
959 ULONG port;
960 IADs *ads;
961 LDAP *ld = NULL;
962 HRESULT hr;
963 ULONG err, at_single_count = 0, at_multiple_count = 0;
964 struct attribute_type *at = NULL;
966 TRACE("%p,%s,%s,%p,%08lx,%p\n", iface, debugstr_w(path), debugstr_w(user), password, flags, obj);
968 hr = parse_path(path, &host, &port, &object);
969 if (hr != S_OK) return hr;
971 TRACE("host %s, port %lu, object %s\n", debugstr_w(host), port, debugstr_w(object));
973 if (host)
975 int version;
977 if (!wcsicmp(host, L"rootDSE"))
979 DOMAIN_CONTROLLER_INFOW *dcinfo;
981 if (object)
983 hr = E_ADS_BAD_PATHNAME;
984 goto fail;
987 object = host;
989 err = DsGetDcNameW(NULL, NULL, NULL, NULL, DS_RETURN_DNS_NAME, &dcinfo);
990 if (err != ERROR_SUCCESS)
992 hr = HRESULT_FROM_WIN32(err);
993 goto fail;
996 host = SysAllocString(dcinfo->DomainName);
997 NetApiBufferFree(dcinfo);
999 if (!host)
1001 hr = E_OUTOFMEMORY;
1002 goto fail;
1006 ld = ldap_initW(host, port);
1007 if (!ld)
1009 hr = HRESULT_FROM_WIN32(LdapGetLastError());
1010 goto fail;
1013 version = LDAP_VERSION3;
1014 err = ldap_set_optionW(ld, LDAP_OPT_PROTOCOL_VERSION, &version);
1015 if (err != LDAP_SUCCESS)
1017 hr = HRESULT_FROM_WIN32(map_ldap_error(err));
1018 ldap_unbind(ld);
1019 goto fail;
1022 err = ldap_connect(ld, NULL);
1023 if (err != LDAP_SUCCESS)
1025 hr = HRESULT_FROM_WIN32(map_ldap_error(err));
1026 ldap_unbind(ld);
1027 goto fail;
1030 if (flags & ADS_SECURE_AUTHENTICATION)
1032 SEC_WINNT_AUTH_IDENTITY_W id;
1034 id.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
1035 id.Domain = (unsigned short *)host;
1036 id.DomainLength = wcslen(host);
1037 id.User = (unsigned short *)user;
1038 id.UserLength = user ? wcslen(user) : 0;
1039 id.Password = (unsigned short *)password;
1040 id.PasswordLength = password ? wcslen(password) : 0;
1042 err = ldap_bind_sW(ld, NULL, (WCHAR *)&id, LDAP_AUTH_NEGOTIATE);
1043 if (err != LDAP_SUCCESS)
1045 TRACE("ldap_bind_sW error %#lx\n", err);
1046 hr = HRESULT_FROM_WIN32(map_ldap_error(err));
1047 ldap_unbind(ld);
1048 goto fail;
1051 else
1053 err = ldap_simple_bind_sW(ld, user, password);
1054 if (err != LDAP_SUCCESS)
1056 TRACE("ldap_simple_bind_sW error %#lx\n", err);
1057 hr = HRESULT_FROM_WIN32(map_ldap_error(err));
1058 ldap_unbind(ld);
1059 goto fail;
1063 at = load_schema(ld, &at_single_count, &at_multiple_count);
1066 hr = LDAPNamespace_create(&IID_IADs, (void **)&ads);
1067 if (hr == S_OK)
1069 LDAP_namespace *ldap = impl_from_IADs(ads);
1070 ldap->ld = ld;
1071 ldap->host = host;
1072 ldap->port = port;
1073 ldap->object = object;
1074 ldap->at = at;
1075 ldap->at_single_count = at_single_count;
1076 ldap->at_multiple_count = at_multiple_count;
1077 hr = IADs_QueryInterface(ads, &IID_IDispatch, (void **)obj);
1078 IADs_Release(ads);
1079 return hr;
1082 fail:
1083 SysFreeString(host);
1084 SysFreeString(object);
1086 return hr;
1089 static const IADsOpenDSObjectVtbl IADsOpenDSObject_vtbl =
1091 openobj_QueryInterface,
1092 openobj_AddRef,
1093 openobj_Release,
1094 openobj_GetTypeInfoCount,
1095 openobj_GetTypeInfo,
1096 openobj_GetIDsOfNames,
1097 openobj_Invoke,
1098 openobj_OpenDSObject
1101 static inline LDAP_namespace *impl_from_IDirectorySearch(IDirectorySearch *iface)
1103 return CONTAINING_RECORD(iface, LDAP_namespace, IDirectorySearch_iface);
1106 static HRESULT WINAPI search_QueryInterface(IDirectorySearch *iface, REFIID riid, void **obj)
1108 TRACE("%p,%s,%p\n", iface, debugstr_guid(riid), obj);
1110 if (!riid || !obj) return E_INVALIDARG;
1112 if (IsEqualGUID(riid, &IID_IDirectorySearch) ||
1113 IsEqualGUID(riid, &IID_IUnknown))
1115 IDirectorySearch_AddRef(iface);
1116 *obj = iface;
1117 return S_OK;
1120 FIXME("interface %s is not implemented\n", debugstr_guid(riid));
1121 return E_NOINTERFACE;
1124 static ULONG WINAPI search_AddRef(IDirectorySearch *iface)
1126 LDAP_namespace *ldap = impl_from_IDirectorySearch(iface);
1127 return IADs_AddRef(&ldap->IADs_iface);
1130 static ULONG WINAPI search_Release(IDirectorySearch *iface)
1132 LDAP_namespace *ldap = impl_from_IDirectorySearch(iface);
1133 return IADs_Release(&ldap->IADs_iface);
1136 static HRESULT WINAPI search_SetSearchPreference(IDirectorySearch *iface, PADS_SEARCHPREF_INFO prefs, DWORD count)
1138 LDAP_namespace *ldap = impl_from_IDirectorySearch(iface);
1139 HRESULT hr = S_OK;
1140 DWORD i;
1142 TRACE("%p,%p,%lu\n", iface, prefs, count);
1144 for (i = 0; i < count; i++)
1146 switch (prefs[i].dwSearchPref)
1148 case ADS_SEARCHPREF_SEARCH_SCOPE:
1149 if (prefs[i].vValue.dwType != ADSTYPE_INTEGER)
1151 FIXME("ADS_SEARCHPREF_SEARCH_SCOPE: unsupported dwType %d\n", prefs[i].vValue.dwType);
1152 prefs[i].dwStatus = ADS_STATUS_INVALID_SEARCHPREFVALUE;
1153 break;
1156 switch (prefs[i].vValue.Integer)
1158 case ADS_SCOPE_BASE:
1159 case ADS_SCOPE_ONELEVEL:
1160 case ADS_SCOPE_SUBTREE:
1161 TRACE("SEARCH_SCOPE: %ld\n", prefs[i].vValue.Integer);
1162 ldap->search.scope = prefs[i].vValue.Integer;
1163 prefs[i].dwStatus = ADS_STATUS_S_OK;
1164 break;
1166 default:
1167 prefs[i].dwStatus = ADS_STATUS_INVALID_SEARCHPREFVALUE;
1168 break;
1170 break;
1172 case ADS_SEARCHPREF_SECURITY_MASK:
1174 int security_mask;
1175 ULONG err;
1176 BerElement *ber;
1177 struct berval *berval;
1178 LDAPControlW *ctrls[2], mask;
1180 if (prefs[i].vValue.dwType != ADSTYPE_INTEGER)
1182 FIXME("ADS_SEARCHPREF_SECURITY_MASK: not supported dwType %d\n", prefs[i].vValue.dwType);
1183 prefs[i].dwStatus = ADS_STATUS_INVALID_SEARCHPREFVALUE;
1184 break;
1187 TRACE("SECURITY_MASK: %08lx\n", prefs[i].vValue.Integer);
1188 security_mask = prefs[i].vValue.Integer;
1189 if (!security_mask)
1190 security_mask = ADS_SECURITY_INFO_OWNER;
1192 ber = ber_alloc_t(LBER_USE_DER);
1193 if (!ber || ber_printf(ber, (char *)"{i}", security_mask) == -1 || ber_flatten(ber, &berval) == -1)
1195 ber_free(ber, 1);
1196 prefs[i].dwStatus = ADS_STATUS_INVALID_SEARCHPREF;
1197 break;
1199 TRACE("ber: %s\n", debugstr_an(berval->bv_val, berval->bv_len));
1201 mask.ldctl_oid = (WCHAR *)L"1.2.840.113556.1.4.801";
1202 mask.ldctl_iscritical = TRUE;
1203 mask.ldctl_value.bv_val = berval->bv_val;
1204 mask.ldctl_value.bv_len = berval->bv_len;
1205 ctrls[0] = &mask;
1206 ctrls[1] = NULL;
1207 err = ldap_set_optionW(ldap->ld, LDAP_OPT_SERVER_CONTROLS, ctrls);
1208 if (err != LDAP_SUCCESS)
1210 TRACE("ldap_set_option error %#lx\n", err);
1211 prefs[i].dwStatus = ADS_STATUS_INVALID_SEARCHPREF;
1212 hr = S_ADS_ERRORSOCCURRED;
1214 else
1215 prefs[i].dwStatus = ADS_STATUS_S_OK;
1217 ber_bvfree(berval);
1218 ber_free(ber, 1);
1219 break;
1222 case ADS_SEARCHPREF_PAGESIZE:
1223 if (prefs[i].vValue.dwType != ADSTYPE_INTEGER)
1225 FIXME("ADS_SEARCHPREF_PAGESIZE: unsupported dwType %d\n", prefs[i].vValue.dwType);
1226 prefs[i].dwStatus = ADS_STATUS_INVALID_SEARCHPREFVALUE;
1227 break;
1230 TRACE("PAGESIZE: %ld\n", prefs[i].vValue.Integer);
1231 ldap->search.pagesize = prefs[i].vValue.Integer;
1232 prefs[i].dwStatus = ADS_STATUS_S_OK;
1233 break;
1235 case ADS_SEARCHPREF_CACHE_RESULTS:
1236 if (prefs[i].vValue.dwType != ADSTYPE_BOOLEAN)
1238 FIXME("ADS_SEARCHPREF_CACHE_RESULTS: unsupported dwType %d\n", prefs[i].vValue.dwType);
1239 prefs[i].dwStatus = ADS_STATUS_INVALID_SEARCHPREFVALUE;
1240 break;
1243 TRACE("CACHE_RESULTS: %ld\n", prefs[i].vValue.Boolean);
1244 ldap->search.cache_results = prefs[i].vValue.Boolean;
1245 prefs[i].dwStatus = ADS_STATUS_S_OK;
1246 break;
1248 case ADS_SEARCHPREF_ATTRIBTYPES_ONLY:
1249 if (prefs[i].vValue.dwType != ADSTYPE_BOOLEAN)
1251 FIXME("ADS_SEARCHPREF_ATTRIBTYPES_ONLY: unsupported dwType %d\n", prefs[i].vValue.dwType);
1252 prefs[i].dwStatus = ADS_STATUS_INVALID_SEARCHPREFVALUE;
1253 break;
1256 TRACE("ATTRIBTYPES_ONLY: %ld\n", prefs[i].vValue.Boolean);
1257 ldap->search.attribtypes_only = prefs[i].vValue.Boolean;
1258 prefs[i].dwStatus = ADS_STATUS_S_OK;
1259 break;
1261 case ADS_SEARCHPREF_TOMBSTONE:
1262 if (prefs[i].vValue.dwType != ADSTYPE_BOOLEAN)
1264 FIXME("ADS_SEARCHPREF_TOMBSTONE: unsupported dwType %d\n", prefs[i].vValue.dwType);
1265 prefs[i].dwStatus = ADS_STATUS_INVALID_SEARCHPREFVALUE;
1266 break;
1269 TRACE("TOMBSTONE: %ld\n", prefs[i].vValue.Boolean);
1270 ldap->search.tombstone = prefs[i].vValue.Boolean;
1271 prefs[i].dwStatus = ADS_STATUS_S_OK;
1272 break;
1274 case ADS_SEARCHPREF_SIZE_LIMIT:
1275 if (prefs[i].vValue.dwType != ADSTYPE_INTEGER)
1277 FIXME("ADS_SEARCHPREF_SIZE_LIMIT: unsupported dwType %d\n", prefs[i].vValue.dwType);
1278 prefs[i].dwStatus = ADS_STATUS_INVALID_SEARCHPREFVALUE;
1279 break;
1282 TRACE("SIZE_LIMIT: %ld\n", prefs[i].vValue.Integer);
1283 ldap->search.size_limit = prefs[i].vValue.Integer;
1284 prefs[i].dwStatus = ADS_STATUS_S_OK;
1285 break;
1287 default:
1288 FIXME("pref %d, type %u: stub\n", prefs[i].dwSearchPref, prefs[i].vValue.dwType);
1289 prefs[i].dwStatus = ADS_STATUS_INVALID_SEARCHPREF;
1290 break;
1294 return hr;
1297 static HRESULT WINAPI search_ExecuteSearch(IDirectorySearch *iface, LPWSTR filter, LPWSTR *names,
1298 DWORD count, PADS_SEARCH_HANDLE res)
1300 LDAP_namespace *ldap = impl_from_IDirectorySearch(iface);
1301 ULONG err, i;
1302 WCHAR **props;
1303 LDAPControlW **ctrls = NULL, *ctrls_a[2], tombstone;
1304 struct ldap_search_context *ldap_ctx;
1306 TRACE("%p,%s,%p,%lu,%p\n", iface, debugstr_w(filter), names, count, res);
1308 if (!res) return E_ADS_BAD_PARAMETER;
1310 ldap_ctx = calloc(1, sizeof(*ldap_ctx));
1311 if (!ldap_ctx) return E_OUTOFMEMORY;
1313 if (count == 0xffffffff)
1314 props = NULL;
1315 else
1317 if (count && !names)
1319 free(ldap_ctx);
1320 return E_ADS_BAD_PARAMETER;
1323 props = malloc((count + 1) * sizeof(props[0]));
1324 if (!props)
1326 free(ldap_ctx);
1327 return E_OUTOFMEMORY;
1330 for (i = 0; i < count; i++)
1332 TRACE("=> %s\n", debugstr_w(names[i]));
1333 props[i] = names[i];
1336 props[count] = NULL;
1339 if (ldap->search.tombstone)
1341 tombstone.ldctl_oid = (WCHAR *)L"1.2.840.113556.1.4.417";
1342 tombstone.ldctl_iscritical = TRUE;
1343 tombstone.ldctl_value.bv_val = NULL;
1344 tombstone.ldctl_value.bv_len = 0;
1345 ctrls_a[0] = &tombstone;
1346 ctrls_a[1] = NULL;
1347 ctrls = ctrls_a;
1350 if (ldap->search.pagesize)
1352 ldap_ctx->page = ldap_search_init_pageW(ldap->ld, ldap->object, ldap->search.scope,
1353 filter, props, ldap->search.attribtypes_only,
1354 ctrls, NULL, 0, ldap->search.size_limit, NULL);
1355 if (ldap_ctx->page)
1356 err = ldap_get_next_page_s(ldap->ld, ldap_ctx->page, NULL,
1357 ldap->search.pagesize, &count, &ldap_ctx->res);
1358 else
1359 err = LDAP_NO_MEMORY;
1361 else
1362 err = ldap_search_ext_sW(ldap->ld, ldap->object, ldap->search.scope, filter, props,
1363 ldap->search.attribtypes_only, ctrls, NULL, NULL, ldap->search.size_limit,
1364 &ldap_ctx->res);
1365 free(props);
1366 if (err != LDAP_SUCCESS)
1368 TRACE("ldap_search_sW error %#lx\n", err);
1369 if (ldap_ctx->page)
1370 ldap_search_abandon_page(ldap->ld, ldap_ctx->page);
1371 free(ldap_ctx);
1372 return HRESULT_FROM_WIN32(map_ldap_error(err));
1375 *res = ldap_ctx;
1376 return S_OK;
1379 static HRESULT WINAPI search_AbandonSearch(IDirectorySearch *iface, ADS_SEARCH_HANDLE res)
1381 FIXME("%p,%p: stub\n", iface, res);
1382 return E_NOTIMPL;
1385 static HRESULT WINAPI search_GetFirstRow(IDirectorySearch *iface, ADS_SEARCH_HANDLE res)
1387 struct ldap_search_context *ldap_ctx = res;
1389 TRACE("%p,%p\n", iface, res);
1391 if (!res) return E_ADS_BAD_PARAMETER;
1393 ldap_ctx->entry = NULL;
1395 return IDirectorySearch_GetNextRow(iface, res);
1398 static HRESULT WINAPI search_GetNextRow(IDirectorySearch *iface, ADS_SEARCH_HANDLE res)
1400 LDAP_namespace *ldap = impl_from_IDirectorySearch(iface);
1401 struct ldap_search_context *ldap_ctx = res;
1403 TRACE("%p,%p\n", iface, res);
1405 if (!res) return E_ADS_BAD_PARAMETER;
1407 if (!ldap_ctx->entry)
1409 ldap_ctx->count = ldap_count_entries(ldap->ld, ldap_ctx->res);
1410 ldap_ctx->pos = 0;
1412 if (ldap_ctx->pos >= ldap_ctx->count)
1413 return S_ADS_NOMORE_ROWS;
1415 ldap_ctx->entry = ldap_first_entry(ldap->ld, ldap_ctx->res);
1417 else
1419 if (ldap_ctx->pos >= ldap_ctx->count)
1421 if (ldap_ctx->page)
1423 ULONG err, count;
1425 ldap_msgfree(ldap_ctx->res);
1426 ldap_ctx->res = NULL;
1428 err = ldap_get_next_page_s(ldap->ld, ldap_ctx->page, NULL, ldap->search.pagesize, &count, &ldap_ctx->res);
1429 if (err == LDAP_SUCCESS)
1431 ldap_ctx->count = ldap_count_entries(ldap->ld, ldap_ctx->res);
1432 ldap_ctx->pos = 0;
1434 if (ldap_ctx->pos >= ldap_ctx->count)
1435 return S_ADS_NOMORE_ROWS;
1437 ldap_ctx->entry = ldap_first_entry(ldap->ld, ldap_ctx->res);
1438 goto exit;
1441 if (err != LDAP_NO_RESULTS_RETURNED)
1443 TRACE("ldap_get_next_page_s error %#lx\n", err);
1444 return HRESULT_FROM_WIN32(map_ldap_error(err));
1446 /* fall through */
1449 return S_ADS_NOMORE_ROWS;
1452 ldap_ctx->entry = ldap_next_entry(ldap->ld, ldap_ctx->entry);
1455 exit:
1456 if (!ldap_ctx->entry)
1457 return S_ADS_NOMORE_ROWS;
1459 ldap_ctx->pos++;
1460 ldap_ctx->ber = NULL;
1462 return S_OK;
1465 static HRESULT WINAPI search_GetPreviousRow(IDirectorySearch *iface, ADS_SEARCH_HANDLE res)
1467 FIXME("%p,%p: stub\n", iface, res);
1468 return E_NOTIMPL;
1471 static HRESULT WINAPI search_GetNextColumnName(IDirectorySearch *iface, ADS_SEARCH_HANDLE res, LPWSTR *name)
1473 LDAP_namespace *ldap = impl_from_IDirectorySearch(iface);
1474 struct ldap_search_context *ldap_ctx = res;
1475 WCHAR *attr;
1477 TRACE("%p,%p,%p\n", iface, res, name);
1479 if (!name || !ldap_ctx || !ldap_ctx->entry) return E_ADS_BAD_PARAMETER;
1481 if (!ldap_ctx->ber)
1483 attr = ldap_first_attributeW(ldap->ld, ldap_ctx->entry, &ldap_ctx->ber);
1484 ldap_ctx->add_ADsPath = TRUE;
1486 else
1487 attr = ldap_next_attributeW(ldap->ld, ldap_ctx->entry, ldap_ctx->ber);
1489 if (attr)
1491 TRACE("=> %s\n", debugstr_w(attr));
1492 *name = AllocADsStr(attr);
1493 ldap_memfreeW(attr);
1494 return *name ? S_OK : E_OUTOFMEMORY;
1496 else if (ldap_ctx->add_ADsPath)
1498 ldap_ctx->add_ADsPath = FALSE;
1499 *name = AllocADsStr((WCHAR *)L"ADsPath");
1500 TRACE("=> %s\n", debugstr_w(*name));
1501 return *name ? S_OK : E_OUTOFMEMORY;
1504 *name = NULL;
1505 return S_ADS_NOMORE_COLUMNS;
1508 static HRESULT add_column_values(LDAP_namespace *ldap, struct ldap_search_context *ldap_ctx,
1509 LPWSTR name, ADS_SEARCH_COLUMN *col)
1511 ADSTYPEENUM type;
1512 DWORD i, count;
1514 type = get_schema_type(name, ldap->at, ldap->at_single_count, ldap->at_multiple_count);
1515 TRACE("%s => type %d\n", debugstr_w(name), type);
1517 switch (type)
1519 default:
1520 FIXME("no special handling for type %d\n", type);
1521 /* fall through */
1522 case ADSTYPE_DN_STRING:
1523 case ADSTYPE_CASE_EXACT_STRING:
1524 case ADSTYPE_CASE_IGNORE_STRING:
1525 case ADSTYPE_PRINTABLE_STRING:
1527 WCHAR **values = ldap_get_valuesW(ldap->ld, ldap_ctx->entry, name);
1528 if (!values)
1529 return E_ADS_COLUMN_NOT_SET;
1530 count = ldap_count_valuesW(values);
1532 col->pADsValues = calloc(count, sizeof(col->pADsValues[0]));
1533 if (!col->pADsValues)
1535 ldap_value_freeW(values);
1536 return E_OUTOFMEMORY;
1539 for (i = 0; i < count; i++)
1541 TRACE("=> %s\n", debugstr_w(values[i]));
1542 col->pADsValues[i].dwType = type;
1543 col->pADsValues[i].CaseIgnoreString = values[i];
1546 col->hReserved = values;
1547 break;
1550 case ADSTYPE_BOOLEAN:
1552 WCHAR **values = ldap_get_valuesW(ldap->ld, ldap_ctx->entry, name);
1553 if (!values)
1554 return E_ADS_COLUMN_NOT_SET;
1555 count = ldap_count_valuesW(values);
1557 col->pADsValues = calloc(count, sizeof(col->pADsValues[0]));
1558 if (!col->pADsValues)
1560 ldap_value_freeW(values);
1561 return E_OUTOFMEMORY;
1564 for (i = 0; i < count; i++)
1566 col->pADsValues[i].dwType = type;
1568 if (!wcsicmp(values[i], L"TRUE"))
1569 col->pADsValues[i].Boolean = 1;
1570 else if (!wcsicmp(values[i], L"FALSE"))
1571 col->pADsValues[i].Boolean = 0;
1572 else
1574 FIXME("not recognized boolean value %s\n", debugstr_w(values[i]));
1575 col->pADsValues[i].Boolean = 0;
1577 TRACE("%s => %ld\n", debugstr_w(values[i]), col->pADsValues[i].Boolean);
1580 ldap_value_freeW(values);
1581 col->hReserved = NULL;
1582 break;
1585 case ADSTYPE_INTEGER:
1586 case ADSTYPE_LARGE_INTEGER:
1588 struct berval **values = ldap_get_values_lenW(ldap->ld, ldap_ctx->entry, name);
1589 if (!values)
1590 return E_ADS_COLUMN_NOT_SET;
1591 count = ldap_count_values_len(values);
1593 col->pADsValues = calloc(count, sizeof(col->pADsValues[0]));
1594 if (!col->pADsValues)
1596 ldap_value_free_len(values);
1597 return E_OUTOFMEMORY;
1600 for (i = 0; i < count; i++)
1602 col->pADsValues[i].dwType = type;
1604 if (type == ADSTYPE_LARGE_INTEGER)
1606 col->pADsValues[i].LargeInteger.QuadPart = _atoi64(values[i]->bv_val);
1607 TRACE("%s => %s\n", debugstr_an(values[i]->bv_val, values[i]->bv_len), wine_dbgstr_longlong(col->pADsValues[i].LargeInteger.QuadPart));
1609 else
1611 col->pADsValues[i].Integer = atol(values[i]->bv_val);
1612 TRACE("%s => %ld\n", debugstr_an(values[i]->bv_val, values[i]->bv_len), col->pADsValues[i].Integer);
1616 ldap_value_free_len(values);
1617 col->hReserved = NULL;
1618 break;
1621 case ADSTYPE_OCTET_STRING:
1622 case ADSTYPE_NT_SECURITY_DESCRIPTOR:
1624 struct berval **values = ldap_get_values_lenW(ldap->ld, ldap_ctx->entry, name);
1625 if (!values)
1626 return E_ADS_COLUMN_NOT_SET;
1627 count = ldap_count_values_len(values);
1629 col->pADsValues = calloc(count, sizeof(col->pADsValues[0]));
1630 if (!col->pADsValues)
1632 ldap_value_free_len(values);
1633 return E_OUTOFMEMORY;
1636 for (i = 0; i < count; i++)
1638 TRACE("=> %s\n", debugstr_an(values[i]->bv_val, values[i]->bv_len));
1639 col->pADsValues[i].dwType = type;
1640 col->pADsValues[i].OctetString.dwLength = values[i]->bv_len;
1641 col->pADsValues[i].OctetString.lpValue = (BYTE *)values[i]->bv_val;
1644 col->hReserved = values;
1645 break;
1648 case ADSTYPE_UTC_TIME:
1650 struct berval **values = ldap_get_values_lenW(ldap->ld, ldap_ctx->entry, name);
1651 if (!values)
1652 return E_ADS_COLUMN_NOT_SET;
1653 count = ldap_count_values_len(values);
1655 col->pADsValues = calloc(count, sizeof(col->pADsValues[0]));
1656 if (!col->pADsValues)
1658 ldap_value_free_len(values);
1659 return E_OUTOFMEMORY;
1662 for (i = 0; i < count; i++)
1664 col->pADsValues[i].dwType = type;
1665 if (values[i]->bv_len < 14 ||
1666 _snscanf_l(values[i]->bv_val, values[i]->bv_len, "%04hu%02hu%02hu%02hu%02hu%02hu", NULL,
1667 &col->pADsValues[i].UTCTime.wYear, &col->pADsValues[i].UTCTime.wMonth,
1668 &col->pADsValues[i].UTCTime.wDay, &col->pADsValues[i].UTCTime.wHour,
1669 &col->pADsValues[i].UTCTime.wMinute, &col->pADsValues[i].UTCTime.wSecond) != 6)
1671 FIXME("not recognized UTCTime: %s\n", debugstr_an(values[i]->bv_val, values[i]->bv_len));
1672 memset(&col->pADsValues[i].UTCTime, 0, sizeof(col->pADsValues[i].UTCTime));
1673 continue;
1676 if ((values[i]->bv_val[14] != '.' && values[i]->bv_val[14] != ',') ||
1677 values[i]->bv_val[15] != '0' || values[i]->bv_val[16] != 'Z')
1678 FIXME("not handled time zone: %s\n", debugstr_an(values[i]->bv_val + 14, values[i]->bv_len - 14));
1680 TRACE("%s => %02u.%02u.%04u %02u:%02u:%02u\n", debugstr_an(values[i]->bv_val, values[i]->bv_len),
1681 col->pADsValues[i].UTCTime.wDay, col->pADsValues[i].UTCTime.wMonth,
1682 col->pADsValues[i].UTCTime.wYear, col->pADsValues[i].UTCTime.wHour,
1683 col->pADsValues[i].UTCTime.wMinute, col->pADsValues[i].UTCTime.wSecond);
1686 ldap_value_free_len(values);
1687 col->hReserved = NULL;
1688 break;
1691 case ADSTYPE_DN_WITH_BINARY:
1693 static const BYTE hex2bin[] =
1695 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x00 */
1696 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x10 */
1697 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x20 */
1698 0,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0, /* 0x30 */
1699 0,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0, /* 0x40 */
1700 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x50 */
1701 0,10,11,12,13,14,15 /* 0x60 */
1703 ADS_DN_WITH_BINARY *dnb;
1704 WCHAR **values = ldap_get_valuesW(ldap->ld, ldap_ctx->entry, name);
1705 if (!values)
1706 return E_ADS_COLUMN_NOT_SET;
1707 count = ldap_count_valuesW(values);
1709 col->pADsValues = calloc(count, sizeof(col->pADsValues[0]) + sizeof(col->pADsValues[0].pDNWithBinary[0]));
1710 if (!col->pADsValues)
1712 ldap_value_freeW(values);
1713 return E_OUTOFMEMORY;
1716 dnb = (ADS_DN_WITH_BINARY *)(col->pADsValues + count);
1718 for (i = 0; i < count; i++)
1720 WCHAR *p = values[i];
1721 DWORD n;
1723 col->pADsValues[i].dwType = type;
1724 col->pADsValues[i].pDNWithBinary = dnb++;
1726 if ((p[0] != 'b' && p[0] != 'B') || p[1] != ':')
1727 FIXME("wrong DN with binary tag '%c%c'\n", p[0], p[1]);
1728 p += 2;
1730 col->pADsValues[i].pDNWithBinary->dwLength = wcstol(p, &p, 10) / 2;
1731 if (*p != ':')
1732 FIXME("wrong DN with binary separator '%c'\n", *p);
1733 p++;
1734 col->pADsValues[i].pDNWithBinary->lpBinaryValue = (BYTE *)p;
1735 /* decode values in-place */
1736 for (n = 0; n < col->pADsValues[i].pDNWithBinary->dwLength; n++, p += 2)
1738 BYTE b;
1740 if (p[0] > 'f' || (p[0] != '0' && !hex2bin[p[0]]) ||
1741 p[1] > 'f' || (p[1] != '0' && !hex2bin[p[1]]))
1743 FIXME("bad hex encoding at %s\n", debugstr_w(p));
1744 continue;
1747 b = (hex2bin[p[0]] << 4) | hex2bin[p[1]];
1748 col->pADsValues[i].pDNWithBinary->lpBinaryValue[n] = b;
1750 if (*p != ':')
1751 FIXME("wrong DN with binary separator '%c'\n", *p);
1752 col->pADsValues[i].pDNWithBinary->pszDNString = p + 1;
1754 TRACE("%s => %lu,%s,%s\n", debugstr_w(values[i]),
1755 col->pADsValues[i].pDNWithBinary->dwLength,
1756 debugstr_an((char *)col->pADsValues[i].pDNWithBinary->lpBinaryValue, col->pADsValues[i].pDNWithBinary->dwLength),
1757 debugstr_w(col->pADsValues[i].pDNWithBinary->pszDNString));
1760 col->hReserved = values;
1761 break;
1765 col->dwADsType = type;
1766 col->dwNumValues = count;
1767 col->pszAttrName = wcsdup(name);
1769 return S_OK;
1772 static HRESULT WINAPI search_GetColumn(IDirectorySearch *iface, ADS_SEARCH_HANDLE res,
1773 LPWSTR name, PADS_SEARCH_COLUMN col)
1775 LDAP_namespace *ldap = impl_from_IDirectorySearch(iface);
1776 struct ldap_search_context *ldap_ctx = res;
1777 HRESULT hr;
1778 ULONG count;
1780 TRACE("%p,%p,%s,%p\n", iface, res, debugstr_w(name), col);
1782 if (!res || !name || !ldap_ctx->entry) return E_ADS_BAD_PARAMETER;
1784 memset(col, 0, sizeof(*col));
1786 if (!wcsicmp(name, L"ADsPath"))
1788 WCHAR *dn = ldap_get_dnW(ldap->ld, ldap_ctx->entry);
1790 col->pADsValues = malloc(sizeof(col->pADsValues[0]));
1791 if (!col->pADsValues)
1793 hr = E_OUTOFMEMORY;
1794 goto exit;
1797 count = sizeof(L"LDAP://") + (wcslen(ldap->host) + 1 /* '/' */) * sizeof(WCHAR);
1798 if (dn) count += wcslen(dn) * sizeof(WCHAR);
1800 col->pADsValues[0].CaseIgnoreString = malloc(count);
1801 if (!col->pADsValues[0].CaseIgnoreString)
1803 hr = E_OUTOFMEMORY;
1804 goto exit;
1807 wcscpy(col->pADsValues[0].CaseIgnoreString, L"LDAP://");
1808 wcscat(col->pADsValues[0].CaseIgnoreString, ldap->host);
1809 wcscat(col->pADsValues[0].CaseIgnoreString, L"/");
1810 if (dn) wcscat(col->pADsValues[0].CaseIgnoreString, dn);
1811 col->pADsValues[0].dwType = ADSTYPE_CASE_IGNORE_STRING;
1812 col->dwADsType = ADSTYPE_CASE_IGNORE_STRING;
1813 col->dwNumValues = 1;
1814 col->pszAttrName = wcsdup(name);
1815 col->hReserved = NULL;
1817 TRACE("=> %s\n", debugstr_w(col->pADsValues[0].CaseIgnoreString));
1818 hr = S_OK;
1819 exit:
1820 ldap_memfreeW(dn);
1821 return hr;
1824 return add_column_values(ldap, ldap_ctx, name, col);
1827 static HRESULT WINAPI search_FreeColumn(IDirectorySearch *iface, PADS_SEARCH_COLUMN col)
1829 TRACE("%p,%p\n", iface, col);
1831 if (!col) return E_ADS_BAD_PARAMETER;
1833 if (!wcsicmp(col->pszAttrName, L"ADsPath"))
1834 free(col->pADsValues[0].CaseIgnoreString);
1835 free(col->pADsValues);
1836 free(col->pszAttrName);
1838 if (col->hReserved)
1840 if (col->dwADsType == ADSTYPE_OCTET_STRING || col->dwADsType == ADSTYPE_NT_SECURITY_DESCRIPTOR)
1841 ldap_value_free_len(col->hReserved);
1842 else
1843 ldap_value_freeW(col->hReserved);
1846 return S_OK;
1849 static HRESULT WINAPI search_CloseSearchHandle(IDirectorySearch *iface, ADS_SEARCH_HANDLE res)
1851 LDAP_namespace *ldap = impl_from_IDirectorySearch(iface);
1852 struct ldap_search_context *ldap_ctx = res;
1854 TRACE("%p,%p\n", iface, res);
1856 if (!res) return E_ADS_BAD_PARAMETER;
1858 if (ldap_ctx->page)
1859 ldap_search_abandon_page(ldap->ld, ldap_ctx->page);
1860 if (ldap_ctx->res)
1861 ldap_msgfree(ldap_ctx->res);
1862 if (ldap_ctx->ber)
1863 ber_free(ldap_ctx->ber, 0);
1864 free(ldap_ctx);
1866 return S_OK;
1869 static const IDirectorySearchVtbl IDirectorySearch_vtbl =
1871 search_QueryInterface,
1872 search_AddRef,
1873 search_Release,
1874 search_SetSearchPreference,
1875 search_ExecuteSearch,
1876 search_AbandonSearch,
1877 search_GetFirstRow,
1878 search_GetNextRow,
1879 search_GetPreviousRow,
1880 search_GetNextColumnName,
1881 search_GetColumn,
1882 search_FreeColumn,
1883 search_CloseSearchHandle
1886 static inline LDAP_namespace *impl_from_IDirectoryObject(IDirectoryObject *iface)
1888 return CONTAINING_RECORD(iface, LDAP_namespace, IDirectoryObject_iface);
1891 static HRESULT WINAPI dirobj_QueryInterface(IDirectoryObject *iface, REFIID riid, void **obj)
1893 LDAP_namespace *ldap = impl_from_IDirectoryObject(iface);
1895 TRACE("%p,%s,%p\n", iface, debugstr_guid(riid), obj);
1897 if (!riid || !obj) return E_INVALIDARG;
1899 if (IsEqualGUID(riid, &IID_IDirectoryObject) ||
1900 IsEqualGUID(riid, &IID_IUnknown))
1902 IDirectoryObject_AddRef(iface);
1903 *obj = iface;
1904 return S_OK;
1907 return IADs_QueryInterface(&ldap->IADs_iface, riid, obj);
1910 static ULONG WINAPI dirobj_AddRef(IDirectoryObject *iface)
1912 LDAP_namespace *ldap = impl_from_IDirectoryObject(iface);
1913 return IADs_AddRef(&ldap->IADs_iface);
1916 static ULONG WINAPI dirobj_Release(IDirectoryObject *iface)
1918 LDAP_namespace *ldap = impl_from_IDirectoryObject(iface);
1919 return IADs_Release(&ldap->IADs_iface);
1922 static HRESULT WINAPI dirobj_GetObjectInformation(IDirectoryObject *iface, PADS_OBJECT_INFO *info)
1924 FIXME("%p,%p: stub\n", iface, info);
1925 return E_NOTIMPL;
1928 static HRESULT WINAPI dirobj_GetObjectAttributes(IDirectoryObject *iface, LPWSTR *names,
1929 DWORD count, PADS_ATTR_INFO *attrs, DWORD *count_returned)
1931 FIXME("%p,%p,%lu,%p,%p: stub\n", iface, names, count, attrs, count_returned);
1932 return E_NOTIMPL;
1935 static HRESULT WINAPI dirobj_SetObjectAttributes(IDirectoryObject *iface, PADS_ATTR_INFO attrs,
1936 DWORD count, DWORD *count_set)
1938 FIXME("%p,%p,%lu,%p: stub\n", iface, attrs, count, count_set);
1939 return E_NOTIMPL;
1942 static HRESULT WINAPI dirobj_CreateDSObject(IDirectoryObject *iface, LPWSTR name,
1943 PADS_ATTR_INFO attrs, DWORD count, IDispatch **obj)
1945 FIXME("%p,%s,%p,%lu,%p: stub\n", iface, debugstr_w(name), attrs, count, obj);
1946 return E_NOTIMPL;
1949 static HRESULT WINAPI dirobj_DeleteDSObject(IDirectoryObject *iface, LPWSTR name)
1951 FIXME("%p,%s: stub\n", iface, debugstr_w(name));
1952 return E_NOTIMPL;
1955 static const IDirectoryObjectVtbl IDirectoryObject_vtbl =
1957 dirobj_QueryInterface,
1958 dirobj_AddRef,
1959 dirobj_Release,
1960 dirobj_GetObjectInformation,
1961 dirobj_GetObjectAttributes,
1962 dirobj_SetObjectAttributes,
1963 dirobj_CreateDSObject,
1964 dirobj_DeleteDSObject
1967 static HRESULT LDAPNamespace_create(REFIID riid, void **obj)
1969 LDAP_namespace *ldap;
1970 HRESULT hr;
1972 ldap = malloc(sizeof(*ldap));
1973 if (!ldap) return E_OUTOFMEMORY;
1975 ldap->IADs_iface.lpVtbl = &IADs_vtbl;
1976 ldap->IADsOpenDSObject_iface.lpVtbl = &IADsOpenDSObject_vtbl;
1977 ldap->IDirectorySearch_iface.lpVtbl = &IDirectorySearch_vtbl;
1978 ldap->IDirectoryObject_iface.lpVtbl = &IDirectoryObject_vtbl;
1979 ldap->ref = 1;
1980 ldap->ld = NULL;
1981 ldap->host = NULL;
1982 ldap->object = NULL;
1983 ldap->attrs_count = 0;
1984 ldap->attrs_count_allocated = 0;
1985 ldap->attrs = NULL;
1986 ldap->search.scope = ADS_SCOPE_SUBTREE;
1987 ldap->search.pagesize = 0;
1988 ldap->search.size_limit = 0;
1989 ldap->search.cache_results = TRUE;
1990 ldap->search.attribtypes_only = FALSE;
1991 ldap->search.tombstone = FALSE;
1992 ldap->at = NULL;
1993 ldap->at_single_count = 0;
1994 ldap->at_multiple_count = 0;
1996 hr = IADs_QueryInterface(&ldap->IADs_iface, riid, obj);
1997 IADs_Release(&ldap->IADs_iface);
1999 return hr;
2002 static const struct class_info
2004 const CLSID *clsid;
2005 HRESULT (*constructor)(REFIID, void **);
2006 } class_info[] =
2008 { &CLSID_ADSystemInfo, ADSystemInfo_create },
2009 { &CLSID_LDAP, LDAP_create },
2010 { &CLSID_LDAPNamespace, LDAPNamespace_create },
2013 typedef struct
2015 IClassFactory IClassFactory_iface;
2016 LONG ref;
2017 const struct class_info *info;
2018 } class_factory;
2020 static inline class_factory *impl_from_IClassFactory(IClassFactory *iface)
2022 return CONTAINING_RECORD(iface, class_factory, IClassFactory_iface);
2025 static HRESULT WINAPI factory_QueryInterface(IClassFactory *iface, REFIID riid, LPVOID *obj)
2027 TRACE("%p,%s,%p\n", iface, debugstr_guid(riid), obj);
2029 if (!riid || !obj) return E_INVALIDARG;
2031 if (IsEqualIID(riid, &IID_IUnknown) ||
2032 IsEqualIID(riid, &IID_IClassFactory))
2034 IClassFactory_AddRef(iface);
2035 *obj = iface;
2036 return S_OK;
2039 *obj = NULL;
2040 FIXME("interface %s is not implemented\n", debugstr_guid(riid));
2041 return E_NOINTERFACE;
2044 static ULONG WINAPI factory_AddRef(IClassFactory *iface)
2046 class_factory *factory = impl_from_IClassFactory(iface);
2047 ULONG ref = InterlockedIncrement(&factory->ref);
2049 TRACE("(%p) ref %lu\n", iface, ref);
2051 return ref;
2054 static ULONG WINAPI factory_Release(IClassFactory *iface)
2056 class_factory *factory = impl_from_IClassFactory(iface);
2057 ULONG ref = InterlockedDecrement(&factory->ref);
2059 TRACE("(%p) ref %lu\n", iface, ref);
2061 if (!ref)
2062 free(factory);
2064 return ref;
2067 static HRESULT WINAPI factory_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **obj)
2069 class_factory *factory = impl_from_IClassFactory(iface);
2071 TRACE("%p,%s,%p\n", outer, debugstr_guid(riid), obj);
2073 if (!riid || !obj) return E_INVALIDARG;
2075 *obj = NULL;
2076 if (outer) return CLASS_E_NOAGGREGATION;
2078 return factory->info->constructor(riid, obj);
2081 static HRESULT WINAPI factory_LockServer(IClassFactory *iface, BOOL lock)
2083 FIXME("%p,%d: stub\n", iface, lock);
2084 return S_OK;
2087 static const struct IClassFactoryVtbl factory_vtbl =
2089 factory_QueryInterface,
2090 factory_AddRef,
2091 factory_Release,
2092 factory_CreateInstance,
2093 factory_LockServer
2096 static HRESULT factory_constructor(const struct class_info *info, REFIID riid, void **obj)
2098 class_factory *factory;
2099 HRESULT hr;
2101 factory = malloc(sizeof(*factory));
2102 if (!factory) return E_OUTOFMEMORY;
2104 factory->IClassFactory_iface.lpVtbl = &factory_vtbl;
2105 factory->ref = 1;
2106 factory->info = info;
2108 hr = IClassFactory_QueryInterface(&factory->IClassFactory_iface, riid, obj);
2109 IClassFactory_Release(&factory->IClassFactory_iface);
2111 return hr;
2114 HRESULT WINAPI DllGetClassObject(REFCLSID clsid, REFIID iid, LPVOID *obj)
2116 int i;
2118 TRACE("%s,%s,%p\n", debugstr_guid(clsid), debugstr_guid(iid), obj);
2120 if (!clsid || !iid || !obj) return E_INVALIDARG;
2122 *obj = NULL;
2124 for (i = 0; i < ARRAY_SIZE(class_info); i++)
2126 if (IsEqualCLSID(class_info[i].clsid, clsid))
2127 return factory_constructor(&class_info[i], iid, obj);
2130 FIXME("class %s/%s is not implemented\n", debugstr_guid(clsid), debugstr_guid(iid));
2131 return CLASS_E_CLASSNOTAVAILABLE;