dmime: Remove DECLSPEC_HIDDEN usage.
[wine.git] / dlls / adsldp / adsldp.c
blobc1e3fa74c580d0846f72c826048e30868129c970
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 #define NONAMELESSUNION
26 #include "windef.h"
27 #include "winbase.h"
28 #include "initguid.h"
29 #include "objbase.h"
30 #include "rpcproxy.h"
31 #include "rpc.h"
32 #include "iads.h"
33 #include "adshlp.h"
34 #include "adserr.h"
35 #define SECURITY_WIN32
36 #include "security.h"
37 #include "dsgetdc.h"
38 #include "lmcons.h"
39 #include "lmapibuf.h"
40 #include "winldap.h"
41 #include "winber.h"
43 #include "adsldp_private.h"
45 #include "wine/debug.h"
47 WINE_DEFAULT_DEBUG_CHANNEL(adsldp);
49 #ifndef LDAP_OPT_SERVER_CONTROLS
50 #define LDAP_OPT_SERVER_CONTROLS 0x0012
51 #endif
53 DEFINE_GUID(CLSID_LDAP,0x228d9a81,0xc302,0x11cf,0x9a,0xa4,0x00,0xaa,0x00,0x4a,0x56,0x91);
54 DEFINE_GUID(CLSID_LDAPNamespace,0x228d9a82,0xc302,0x11cf,0x9a,0xa4,0x00,0xaa,0x00,0x4a,0x56,0x91);
56 static HRESULT LDAPNamespace_create(REFIID riid, void **obj);
58 typedef struct
60 IParseDisplayName IParseDisplayName_iface;
61 LONG ref;
62 } LDAP_PARSE;
64 static inline LDAP_PARSE *impl_from_IParseDisplayName(IParseDisplayName *iface)
66 return CONTAINING_RECORD(iface, LDAP_PARSE, IParseDisplayName_iface);
69 static HRESULT WINAPI ldap_QueryInterface(IParseDisplayName *iface, REFIID riid, void **obj)
71 TRACE("%p,%s,%p\n", iface, debugstr_guid(riid), obj);
73 if (!riid || !obj) return E_INVALIDARG;
75 if (IsEqualGUID(riid, &IID_IUnknown) ||
76 IsEqualGUID(riid, &IID_IParseDisplayName))
78 IParseDisplayName_AddRef(iface);
79 *obj = iface;
80 return S_OK;
83 *obj = NULL;
84 FIXME("interface %s is not implemented\n", debugstr_guid(riid));
85 return E_NOINTERFACE;
88 static ULONG WINAPI ldap_AddRef(IParseDisplayName *iface)
90 LDAP_PARSE *ldap = impl_from_IParseDisplayName(iface);
91 return InterlockedIncrement(&ldap->ref);
94 static ULONG WINAPI ldap_Release(IParseDisplayName *iface)
96 LDAP_PARSE *ldap = impl_from_IParseDisplayName(iface);
97 LONG ref = InterlockedDecrement(&ldap->ref);
99 if (!ref)
101 TRACE("destroying %p\n", iface);
102 free(ldap);
105 return ref;
108 static HRESULT WINAPI ldap_ParseDisplayName(IParseDisplayName *iface, IBindCtx *bc,
109 LPOLESTR name, ULONG *eaten, IMoniker **mk)
111 HRESULT hr;
112 IADsOpenDSObject *ads_open;
113 IDispatch *disp;
115 TRACE("%p,%p,%s,%p,%p\n", iface, bc, debugstr_w(name), eaten, mk);
117 hr = LDAPNamespace_create(&IID_IADsOpenDSObject, (void **)&ads_open);
118 if (hr != S_OK) return hr;
120 hr = IADsOpenDSObject_OpenDSObject(ads_open, name, NULL, NULL, ADS_SECURE_AUTHENTICATION, &disp);
121 if (hr != S_OK)
122 hr = IADsOpenDSObject_OpenDSObject(ads_open, name, NULL, NULL, 0, &disp);
123 if (hr == S_OK)
125 hr = CreatePointerMoniker((IUnknown *)disp, mk);
126 if (hr == S_OK)
127 *eaten = wcslen(name);
129 IDispatch_Release(disp);
132 IADsOpenDSObject_Release(ads_open);
134 return hr;
137 static const IParseDisplayNameVtbl LDAP_PARSE_vtbl =
139 ldap_QueryInterface,
140 ldap_AddRef,
141 ldap_Release,
142 ldap_ParseDisplayName
145 static HRESULT LDAP_create(REFIID riid, void **obj)
147 LDAP_PARSE *ldap;
148 HRESULT hr;
150 ldap = malloc(sizeof(*ldap));
151 if (!ldap) return E_OUTOFMEMORY;
153 ldap->IParseDisplayName_iface.lpVtbl = &LDAP_PARSE_vtbl;
154 ldap->ref = 1;
156 hr = IParseDisplayName_QueryInterface(&ldap->IParseDisplayName_iface, riid, obj);
157 IParseDisplayName_Release(&ldap->IParseDisplayName_iface);
159 return hr;
162 typedef struct
164 IADsADSystemInfo IADsADSystemInfo_iface;
165 LONG ref;
166 } AD_sysinfo;
168 static inline AD_sysinfo *impl_from_IADsADSystemInfo(IADsADSystemInfo *iface)
170 return CONTAINING_RECORD(iface, AD_sysinfo, IADsADSystemInfo_iface);
173 static HRESULT WINAPI sysinfo_QueryInterface(IADsADSystemInfo *iface, REFIID riid, void **obj)
175 TRACE("%p,%s,%p\n", iface, debugstr_guid(riid), obj);
177 if (!riid || !obj) return E_INVALIDARG;
179 if (IsEqualGUID(riid, &IID_IADsADSystemInfo) ||
180 IsEqualGUID(riid, &IID_IDispatch) ||
181 IsEqualGUID(riid, &IID_IUnknown))
183 IADsADSystemInfo_AddRef(iface);
184 *obj = iface;
185 return S_OK;
188 *obj = NULL;
189 FIXME("interface %s is not implemented\n", debugstr_guid(riid));
190 return E_NOINTERFACE;
193 static ULONG WINAPI sysinfo_AddRef(IADsADSystemInfo *iface)
195 AD_sysinfo *sysinfo = impl_from_IADsADSystemInfo(iface);
196 return InterlockedIncrement(&sysinfo->ref);
199 static ULONG WINAPI sysinfo_Release(IADsADSystemInfo *iface)
201 AD_sysinfo *sysinfo = impl_from_IADsADSystemInfo(iface);
202 LONG ref = InterlockedDecrement(&sysinfo->ref);
204 if (!ref)
206 TRACE("destroying %p\n", iface);
207 free(sysinfo);
210 return ref;
213 static HRESULT WINAPI sysinfo_GetTypeInfoCount(IADsADSystemInfo *iface, UINT *count)
215 FIXME("%p,%p: stub\n", iface, count);
216 return E_NOTIMPL;
219 static HRESULT WINAPI sysinfo_GetTypeInfo(IADsADSystemInfo *iface, UINT index, LCID lcid, ITypeInfo **info)
221 FIXME("%p,%u,%#lx,%p: stub\n", iface, index, lcid, info);
222 return E_NOTIMPL;
225 static HRESULT WINAPI sysinfo_GetIDsOfNames(IADsADSystemInfo *iface, REFIID riid, LPOLESTR *names,
226 UINT count, LCID lcid, DISPID *dispid)
228 FIXME("%p,%s,%p,%u,%lu,%p: stub\n", iface, debugstr_guid(riid), names, count, lcid, dispid);
229 return E_NOTIMPL;
232 static HRESULT WINAPI sysinfo_Invoke(IADsADSystemInfo *iface, DISPID dispid, REFIID riid, LCID lcid, WORD flags,
233 DISPPARAMS *params, VARIANT *result, EXCEPINFO *excepinfo, UINT *argerr)
235 FIXME("%p,%ld,%s,%04lx,%04x,%p,%p,%p,%p: stub\n", iface, dispid, debugstr_guid(riid), lcid, flags,
236 params, result, excepinfo, argerr);
237 return E_NOTIMPL;
240 static HRESULT WINAPI sysinfo_get_UserName(IADsADSystemInfo *iface, BSTR *retval)
242 FIXME("%p,%p: stub\n", iface, retval);
243 return E_NOTIMPL;
246 static HRESULT WINAPI sysinfo_get_ComputerName(IADsADSystemInfo *iface, BSTR *retval)
248 ULONG size;
249 WCHAR *name;
251 TRACE("%p,%p\n", iface, retval);
253 size = 0;
254 GetComputerObjectNameW(NameFullyQualifiedDN, NULL, &size);
255 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
256 return HRESULT_FROM_WIN32(GetLastError());
258 name = SysAllocStringLen(NULL, size);
259 if (!name) return E_OUTOFMEMORY;
261 if (!GetComputerObjectNameW(NameFullyQualifiedDN, name, &size))
263 SysFreeString(name);
264 return HRESULT_FROM_WIN32(GetLastError());
267 *retval = name;
268 return S_OK;
271 static HRESULT WINAPI sysinfo_get_SiteName(IADsADSystemInfo *iface, BSTR *retval)
273 FIXME("%p,%p: stub\n", iface, retval);
274 return E_NOTIMPL;
277 static HRESULT WINAPI sysinfo_get_DomainShortName(IADsADSystemInfo *iface, BSTR *retval)
279 FIXME("%p,%p: stub\n", iface, retval);
280 return E_NOTIMPL;
283 static HRESULT WINAPI sysinfo_get_DomainDNSName(IADsADSystemInfo *iface, BSTR *retval)
285 FIXME("%p,%p: stub\n", iface, retval);
286 return E_NOTIMPL;
289 static HRESULT WINAPI sysinfo_get_ForestDNSName(IADsADSystemInfo *iface, BSTR *retval)
291 FIXME("%p,%p: stub\n", iface, retval);
292 return E_NOTIMPL;
295 static HRESULT WINAPI sysinfo_get_PDCRoleOwner(IADsADSystemInfo *iface, BSTR *retval)
297 FIXME("%p,%p: stub\n", iface, retval);
298 return E_NOTIMPL;
301 static HRESULT WINAPI sysinfo_get_SchemaRoleOwner(IADsADSystemInfo *iface, BSTR *retval)
303 FIXME("%p,%p: stub\n", iface, retval);
304 return E_NOTIMPL;
307 static HRESULT WINAPI sysinfo_get_IsNativeMode(IADsADSystemInfo *iface, VARIANT_BOOL *retval)
309 FIXME("%p,%p: stub\n", iface, retval);
310 return E_NOTIMPL;
313 static HRESULT WINAPI sysinfo_GetAnyDCName(IADsADSystemInfo *iface, BSTR *retval)
315 FIXME("%p,%p: stub\n", iface, retval);
316 return E_NOTIMPL;
319 static HRESULT WINAPI sysinfo_GetDCSiteName(IADsADSystemInfo *iface, BSTR server, BSTR *retval)
321 FIXME("%p,%s,%p: stub\n", iface, debugstr_w(server), retval);
322 return E_NOTIMPL;
325 static HRESULT WINAPI sysinfo_RefreshSchemaCache(IADsADSystemInfo *iface)
327 FIXME("%p: stub\n", iface);
328 return E_NOTIMPL;
331 static HRESULT WINAPI sysinfo_GetTrees(IADsADSystemInfo *iface, VARIANT *retval)
333 FIXME("%p,%p: stub\n", iface, retval);
334 return E_NOTIMPL;
337 static const IADsADSystemInfoVtbl IADsADSystemInfo_vtbl =
339 sysinfo_QueryInterface,
340 sysinfo_AddRef,
341 sysinfo_Release,
342 sysinfo_GetTypeInfoCount,
343 sysinfo_GetTypeInfo,
344 sysinfo_GetIDsOfNames,
345 sysinfo_Invoke,
346 sysinfo_get_UserName,
347 sysinfo_get_ComputerName,
348 sysinfo_get_SiteName,
349 sysinfo_get_DomainShortName,
350 sysinfo_get_DomainDNSName,
351 sysinfo_get_ForestDNSName,
352 sysinfo_get_PDCRoleOwner,
353 sysinfo_get_SchemaRoleOwner,
354 sysinfo_get_IsNativeMode,
355 sysinfo_GetAnyDCName,
356 sysinfo_GetDCSiteName,
357 sysinfo_RefreshSchemaCache,
358 sysinfo_GetTrees
361 static HRESULT ADSystemInfo_create(REFIID riid, void **obj)
363 AD_sysinfo *sysinfo;
364 HRESULT hr;
366 sysinfo = malloc(sizeof(*sysinfo));
367 if (!sysinfo) return E_OUTOFMEMORY;
369 sysinfo->IADsADSystemInfo_iface.lpVtbl = &IADsADSystemInfo_vtbl;
370 sysinfo->ref = 1;
372 hr = IADsADSystemInfo_QueryInterface(&sysinfo->IADsADSystemInfo_iface, riid, obj);
373 IADsADSystemInfo_Release(&sysinfo->IADsADSystemInfo_iface);
375 return hr;
378 struct ldap_attribute
380 WCHAR *name;
381 WCHAR **values;
384 typedef struct
386 IADs IADs_iface;
387 IADsOpenDSObject IADsOpenDSObject_iface;
388 IDirectorySearch IDirectorySearch_iface;
389 IDirectoryObject IDirectoryObject_iface;
390 LONG ref;
391 LDAP *ld;
392 BSTR host;
393 BSTR object;
394 ULONG port;
395 ULONG attrs_count, attrs_count_allocated;
396 struct ldap_attribute *attrs;
397 struct attribute_type *at;
398 ULONG at_single_count, at_multiple_count;
399 struct
401 ADS_SCOPEENUM scope;
402 int pagesize;
403 int size_limit;
404 BOOL cache_results;
405 BOOL attribtypes_only;
406 BOOL tombstone;
407 } search;
408 } LDAP_namespace;
410 struct ldap_search_context
412 LDAPSearch *page;
413 LDAPMessage *res, *entry;
414 BerElement *ber;
415 ULONG count, pos;
416 BOOL add_ADsPath;
419 static inline LDAP_namespace *impl_from_IADs(IADs *iface)
421 return CONTAINING_RECORD(iface, LDAP_namespace, IADs_iface);
424 static HRESULT WINAPI ldapns_QueryInterface(IADs *iface, REFIID riid, void **obj)
426 LDAP_namespace *ldap = impl_from_IADs(iface);
428 TRACE("%p,%s,%p\n", iface, debugstr_guid(riid), obj);
430 if (!riid || !obj) return E_INVALIDARG;
432 if (IsEqualGUID(riid, &IID_IUnknown) ||
433 IsEqualGUID(riid, &IID_IDispatch) ||
434 IsEqualGUID(riid, &IID_IADs))
436 IADs_AddRef(iface);
437 *obj = iface;
438 return S_OK;
441 if (IsEqualGUID(riid, &IID_IADsOpenDSObject))
443 IADs_AddRef(iface);
444 *obj = &ldap->IADsOpenDSObject_iface;
445 return S_OK;
448 if (IsEqualGUID(riid, &IID_IDirectorySearch))
450 if (!ldap->ld || (ldap->object && !wcsicmp(ldap->object, L"rootDSE")))
451 return E_NOINTERFACE;
453 IADs_AddRef(iface);
454 *obj = &ldap->IDirectorySearch_iface;
455 return S_OK;
458 if (IsEqualGUID(riid, &IID_IDirectoryObject))
460 IADs_AddRef(iface);
461 *obj = &ldap->IDirectoryObject_iface;
462 return S_OK;
465 FIXME("interface %s is not implemented\n", debugstr_guid(riid));
466 return E_NOINTERFACE;
469 static ULONG WINAPI ldapns_AddRef(IADs *iface)
471 LDAP_namespace *ldap = impl_from_IADs(iface);
472 return InterlockedIncrement(&ldap->ref);
475 static void free_attributes(LDAP_namespace *ldap)
477 ULONG i;
479 if (!ldap->attrs) return;
481 for (i = 0; i < ldap->attrs_count; i++)
483 ldap_memfreeW(ldap->attrs[i].name);
484 ldap_value_freeW(ldap->attrs[i].values);
487 free(ldap->attrs);
488 ldap->attrs = NULL;
489 ldap->attrs_count = 0;
492 static ULONG WINAPI ldapns_Release(IADs *iface)
494 LDAP_namespace *ldap = impl_from_IADs(iface);
495 LONG ref = InterlockedDecrement(&ldap->ref);
497 if (!ref)
499 TRACE("destroying %p\n", iface);
500 if (ldap->ld) ldap_unbind(ldap->ld);
501 SysFreeString(ldap->host);
502 SysFreeString(ldap->object);
503 free_attributes(ldap);
504 free_attribute_types(ldap->at, ldap->at_single_count + ldap->at_multiple_count);
505 free(ldap);
508 return ref;
511 static HRESULT WINAPI ldapns_GetTypeInfoCount(IADs *iface, UINT *count)
513 FIXME("%p,%p: stub\n", iface, count);
514 return E_NOTIMPL;
517 static HRESULT WINAPI ldapns_GetTypeInfo(IADs *iface, UINT index, LCID lcid, ITypeInfo **info)
519 FIXME("%p,%u,%#lx,%p: stub\n", iface, index, lcid, info);
520 return E_NOTIMPL;
523 static HRESULT WINAPI ldapns_GetIDsOfNames(IADs *iface, REFIID riid, LPOLESTR *names,
524 UINT count, LCID lcid, DISPID *dispid)
526 FIXME("%p,%s,%p,%u,%lu,%p: stub\n", iface, debugstr_guid(riid), names, count, lcid, dispid);
527 return E_NOTIMPL;
530 static HRESULT WINAPI ldapns_Invoke(IADs *iface, DISPID dispid, REFIID riid, LCID lcid, WORD flags,
531 DISPPARAMS *params, VARIANT *result, EXCEPINFO *excepinfo, UINT *argerr)
533 FIXME("%p,%ld,%s,%04lx,%04x,%p,%p,%p,%p: stub\n", iface, dispid, debugstr_guid(riid), lcid, flags,
534 params, result, excepinfo, argerr);
535 return E_NOTIMPL;
538 static HRESULT WINAPI ldapns_get_Name(IADs *iface, BSTR *retval)
540 FIXME("%p,%p: stub\n", iface, retval);
541 return E_NOTIMPL;
544 static HRESULT WINAPI ldapns_get_Class(IADs *iface, BSTR *retval)
546 FIXME("%p,%p: stub\n", iface, retval);
547 return E_NOTIMPL;
550 static HRESULT WINAPI ldapns_get_GUID(IADs *iface, BSTR *retval)
552 FIXME("%p,%p: stub\n", iface, retval);
553 return E_NOTIMPL;
556 static HRESULT WINAPI ldapns_get_ADsPath(IADs *iface, BSTR *retval)
558 FIXME("%p,%p: stub\n", iface, retval);
559 return E_NOTIMPL;
562 static HRESULT WINAPI ldapns_get_Parent(IADs *iface, BSTR *retval)
564 FIXME("%p,%p: stub\n", iface, retval);
565 return E_NOTIMPL;
568 static HRESULT WINAPI ldapns_get_Schema(IADs *iface, BSTR *retval)
570 FIXME("%p,%p: stub\n", iface, retval);
571 return E_NOTIMPL;
574 static HRESULT WINAPI ldapns_GetInfo(IADs *iface)
576 HRESULT hr;
577 VARIANT var;
579 TRACE("%p\n", iface);
581 hr = ADsBuildVarArrayStr(NULL, 0, &var);
582 if (hr == S_OK)
584 hr = IADs_GetInfoEx(iface, var, 0);
585 VariantClear(&var);
587 return hr;
590 static HRESULT WINAPI ldapns_SetInfo(IADs *iface)
592 FIXME("%p: stub\n", iface);
593 return E_NOTIMPL;
596 static HRESULT WINAPI ldapns_Get(IADs *iface, BSTR name, VARIANT *prop)
598 LDAP_namespace *ldap = impl_from_IADs(iface);
599 HRESULT hr;
600 ULONG i;
602 TRACE("%p,%s,%p\n", iface, debugstr_w(name), prop);
604 if (!name || !prop) return E_ADS_BAD_PARAMETER;
606 if (!ldap->attrs_count)
608 hr = IADs_GetInfo(iface);
609 if (hr != S_OK) return hr;
612 for (i = 0; i < ldap->attrs_count; i++)
614 if (!wcsicmp(name, ldap->attrs[i].name))
616 LONG count = ldap_count_valuesW(ldap->attrs[i].values);
617 if (!count)
619 V_BSTR(prop) = NULL;
620 V_VT(prop) = VT_BSTR;
621 return S_OK;
624 if (count > 1)
626 SAFEARRAY *sa;
627 VARIANT item;
628 LONG idx;
630 TRACE("attr %s has %lu values\n", debugstr_w(ldap->attrs[i].name), count);
632 sa = SafeArrayCreateVector(VT_VARIANT, 0, count);
633 if (!sa) return E_OUTOFMEMORY;
635 for (idx = 0; idx < count; idx++)
637 TRACE("=> %s\n", debugstr_w(ldap->attrs[i].values[idx]));
638 V_VT(&item) = VT_BSTR;
639 V_BSTR(&item) = SysAllocString(ldap->attrs[i].values[idx]);
640 if (!V_BSTR(&item))
642 hr = E_OUTOFMEMORY;
643 goto fail;
646 hr = SafeArrayPutElement(sa, &idx, &item);
647 SysFreeString(V_BSTR(&item));
648 if (hr != S_OK) goto fail;
651 V_VT(prop) = VT_ARRAY | VT_VARIANT;
652 V_ARRAY(prop) = sa;
653 return S_OK;
654 fail:
655 SafeArrayDestroy(sa);
656 return hr;
658 else
660 TRACE("=> %s\n", debugstr_w(ldap->attrs[i].values[0]));
661 V_BSTR(prop) = SysAllocString(ldap->attrs[i].values[0]);
662 if (!V_BSTR(prop)) return E_OUTOFMEMORY;
663 V_VT(prop) = VT_BSTR;
664 return S_OK;
669 return E_ADS_PROPERTY_NOT_FOUND;
672 static HRESULT WINAPI ldapns_Put(IADs *iface, BSTR name, VARIANT prop)
674 FIXME("%p,%s,%s: stub\n", iface, debugstr_w(name), wine_dbgstr_variant(&prop));
675 return E_NOTIMPL;
678 static HRESULT WINAPI ldapns_GetEx(IADs *iface, BSTR name, VARIANT *prop)
680 FIXME("%p,%s,%p: stub\n", iface, debugstr_w(name), prop);
681 return E_NOTIMPL;
684 static HRESULT WINAPI ldapns_PutEx(IADs *iface, LONG code, BSTR name, VARIANT prop)
686 FIXME("%p,%ld,%s,%s: stub\n", iface, code, debugstr_w(name), wine_dbgstr_variant(&prop));
687 return E_NOTIMPL;
690 static HRESULT add_attribute(LDAP_namespace *ldap, WCHAR *name, WCHAR **values)
692 struct ldap_attribute *new_attrs;
694 if (!ldap->attrs)
696 ldap->attrs = malloc(256 * sizeof(ldap->attrs[0]));
697 if (!ldap->attrs) return E_OUTOFMEMORY;
698 ldap->attrs_count_allocated = 256;
700 else if (ldap->attrs_count_allocated < ldap->attrs_count + 1)
702 new_attrs = realloc(ldap->attrs, (ldap->attrs_count_allocated * 2) * sizeof(*new_attrs));
703 if (!new_attrs) return E_OUTOFMEMORY;
705 ldap->attrs_count_allocated *= 2;
706 ldap->attrs = new_attrs;
709 ldap->attrs[ldap->attrs_count].name = name;
710 ldap->attrs[ldap->attrs_count].values = values;
711 ldap->attrs_count++;
713 return S_OK;
716 static HRESULT WINAPI ldapns_GetInfoEx(IADs *iface, VARIANT prop, LONG reserved)
718 LDAP_namespace *ldap = impl_from_IADs(iface);
719 HRESULT hr;
720 SAFEARRAY *sa;
721 VARIANT *item;
722 WCHAR **props = NULL, *attr, **values;
723 DWORD i, count, err;
724 LDAPMessage *res = NULL, *entry;
725 BerElement *ber;
727 TRACE("%p,%s,%ld\n", iface, wine_dbgstr_variant(&prop), reserved);
729 free_attributes(ldap);
731 if (!ldap->ld) return E_NOTIMPL;
733 if (V_VT(&prop) != (VT_ARRAY | VT_VARIANT))
734 return E_ADS_BAD_PARAMETER;
736 sa = V_ARRAY(&prop);
737 if (sa->cDims != 1)
738 return E_ADS_BAD_PARAMETER;
740 hr = SafeArrayAccessData(sa, (void *)&item);
741 if (hr != S_OK) return hr;
743 count = sa->rgsabound[0].cElements;
744 if (count)
746 props = malloc((count + 1) * sizeof(props[0]));
747 if (!props)
749 hr = E_OUTOFMEMORY;
750 goto exit;
753 for (i = 0; i < count; i++)
755 if (V_VT(&item[i]) != VT_BSTR)
757 hr = E_ADS_BAD_PARAMETER;
758 goto exit;
760 props[i] = V_BSTR(&item[i]);
762 props[sa->rgsabound[0].cElements] = NULL;
765 err = ldap_search_sW(ldap->ld, NULL, LDAP_SCOPE_BASE, (WCHAR *)L"(objectClass=*)", props, FALSE, &res);
766 if (err != LDAP_SUCCESS)
768 TRACE("ldap_search_sW error %#lx\n", err);
769 hr = HRESULT_FROM_WIN32(map_ldap_error(err));
770 goto exit;
773 entry = ldap_first_entry(ldap->ld, res);
774 while (entry)
776 attr = ldap_first_attributeW(ldap->ld, entry, &ber);
777 while (attr)
779 TRACE("attr: %s\n", debugstr_w(attr));
781 values = ldap_get_valuesW(ldap->ld, entry, attr);
783 hr = add_attribute(ldap, attr, values);
784 if (hr != S_OK)
786 ldap_value_freeW(values);
787 ldap_memfreeW(attr);
788 ber_free(ber, 0);
789 goto exit;
792 attr = ldap_next_attributeW(ldap->ld, entry, ber);
795 ber_free(ber, 0);
796 entry = ldap_next_entry(ldap->ld, res);
799 exit:
800 if (res) ldap_msgfree(res);
801 free(props);
802 SafeArrayUnaccessData(sa);
803 return hr;
806 static const IADsVtbl IADs_vtbl =
808 ldapns_QueryInterface,
809 ldapns_AddRef,
810 ldapns_Release,
811 ldapns_GetTypeInfoCount,
812 ldapns_GetTypeInfo,
813 ldapns_GetIDsOfNames,
814 ldapns_Invoke,
815 ldapns_get_Name,
816 ldapns_get_Class,
817 ldapns_get_GUID,
818 ldapns_get_ADsPath,
819 ldapns_get_Parent,
820 ldapns_get_Schema,
821 ldapns_GetInfo,
822 ldapns_SetInfo,
823 ldapns_Get,
824 ldapns_Put,
825 ldapns_GetEx,
826 ldapns_PutEx,
827 ldapns_GetInfoEx
830 static inline LDAP_namespace *impl_from_IADsOpenDSObject(IADsOpenDSObject *iface)
832 return CONTAINING_RECORD(iface, LDAP_namespace, IADsOpenDSObject_iface);
835 static HRESULT WINAPI openobj_QueryInterface(IADsOpenDSObject *iface, REFIID riid, void **obj)
837 TRACE("%p,%s,%p\n", iface, debugstr_guid(riid), obj);
839 if (!riid || !obj) return E_INVALIDARG;
841 if (IsEqualGUID(riid, &IID_IADsOpenDSObject) ||
842 IsEqualGUID(riid, &IID_IDispatch) ||
843 IsEqualGUID(riid, &IID_IUnknown))
845 IADsOpenDSObject_AddRef(iface);
846 *obj = iface;
847 return S_OK;
850 FIXME("interface %s is not implemented\n", debugstr_guid(riid));
851 return E_NOINTERFACE;
854 static ULONG WINAPI openobj_AddRef(IADsOpenDSObject *iface)
856 LDAP_namespace *ldap = impl_from_IADsOpenDSObject(iface);
857 return IADs_AddRef(&ldap->IADs_iface);
860 static ULONG WINAPI openobj_Release(IADsOpenDSObject *iface)
862 LDAP_namespace *ldap = impl_from_IADsOpenDSObject(iface);
863 return IADs_Release(&ldap->IADs_iface);
866 static HRESULT WINAPI openobj_GetTypeInfoCount(IADsOpenDSObject *iface, UINT *count)
868 FIXME("%p,%p: stub\n", iface, count);
869 return E_NOTIMPL;
872 static HRESULT WINAPI openobj_GetTypeInfo(IADsOpenDSObject *iface, UINT index, LCID lcid, ITypeInfo **info)
874 FIXME("%p,%u,%#lx,%p: stub\n", iface, index, lcid, info);
875 return E_NOTIMPL;
878 static HRESULT WINAPI openobj_GetIDsOfNames(IADsOpenDSObject *iface, REFIID riid, LPOLESTR *names,
879 UINT count, LCID lcid, DISPID *dispid)
881 FIXME("%p,%s,%p,%u,%lu,%p: stub\n", iface, debugstr_guid(riid), names, count, lcid, dispid);
882 return E_NOTIMPL;
885 static HRESULT WINAPI openobj_Invoke(IADsOpenDSObject *iface, DISPID dispid, REFIID riid, LCID lcid, WORD flags,
886 DISPPARAMS *params, VARIANT *result, EXCEPINFO *excepinfo, UINT *argerr)
888 FIXME("%p,%ld,%s,%04lx,%04x,%p,%p,%p,%p: stub\n", iface, dispid, debugstr_guid(riid), lcid, flags,
889 params, result, excepinfo, argerr);
890 return E_NOTIMPL;
893 static HRESULT parse_path(WCHAR *path, BSTR *host, ULONG *port, BSTR *object)
895 WCHAR *p, *p_host;
896 int host_len;
898 if (host) *host = NULL;
899 if (port) *port = 0;
900 if (object) *object = NULL;
902 if (wcsnicmp(path, L"LDAP:", 5) != 0)
903 return E_ADS_BAD_PATHNAME;
905 p = path + 5;
906 if (!*p) return S_OK;
908 if (*p++ != '/' || *p++ != '/' || !*p)
909 return E_ADS_BAD_PATHNAME;
911 p_host = p;
912 host_len = 0;
913 while (*p && *p != '/')
915 if (*p == ':')
917 ULONG dummy;
918 if (!port) port = &dummy;
919 *port = wcstol(p + 1, &p, 10);
920 if (*p && *p != '/') return E_ADS_BAD_PATHNAME;
922 else
924 p++;
925 host_len++;
928 if (host_len == 0) return E_ADS_BAD_PATHNAME;
930 if (host)
932 *host = SysAllocStringLen(p_host, host_len);
933 if (!*host) return E_OUTOFMEMORY;
936 if (!*p) return S_OK;
938 if (*p++ != '/' || !*p)
940 SysFreeString(*host);
941 return E_ADS_BAD_PATHNAME;
944 if (object)
946 *object = SysAllocString(p);
947 if (!*object)
949 SysFreeString(*host);
950 return E_OUTOFMEMORY;
954 return S_OK;
957 static HRESULT WINAPI openobj_OpenDSObject(IADsOpenDSObject *iface, BSTR path, BSTR user, BSTR password,
958 LONG flags, IDispatch **obj)
960 BSTR host, object;
961 ULONG port;
962 IADs *ads;
963 LDAP *ld = NULL;
964 HRESULT hr;
965 ULONG err, at_single_count = 0, at_multiple_count = 0;
966 struct attribute_type *at = NULL;
968 TRACE("%p,%s,%s,%p,%08lx,%p\n", iface, debugstr_w(path), debugstr_w(user), password, flags, obj);
970 hr = parse_path(path, &host, &port, &object);
971 if (hr != S_OK) return hr;
973 TRACE("host %s, port %lu, object %s\n", debugstr_w(host), port, debugstr_w(object));
975 if (host)
977 int version;
979 if (!wcsicmp(host, L"rootDSE"))
981 DOMAIN_CONTROLLER_INFOW *dcinfo;
983 if (object)
985 hr = E_ADS_BAD_PATHNAME;
986 goto fail;
989 object = host;
991 err = DsGetDcNameW(NULL, NULL, NULL, NULL, DS_RETURN_DNS_NAME, &dcinfo);
992 if (err != ERROR_SUCCESS)
994 hr = HRESULT_FROM_WIN32(err);
995 goto fail;
998 host = SysAllocString(dcinfo->DomainName);
999 NetApiBufferFree(dcinfo);
1001 if (!host)
1003 hr = E_OUTOFMEMORY;
1004 goto fail;
1008 ld = ldap_initW(host, port);
1009 if (!ld)
1011 hr = HRESULT_FROM_WIN32(LdapGetLastError());
1012 goto fail;
1015 version = LDAP_VERSION3;
1016 err = ldap_set_optionW(ld, LDAP_OPT_PROTOCOL_VERSION, &version);
1017 if (err != LDAP_SUCCESS)
1019 hr = HRESULT_FROM_WIN32(map_ldap_error(err));
1020 ldap_unbind(ld);
1021 goto fail;
1024 err = ldap_connect(ld, NULL);
1025 if (err != LDAP_SUCCESS)
1027 hr = HRESULT_FROM_WIN32(map_ldap_error(err));
1028 ldap_unbind(ld);
1029 goto fail;
1032 if (flags & ADS_SECURE_AUTHENTICATION)
1034 SEC_WINNT_AUTH_IDENTITY_W id;
1036 id.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
1037 id.Domain = (unsigned short *)host;
1038 id.DomainLength = wcslen(host);
1039 id.User = (unsigned short *)user;
1040 id.UserLength = user ? wcslen(user) : 0;
1041 id.Password = (unsigned short *)password;
1042 id.PasswordLength = password ? wcslen(password) : 0;
1044 err = ldap_bind_sW(ld, NULL, (WCHAR *)&id, LDAP_AUTH_NEGOTIATE);
1045 if (err != LDAP_SUCCESS)
1047 TRACE("ldap_bind_sW error %#lx\n", err);
1048 hr = HRESULT_FROM_WIN32(map_ldap_error(err));
1049 ldap_unbind(ld);
1050 goto fail;
1053 else
1055 err = ldap_simple_bind_sW(ld, user, password);
1056 if (err != LDAP_SUCCESS)
1058 TRACE("ldap_simple_bind_sW error %#lx\n", err);
1059 hr = HRESULT_FROM_WIN32(map_ldap_error(err));
1060 ldap_unbind(ld);
1061 goto fail;
1065 at = load_schema(ld, &at_single_count, &at_multiple_count);
1068 hr = LDAPNamespace_create(&IID_IADs, (void **)&ads);
1069 if (hr == S_OK)
1071 LDAP_namespace *ldap = impl_from_IADs(ads);
1072 ldap->ld = ld;
1073 ldap->host = host;
1074 ldap->port = port;
1075 ldap->object = object;
1076 ldap->at = at;
1077 ldap->at_single_count = at_single_count;
1078 ldap->at_multiple_count = at_multiple_count;
1079 hr = IADs_QueryInterface(ads, &IID_IDispatch, (void **)obj);
1080 IADs_Release(ads);
1081 return hr;
1084 fail:
1085 SysFreeString(host);
1086 SysFreeString(object);
1088 return hr;
1091 static const IADsOpenDSObjectVtbl IADsOpenDSObject_vtbl =
1093 openobj_QueryInterface,
1094 openobj_AddRef,
1095 openobj_Release,
1096 openobj_GetTypeInfoCount,
1097 openobj_GetTypeInfo,
1098 openobj_GetIDsOfNames,
1099 openobj_Invoke,
1100 openobj_OpenDSObject
1103 static inline LDAP_namespace *impl_from_IDirectorySearch(IDirectorySearch *iface)
1105 return CONTAINING_RECORD(iface, LDAP_namespace, IDirectorySearch_iface);
1108 static HRESULT WINAPI search_QueryInterface(IDirectorySearch *iface, REFIID riid, void **obj)
1110 TRACE("%p,%s,%p\n", iface, debugstr_guid(riid), obj);
1112 if (!riid || !obj) return E_INVALIDARG;
1114 if (IsEqualGUID(riid, &IID_IDirectorySearch) ||
1115 IsEqualGUID(riid, &IID_IUnknown))
1117 IDirectorySearch_AddRef(iface);
1118 *obj = iface;
1119 return S_OK;
1122 FIXME("interface %s is not implemented\n", debugstr_guid(riid));
1123 return E_NOINTERFACE;
1126 static ULONG WINAPI search_AddRef(IDirectorySearch *iface)
1128 LDAP_namespace *ldap = impl_from_IDirectorySearch(iface);
1129 return IADs_AddRef(&ldap->IADs_iface);
1132 static ULONG WINAPI search_Release(IDirectorySearch *iface)
1134 LDAP_namespace *ldap = impl_from_IDirectorySearch(iface);
1135 return IADs_Release(&ldap->IADs_iface);
1138 static HRESULT WINAPI search_SetSearchPreference(IDirectorySearch *iface, PADS_SEARCHPREF_INFO prefs, DWORD count)
1140 LDAP_namespace *ldap = impl_from_IDirectorySearch(iface);
1141 HRESULT hr = S_OK;
1142 DWORD i;
1144 TRACE("%p,%p,%lu\n", iface, prefs, count);
1146 for (i = 0; i < count; i++)
1148 switch (prefs[i].dwSearchPref)
1150 case ADS_SEARCHPREF_SEARCH_SCOPE:
1151 if (prefs[i].vValue.dwType != ADSTYPE_INTEGER)
1153 FIXME("ADS_SEARCHPREF_SEARCH_SCOPE: unsupported dwType %d\n", prefs[i].vValue.dwType);
1154 prefs[i].dwStatus = ADS_STATUS_INVALID_SEARCHPREFVALUE;
1155 break;
1158 switch (prefs[i].vValue.u.Integer)
1160 case ADS_SCOPE_BASE:
1161 case ADS_SCOPE_ONELEVEL:
1162 case ADS_SCOPE_SUBTREE:
1163 TRACE("SEARCH_SCOPE: %ld\n", prefs[i].vValue.u.Integer);
1164 ldap->search.scope = prefs[i].vValue.u.Integer;
1165 prefs[i].dwStatus = ADS_STATUS_S_OK;
1166 break;
1168 default:
1169 prefs[i].dwStatus = ADS_STATUS_INVALID_SEARCHPREFVALUE;
1170 break;
1172 break;
1174 case ADS_SEARCHPREF_SECURITY_MASK:
1176 int security_mask;
1177 ULONG err;
1178 BerElement *ber;
1179 struct berval *berval;
1180 LDAPControlW *ctrls[2], mask;
1182 if (prefs[i].vValue.dwType != ADSTYPE_INTEGER)
1184 FIXME("ADS_SEARCHPREF_SECURITY_MASK: not supported dwType %d\n", prefs[i].vValue.dwType);
1185 prefs[i].dwStatus = ADS_STATUS_INVALID_SEARCHPREFVALUE;
1186 break;
1189 TRACE("SECURITY_MASK: %08lx\n", prefs[i].vValue.u.Integer);
1190 security_mask = prefs[i].vValue.u.Integer;
1191 if (!security_mask)
1192 security_mask = ADS_SECURITY_INFO_OWNER;
1194 ber = ber_alloc_t(LBER_USE_DER);
1195 if (!ber || ber_printf(ber, (char *)"{i}", security_mask) == -1 || ber_flatten(ber, &berval) == -1)
1197 ber_free(ber, 1);
1198 prefs[i].dwStatus = ADS_STATUS_INVALID_SEARCHPREF;
1199 break;
1201 TRACE("ber: %s\n", debugstr_an(berval->bv_val, berval->bv_len));
1203 mask.ldctl_oid = (WCHAR *)L"1.2.840.113556.1.4.801";
1204 mask.ldctl_iscritical = TRUE;
1205 mask.ldctl_value.bv_val = berval->bv_val;
1206 mask.ldctl_value.bv_len = berval->bv_len;
1207 ctrls[0] = &mask;
1208 ctrls[1] = NULL;
1209 err = ldap_set_optionW(ldap->ld, LDAP_OPT_SERVER_CONTROLS, ctrls);
1210 if (err != LDAP_SUCCESS)
1212 TRACE("ldap_set_option error %#lx\n", err);
1213 prefs[i].dwStatus = ADS_STATUS_INVALID_SEARCHPREF;
1214 hr = S_ADS_ERRORSOCCURRED;
1216 else
1217 prefs[i].dwStatus = ADS_STATUS_S_OK;
1219 ber_bvfree(berval);
1220 ber_free(ber, 1);
1221 break;
1224 case ADS_SEARCHPREF_PAGESIZE:
1225 if (prefs[i].vValue.dwType != ADSTYPE_INTEGER)
1227 FIXME("ADS_SEARCHPREF_PAGESIZE: unsupported dwType %d\n", prefs[i].vValue.dwType);
1228 prefs[i].dwStatus = ADS_STATUS_INVALID_SEARCHPREFVALUE;
1229 break;
1232 TRACE("PAGESIZE: %ld\n", prefs[i].vValue.u.Integer);
1233 ldap->search.pagesize = prefs[i].vValue.u.Integer;
1234 prefs[i].dwStatus = ADS_STATUS_S_OK;
1235 break;
1237 case ADS_SEARCHPREF_CACHE_RESULTS:
1238 if (prefs[i].vValue.dwType != ADSTYPE_BOOLEAN)
1240 FIXME("ADS_SEARCHPREF_CACHE_RESULTS: unsupported dwType %d\n", prefs[i].vValue.dwType);
1241 prefs[i].dwStatus = ADS_STATUS_INVALID_SEARCHPREFVALUE;
1242 break;
1245 TRACE("CACHE_RESULTS: %ld\n", prefs[i].vValue.u.Boolean);
1246 ldap->search.cache_results = prefs[i].vValue.u.Boolean;
1247 prefs[i].dwStatus = ADS_STATUS_S_OK;
1248 break;
1250 case ADS_SEARCHPREF_ATTRIBTYPES_ONLY:
1251 if (prefs[i].vValue.dwType != ADSTYPE_BOOLEAN)
1253 FIXME("ADS_SEARCHPREF_ATTRIBTYPES_ONLY: unsupported dwType %d\n", prefs[i].vValue.dwType);
1254 prefs[i].dwStatus = ADS_STATUS_INVALID_SEARCHPREFVALUE;
1255 break;
1258 TRACE("ATTRIBTYPES_ONLY: %ld\n", prefs[i].vValue.u.Boolean);
1259 ldap->search.attribtypes_only = prefs[i].vValue.u.Boolean;
1260 prefs[i].dwStatus = ADS_STATUS_S_OK;
1261 break;
1263 case ADS_SEARCHPREF_TOMBSTONE:
1264 if (prefs[i].vValue.dwType != ADSTYPE_BOOLEAN)
1266 FIXME("ADS_SEARCHPREF_TOMBSTONE: unsupported dwType %d\n", prefs[i].vValue.dwType);
1267 prefs[i].dwStatus = ADS_STATUS_INVALID_SEARCHPREFVALUE;
1268 break;
1271 TRACE("TOMBSTONE: %ld\n", prefs[i].vValue.u.Boolean);
1272 ldap->search.tombstone = prefs[i].vValue.u.Boolean;
1273 prefs[i].dwStatus = ADS_STATUS_S_OK;
1274 break;
1276 case ADS_SEARCHPREF_SIZE_LIMIT:
1277 if (prefs[i].vValue.dwType != ADSTYPE_INTEGER)
1279 FIXME("ADS_SEARCHPREF_SIZE_LIMIT: unsupported dwType %d\n", prefs[i].vValue.dwType);
1280 prefs[i].dwStatus = ADS_STATUS_INVALID_SEARCHPREFVALUE;
1281 break;
1284 TRACE("SIZE_LIMIT: %ld\n", prefs[i].vValue.u.Integer);
1285 ldap->search.size_limit = prefs[i].vValue.u.Integer;
1286 prefs[i].dwStatus = ADS_STATUS_S_OK;
1287 break;
1289 default:
1290 FIXME("pref %d, type %u: stub\n", prefs[i].dwSearchPref, prefs[i].vValue.dwType);
1291 prefs[i].dwStatus = ADS_STATUS_INVALID_SEARCHPREF;
1292 break;
1296 return hr;
1299 static HRESULT WINAPI search_ExecuteSearch(IDirectorySearch *iface, LPWSTR filter, LPWSTR *names,
1300 DWORD count, PADS_SEARCH_HANDLE res)
1302 LDAP_namespace *ldap = impl_from_IDirectorySearch(iface);
1303 ULONG err, i;
1304 WCHAR **props;
1305 LDAPControlW **ctrls = NULL, *ctrls_a[2], tombstone;
1306 struct ldap_search_context *ldap_ctx;
1308 TRACE("%p,%s,%p,%lu,%p\n", iface, debugstr_w(filter), names, count, res);
1310 if (!res) return E_ADS_BAD_PARAMETER;
1312 ldap_ctx = calloc(1, sizeof(*ldap_ctx));
1313 if (!ldap_ctx) return E_OUTOFMEMORY;
1315 if (count == 0xffffffff)
1316 props = NULL;
1317 else
1319 if (count && !names)
1321 free(ldap_ctx);
1322 return E_ADS_BAD_PARAMETER;
1325 props = malloc((count + 1) * sizeof(props[0]));
1326 if (!props)
1328 free(ldap_ctx);
1329 return E_OUTOFMEMORY;
1332 for (i = 0; i < count; i++)
1334 TRACE("=> %s\n", debugstr_w(names[i]));
1335 props[i] = names[i];
1338 props[count] = NULL;
1341 if (ldap->search.tombstone)
1343 tombstone.ldctl_oid = (WCHAR *)L"1.2.840.113556.1.4.417";
1344 tombstone.ldctl_iscritical = TRUE;
1345 tombstone.ldctl_value.bv_val = NULL;
1346 tombstone.ldctl_value.bv_len = 0;
1347 ctrls_a[0] = &tombstone;
1348 ctrls_a[1] = NULL;
1349 ctrls = ctrls_a;
1352 if (ldap->search.pagesize)
1354 ldap_ctx->page = ldap_search_init_pageW(ldap->ld, ldap->object, ldap->search.scope,
1355 filter, props, ldap->search.attribtypes_only,
1356 ctrls, NULL, 0, ldap->search.size_limit, NULL);
1357 if (ldap_ctx->page)
1358 err = ldap_get_next_page_s(ldap->ld, ldap_ctx->page, NULL,
1359 ldap->search.pagesize, &count, &ldap_ctx->res);
1360 else
1361 err = LDAP_NO_MEMORY;
1363 else
1364 err = ldap_search_ext_sW(ldap->ld, ldap->object, ldap->search.scope, filter, props,
1365 ldap->search.attribtypes_only, ctrls, NULL, NULL, ldap->search.size_limit,
1366 &ldap_ctx->res);
1367 free(props);
1368 if (err != LDAP_SUCCESS)
1370 TRACE("ldap_search_sW error %#lx\n", err);
1371 if (ldap_ctx->page)
1372 ldap_search_abandon_page(ldap->ld, ldap_ctx->page);
1373 free(ldap_ctx);
1374 return HRESULT_FROM_WIN32(map_ldap_error(err));
1377 *res = ldap_ctx;
1378 return S_OK;
1381 static HRESULT WINAPI search_AbandonSearch(IDirectorySearch *iface, ADS_SEARCH_HANDLE res)
1383 FIXME("%p,%p: stub\n", iface, res);
1384 return E_NOTIMPL;
1387 static HRESULT WINAPI search_GetFirstRow(IDirectorySearch *iface, ADS_SEARCH_HANDLE res)
1389 struct ldap_search_context *ldap_ctx = res;
1391 TRACE("%p,%p\n", iface, res);
1393 if (!res) return E_ADS_BAD_PARAMETER;
1395 ldap_ctx->entry = NULL;
1397 return IDirectorySearch_GetNextRow(iface, res);
1400 static HRESULT WINAPI search_GetNextRow(IDirectorySearch *iface, ADS_SEARCH_HANDLE res)
1402 LDAP_namespace *ldap = impl_from_IDirectorySearch(iface);
1403 struct ldap_search_context *ldap_ctx = res;
1405 TRACE("%p,%p\n", iface, res);
1407 if (!res) return E_ADS_BAD_PARAMETER;
1409 if (!ldap_ctx->entry)
1411 ldap_ctx->count = ldap_count_entries(ldap->ld, ldap_ctx->res);
1412 ldap_ctx->pos = 0;
1414 if (ldap_ctx->pos >= ldap_ctx->count)
1415 return S_ADS_NOMORE_ROWS;
1417 ldap_ctx->entry = ldap_first_entry(ldap->ld, ldap_ctx->res);
1419 else
1421 if (ldap_ctx->pos >= ldap_ctx->count)
1423 if (ldap_ctx->page)
1425 ULONG err, count;
1427 ldap_msgfree(ldap_ctx->res);
1428 ldap_ctx->res = NULL;
1430 err = ldap_get_next_page_s(ldap->ld, ldap_ctx->page, NULL, ldap->search.pagesize, &count, &ldap_ctx->res);
1431 if (err == LDAP_SUCCESS)
1433 ldap_ctx->count = ldap_count_entries(ldap->ld, ldap_ctx->res);
1434 ldap_ctx->pos = 0;
1436 if (ldap_ctx->pos >= ldap_ctx->count)
1437 return S_ADS_NOMORE_ROWS;
1439 ldap_ctx->entry = ldap_first_entry(ldap->ld, ldap_ctx->res);
1440 goto exit;
1443 if (err != LDAP_NO_RESULTS_RETURNED)
1445 TRACE("ldap_get_next_page_s error %#lx\n", err);
1446 return HRESULT_FROM_WIN32(map_ldap_error(err));
1448 /* fall through */
1451 return S_ADS_NOMORE_ROWS;
1454 ldap_ctx->entry = ldap_next_entry(ldap->ld, ldap_ctx->entry);
1457 exit:
1458 if (!ldap_ctx->entry)
1459 return S_ADS_NOMORE_ROWS;
1461 ldap_ctx->pos++;
1462 ldap_ctx->ber = NULL;
1464 return S_OK;
1467 static HRESULT WINAPI search_GetPreviousRow(IDirectorySearch *iface, ADS_SEARCH_HANDLE res)
1469 FIXME("%p,%p: stub\n", iface, res);
1470 return E_NOTIMPL;
1473 static HRESULT WINAPI search_GetNextColumnName(IDirectorySearch *iface, ADS_SEARCH_HANDLE res, LPWSTR *name)
1475 LDAP_namespace *ldap = impl_from_IDirectorySearch(iface);
1476 struct ldap_search_context *ldap_ctx = res;
1477 WCHAR *attr;
1479 TRACE("%p,%p,%p\n", iface, res, name);
1481 if (!name || !ldap_ctx || !ldap_ctx->entry) return E_ADS_BAD_PARAMETER;
1483 if (!ldap_ctx->ber)
1485 attr = ldap_first_attributeW(ldap->ld, ldap_ctx->entry, &ldap_ctx->ber);
1486 ldap_ctx->add_ADsPath = TRUE;
1488 else
1489 attr = ldap_next_attributeW(ldap->ld, ldap_ctx->entry, ldap_ctx->ber);
1491 if (attr)
1493 TRACE("=> %s\n", debugstr_w(attr));
1494 *name = AllocADsStr(attr);
1495 ldap_memfreeW(attr);
1496 return *name ? S_OK : E_OUTOFMEMORY;
1498 else if (ldap_ctx->add_ADsPath)
1500 ldap_ctx->add_ADsPath = FALSE;
1501 *name = AllocADsStr((WCHAR *)L"ADsPath");
1502 TRACE("=> %s\n", debugstr_w(*name));
1503 return *name ? S_OK : E_OUTOFMEMORY;
1506 *name = NULL;
1507 return S_ADS_NOMORE_COLUMNS;
1510 static HRESULT add_column_values(LDAP_namespace *ldap, struct ldap_search_context *ldap_ctx,
1511 LPWSTR name, ADS_SEARCH_COLUMN *col)
1513 ADSTYPEENUM type;
1514 DWORD i, count;
1516 type = get_schema_type(name, ldap->at, ldap->at_single_count, ldap->at_multiple_count);
1517 TRACE("%s => type %d\n", debugstr_w(name), type);
1519 switch (type)
1521 default:
1522 FIXME("no special handling for type %d\n", type);
1523 /* fall through */
1524 case ADSTYPE_DN_STRING:
1525 case ADSTYPE_CASE_EXACT_STRING:
1526 case ADSTYPE_CASE_IGNORE_STRING:
1527 case ADSTYPE_PRINTABLE_STRING:
1529 WCHAR **values = ldap_get_valuesW(ldap->ld, ldap_ctx->entry, name);
1530 if (!values)
1531 return E_ADS_COLUMN_NOT_SET;
1532 count = ldap_count_valuesW(values);
1534 col->pADsValues = calloc(count, sizeof(col->pADsValues[0]));
1535 if (!col->pADsValues)
1537 ldap_value_freeW(values);
1538 return E_OUTOFMEMORY;
1541 for (i = 0; i < count; i++)
1543 TRACE("=> %s\n", debugstr_w(values[i]));
1544 col->pADsValues[i].dwType = type;
1545 col->pADsValues[i].u.CaseIgnoreString = values[i];
1548 col->hReserved = values;
1549 break;
1552 case ADSTYPE_BOOLEAN:
1554 WCHAR **values = ldap_get_valuesW(ldap->ld, ldap_ctx->entry, name);
1555 if (!values)
1556 return E_ADS_COLUMN_NOT_SET;
1557 count = ldap_count_valuesW(values);
1559 col->pADsValues = calloc(count, sizeof(col->pADsValues[0]));
1560 if (!col->pADsValues)
1562 ldap_value_freeW(values);
1563 return E_OUTOFMEMORY;
1566 for (i = 0; i < count; i++)
1568 col->pADsValues[i].dwType = type;
1570 if (!wcsicmp(values[i], L"TRUE"))
1571 col->pADsValues[i].u.Boolean = 1;
1572 else if (!wcsicmp(values[i], L"FALSE"))
1573 col->pADsValues[i].u.Boolean = 0;
1574 else
1576 FIXME("not recognized boolean value %s\n", debugstr_w(values[i]));
1577 col->pADsValues[i].u.Boolean = 0;
1579 TRACE("%s => %ld\n", debugstr_w(values[i]), col->pADsValues[i].u.Boolean);
1582 ldap_value_freeW(values);
1583 col->hReserved = NULL;
1584 break;
1587 case ADSTYPE_INTEGER:
1588 case ADSTYPE_LARGE_INTEGER:
1590 struct berval **values = ldap_get_values_lenW(ldap->ld, ldap_ctx->entry, name);
1591 if (!values)
1592 return E_ADS_COLUMN_NOT_SET;
1593 count = ldap_count_values_len(values);
1595 col->pADsValues = calloc(count, sizeof(col->pADsValues[0]));
1596 if (!col->pADsValues)
1598 ldap_value_free_len(values);
1599 return E_OUTOFMEMORY;
1602 for (i = 0; i < count; i++)
1604 col->pADsValues[i].dwType = type;
1606 if (type == ADSTYPE_LARGE_INTEGER)
1608 col->pADsValues[i].u.LargeInteger.QuadPart = _atoi64(values[i]->bv_val);
1609 TRACE("%s => %s\n", debugstr_an(values[i]->bv_val, values[i]->bv_len), wine_dbgstr_longlong(col->pADsValues[i].u.LargeInteger.QuadPart));
1611 else
1613 col->pADsValues[i].u.Integer = atol(values[i]->bv_val);
1614 TRACE("%s => %ld\n", debugstr_an(values[i]->bv_val, values[i]->bv_len), col->pADsValues[i].u.Integer);
1618 ldap_value_free_len(values);
1619 col->hReserved = NULL;
1620 break;
1623 case ADSTYPE_OCTET_STRING:
1624 case ADSTYPE_NT_SECURITY_DESCRIPTOR:
1626 struct berval **values = ldap_get_values_lenW(ldap->ld, ldap_ctx->entry, name);
1627 if (!values)
1628 return E_ADS_COLUMN_NOT_SET;
1629 count = ldap_count_values_len(values);
1631 col->pADsValues = calloc(count, sizeof(col->pADsValues[0]));
1632 if (!col->pADsValues)
1634 ldap_value_free_len(values);
1635 return E_OUTOFMEMORY;
1638 for (i = 0; i < count; i++)
1640 TRACE("=> %s\n", debugstr_an(values[i]->bv_val, values[i]->bv_len));
1641 col->pADsValues[i].dwType = type;
1642 col->pADsValues[i].u.OctetString.dwLength = values[i]->bv_len;
1643 col->pADsValues[i].u.OctetString.lpValue = (BYTE *)values[i]->bv_val;
1646 col->hReserved = values;
1647 break;
1650 case ADSTYPE_UTC_TIME:
1652 struct berval **values = ldap_get_values_lenW(ldap->ld, ldap_ctx->entry, name);
1653 if (!values)
1654 return E_ADS_COLUMN_NOT_SET;
1655 count = ldap_count_values_len(values);
1657 col->pADsValues = calloc(count, sizeof(col->pADsValues[0]));
1658 if (!col->pADsValues)
1660 ldap_value_free_len(values);
1661 return E_OUTOFMEMORY;
1664 for (i = 0; i < count; i++)
1666 col->pADsValues[i].dwType = type;
1667 if (values[i]->bv_len < 14 ||
1668 _snscanf_l(values[i]->bv_val, values[i]->bv_len, "%04hu%02hu%02hu%02hu%02hu%02hu", NULL,
1669 &col->pADsValues[i].u.UTCTime.wYear, &col->pADsValues[i].u.UTCTime.wMonth,
1670 &col->pADsValues[i].u.UTCTime.wDay, &col->pADsValues[i].u.UTCTime.wHour,
1671 &col->pADsValues[i].u.UTCTime.wMinute, &col->pADsValues[i].u.UTCTime.wSecond) != 6)
1673 FIXME("not recognized UTCTime: %s\n", debugstr_an(values[i]->bv_val, values[i]->bv_len));
1674 memset(&col->pADsValues[i].u.UTCTime, 0, sizeof(col->pADsValues[i].u.UTCTime));
1675 continue;
1678 if ((values[i]->bv_val[14] != '.' && values[i]->bv_val[14] != ',') ||
1679 values[i]->bv_val[15] != '0' || values[i]->bv_val[16] != 'Z')
1680 FIXME("not handled time zone: %s\n", debugstr_an(values[i]->bv_val + 14, values[i]->bv_len - 14));
1682 TRACE("%s => %02u.%02u.%04u %02u:%02u:%02u\n", debugstr_an(values[i]->bv_val, values[i]->bv_len),
1683 col->pADsValues[i].u.UTCTime.wDay, col->pADsValues[i].u.UTCTime.wMonth,
1684 col->pADsValues[i].u.UTCTime.wYear, col->pADsValues[i].u.UTCTime.wHour,
1685 col->pADsValues[i].u.UTCTime.wMinute, col->pADsValues[i].u.UTCTime.wSecond);
1688 ldap_value_free_len(values);
1689 col->hReserved = NULL;
1690 break;
1693 case ADSTYPE_DN_WITH_BINARY:
1695 static const BYTE hex2bin[] =
1697 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x00 */
1698 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x10 */
1699 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x20 */
1700 0,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0, /* 0x30 */
1701 0,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0, /* 0x40 */
1702 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x50 */
1703 0,10,11,12,13,14,15 /* 0x60 */
1705 ADS_DN_WITH_BINARY *dnb;
1706 WCHAR **values = ldap_get_valuesW(ldap->ld, ldap_ctx->entry, name);
1707 if (!values)
1708 return E_ADS_COLUMN_NOT_SET;
1709 count = ldap_count_valuesW(values);
1711 col->pADsValues = calloc(count, sizeof(col->pADsValues[0]) + sizeof(col->pADsValues[0].u.pDNWithBinary[0]));
1712 if (!col->pADsValues)
1714 ldap_value_freeW(values);
1715 return E_OUTOFMEMORY;
1718 dnb = (ADS_DN_WITH_BINARY *)(col->pADsValues + count);
1720 for (i = 0; i < count; i++)
1722 WCHAR *p = values[i];
1723 DWORD n;
1725 col->pADsValues[i].dwType = type;
1726 col->pADsValues[i].u.pDNWithBinary = dnb++;
1728 if ((p[0] != 'b' && p[0] != 'B') || p[1] != ':')
1729 FIXME("wrong DN with binary tag '%c%c'\n", p[0], p[1]);
1730 p += 2;
1732 col->pADsValues[i].u.pDNWithBinary->dwLength = wcstol(p, &p, 10) / 2;
1733 if (*p != ':')
1734 FIXME("wrong DN with binary separator '%c'\n", *p);
1735 p++;
1736 col->pADsValues[i].u.pDNWithBinary->lpBinaryValue = (BYTE *)p;
1737 /* decode values in-place */
1738 for (n = 0; n < col->pADsValues[i].u.pDNWithBinary->dwLength; n++, p += 2)
1740 BYTE b;
1742 if (p[0] > 'f' || (p[0] != '0' && !hex2bin[p[0]]) ||
1743 p[1] > 'f' || (p[1] != '0' && !hex2bin[p[1]]))
1745 FIXME("bad hex encoding at %s\n", debugstr_w(p));
1746 continue;
1749 b = (hex2bin[p[0]] << 4) | hex2bin[p[1]];
1750 col->pADsValues[i].u.pDNWithBinary->lpBinaryValue[n] = b;
1752 if (*p != ':')
1753 FIXME("wrong DN with binary separator '%c'\n", *p);
1754 col->pADsValues[i].u.pDNWithBinary->pszDNString = p + 1;
1756 TRACE("%s => %lu,%s,%s\n", debugstr_w(values[i]),
1757 col->pADsValues[i].u.pDNWithBinary->dwLength,
1758 debugstr_an((char *)col->pADsValues[i].u.pDNWithBinary->lpBinaryValue, col->pADsValues[i].u.pDNWithBinary->dwLength),
1759 debugstr_w(col->pADsValues[i].u.pDNWithBinary->pszDNString));
1762 col->hReserved = values;
1763 break;
1767 col->dwADsType = type;
1768 col->dwNumValues = count;
1769 col->pszAttrName = wcsdup(name);
1771 return S_OK;
1774 static HRESULT WINAPI search_GetColumn(IDirectorySearch *iface, ADS_SEARCH_HANDLE res,
1775 LPWSTR name, PADS_SEARCH_COLUMN col)
1777 LDAP_namespace *ldap = impl_from_IDirectorySearch(iface);
1778 struct ldap_search_context *ldap_ctx = res;
1779 HRESULT hr;
1780 ULONG count;
1782 TRACE("%p,%p,%s,%p\n", iface, res, debugstr_w(name), col);
1784 if (!res || !name || !ldap_ctx->entry) return E_ADS_BAD_PARAMETER;
1786 memset(col, 0, sizeof(*col));
1788 if (!wcsicmp(name, L"ADsPath"))
1790 WCHAR *dn = ldap_get_dnW(ldap->ld, ldap_ctx->entry);
1792 col->pADsValues = malloc(sizeof(col->pADsValues[0]));
1793 if (!col->pADsValues)
1795 hr = E_OUTOFMEMORY;
1796 goto exit;
1799 count = sizeof(L"LDAP://") + (wcslen(ldap->host) + 1 /* '/' */) * sizeof(WCHAR);
1800 if (dn) count += wcslen(dn) * sizeof(WCHAR);
1802 col->pADsValues[0].u.CaseIgnoreString = malloc(count);
1803 if (!col->pADsValues[0].u.CaseIgnoreString)
1805 hr = E_OUTOFMEMORY;
1806 goto exit;
1809 wcscpy(col->pADsValues[0].u.CaseIgnoreString, L"LDAP://");
1810 wcscat(col->pADsValues[0].u.CaseIgnoreString, ldap->host);
1811 wcscat(col->pADsValues[0].u.CaseIgnoreString, L"/");
1812 if (dn) wcscat(col->pADsValues[0].u.CaseIgnoreString, dn);
1813 col->pADsValues[0].dwType = ADSTYPE_CASE_IGNORE_STRING;
1814 col->dwADsType = ADSTYPE_CASE_IGNORE_STRING;
1815 col->dwNumValues = 1;
1816 col->pszAttrName = wcsdup(name);
1817 col->hReserved = NULL;
1819 TRACE("=> %s\n", debugstr_w(col->pADsValues[0].u.CaseIgnoreString));
1820 hr = S_OK;
1821 exit:
1822 ldap_memfreeW(dn);
1823 return hr;
1826 return add_column_values(ldap, ldap_ctx, name, col);
1829 static HRESULT WINAPI search_FreeColumn(IDirectorySearch *iface, PADS_SEARCH_COLUMN col)
1831 TRACE("%p,%p\n", iface, col);
1833 if (!col) return E_ADS_BAD_PARAMETER;
1835 if (!wcsicmp(col->pszAttrName, L"ADsPath"))
1836 free(col->pADsValues[0].u.CaseIgnoreString);
1837 free(col->pADsValues);
1838 free(col->pszAttrName);
1840 if (col->hReserved)
1842 if (col->dwADsType == ADSTYPE_OCTET_STRING || col->dwADsType == ADSTYPE_NT_SECURITY_DESCRIPTOR)
1843 ldap_value_free_len(col->hReserved);
1844 else
1845 ldap_value_freeW(col->hReserved);
1848 return S_OK;
1851 static HRESULT WINAPI search_CloseSearchHandle(IDirectorySearch *iface, ADS_SEARCH_HANDLE res)
1853 LDAP_namespace *ldap = impl_from_IDirectorySearch(iface);
1854 struct ldap_search_context *ldap_ctx = res;
1856 TRACE("%p,%p\n", iface, res);
1858 if (!res) return E_ADS_BAD_PARAMETER;
1860 if (ldap_ctx->page)
1861 ldap_search_abandon_page(ldap->ld, ldap_ctx->page);
1862 if (ldap_ctx->res)
1863 ldap_msgfree(ldap_ctx->res);
1864 if (ldap_ctx->ber)
1865 ber_free(ldap_ctx->ber, 0);
1866 free(ldap_ctx);
1868 return S_OK;
1871 static const IDirectorySearchVtbl IDirectorySearch_vtbl =
1873 search_QueryInterface,
1874 search_AddRef,
1875 search_Release,
1876 search_SetSearchPreference,
1877 search_ExecuteSearch,
1878 search_AbandonSearch,
1879 search_GetFirstRow,
1880 search_GetNextRow,
1881 search_GetPreviousRow,
1882 search_GetNextColumnName,
1883 search_GetColumn,
1884 search_FreeColumn,
1885 search_CloseSearchHandle
1888 static inline LDAP_namespace *impl_from_IDirectoryObject(IDirectoryObject *iface)
1890 return CONTAINING_RECORD(iface, LDAP_namespace, IDirectoryObject_iface);
1893 static HRESULT WINAPI dirobj_QueryInterface(IDirectoryObject *iface, REFIID riid, void **obj)
1895 LDAP_namespace *ldap = impl_from_IDirectoryObject(iface);
1897 TRACE("%p,%s,%p\n", iface, debugstr_guid(riid), obj);
1899 if (!riid || !obj) return E_INVALIDARG;
1901 if (IsEqualGUID(riid, &IID_IDirectoryObject) ||
1902 IsEqualGUID(riid, &IID_IUnknown))
1904 IDirectoryObject_AddRef(iface);
1905 *obj = iface;
1906 return S_OK;
1909 return IADs_QueryInterface(&ldap->IADs_iface, riid, obj);
1912 static ULONG WINAPI dirobj_AddRef(IDirectoryObject *iface)
1914 LDAP_namespace *ldap = impl_from_IDirectoryObject(iface);
1915 return IADs_AddRef(&ldap->IADs_iface);
1918 static ULONG WINAPI dirobj_Release(IDirectoryObject *iface)
1920 LDAP_namespace *ldap = impl_from_IDirectoryObject(iface);
1921 return IADs_Release(&ldap->IADs_iface);
1924 static HRESULT WINAPI dirobj_GetObjectInformation(IDirectoryObject *iface, PADS_OBJECT_INFO *info)
1926 FIXME("%p,%p: stub\n", iface, info);
1927 return E_NOTIMPL;
1930 static HRESULT WINAPI dirobj_GetObjectAttributes(IDirectoryObject *iface, LPWSTR *names,
1931 DWORD count, PADS_ATTR_INFO *attrs, DWORD *count_returned)
1933 FIXME("%p,%p,%lu,%p,%p: stub\n", iface, names, count, attrs, count_returned);
1934 return E_NOTIMPL;
1937 static HRESULT WINAPI dirobj_SetObjectAttributes(IDirectoryObject *iface, PADS_ATTR_INFO attrs,
1938 DWORD count, DWORD *count_set)
1940 FIXME("%p,%p,%lu,%p: stub\n", iface, attrs, count, count_set);
1941 return E_NOTIMPL;
1944 static HRESULT WINAPI dirobj_CreateDSObject(IDirectoryObject *iface, LPWSTR name,
1945 PADS_ATTR_INFO attrs, DWORD count, IDispatch **obj)
1947 FIXME("%p,%s,%p,%lu,%p: stub\n", iface, debugstr_w(name), attrs, count, obj);
1948 return E_NOTIMPL;
1951 static HRESULT WINAPI dirobj_DeleteDSObject(IDirectoryObject *iface, LPWSTR name)
1953 FIXME("%p,%s: stub\n", iface, debugstr_w(name));
1954 return E_NOTIMPL;
1957 static const IDirectoryObjectVtbl IDirectoryObject_vtbl =
1959 dirobj_QueryInterface,
1960 dirobj_AddRef,
1961 dirobj_Release,
1962 dirobj_GetObjectInformation,
1963 dirobj_GetObjectAttributes,
1964 dirobj_SetObjectAttributes,
1965 dirobj_CreateDSObject,
1966 dirobj_DeleteDSObject
1969 static HRESULT LDAPNamespace_create(REFIID riid, void **obj)
1971 LDAP_namespace *ldap;
1972 HRESULT hr;
1974 ldap = malloc(sizeof(*ldap));
1975 if (!ldap) return E_OUTOFMEMORY;
1977 ldap->IADs_iface.lpVtbl = &IADs_vtbl;
1978 ldap->IADsOpenDSObject_iface.lpVtbl = &IADsOpenDSObject_vtbl;
1979 ldap->IDirectorySearch_iface.lpVtbl = &IDirectorySearch_vtbl;
1980 ldap->IDirectoryObject_iface.lpVtbl = &IDirectoryObject_vtbl;
1981 ldap->ref = 1;
1982 ldap->ld = NULL;
1983 ldap->host = NULL;
1984 ldap->object = NULL;
1985 ldap->attrs_count = 0;
1986 ldap->attrs_count_allocated = 0;
1987 ldap->attrs = NULL;
1988 ldap->search.scope = ADS_SCOPE_SUBTREE;
1989 ldap->search.pagesize = 0;
1990 ldap->search.size_limit = 0;
1991 ldap->search.cache_results = TRUE;
1992 ldap->search.attribtypes_only = FALSE;
1993 ldap->search.tombstone = FALSE;
1994 ldap->at = NULL;
1995 ldap->at_single_count = 0;
1996 ldap->at_multiple_count = 0;
1998 hr = IADs_QueryInterface(&ldap->IADs_iface, riid, obj);
1999 IADs_Release(&ldap->IADs_iface);
2001 return hr;
2004 static const struct class_info
2006 const CLSID *clsid;
2007 HRESULT (*constructor)(REFIID, void **);
2008 } class_info[] =
2010 { &CLSID_ADSystemInfo, ADSystemInfo_create },
2011 { &CLSID_LDAP, LDAP_create },
2012 { &CLSID_LDAPNamespace, LDAPNamespace_create },
2015 typedef struct
2017 IClassFactory IClassFactory_iface;
2018 LONG ref;
2019 const struct class_info *info;
2020 } class_factory;
2022 static inline class_factory *impl_from_IClassFactory(IClassFactory *iface)
2024 return CONTAINING_RECORD(iface, class_factory, IClassFactory_iface);
2027 static HRESULT WINAPI factory_QueryInterface(IClassFactory *iface, REFIID riid, LPVOID *obj)
2029 TRACE("%p,%s,%p\n", iface, debugstr_guid(riid), obj);
2031 if (!riid || !obj) return E_INVALIDARG;
2033 if (IsEqualIID(riid, &IID_IUnknown) ||
2034 IsEqualIID(riid, &IID_IClassFactory))
2036 IClassFactory_AddRef(iface);
2037 *obj = iface;
2038 return S_OK;
2041 *obj = NULL;
2042 FIXME("interface %s is not implemented\n", debugstr_guid(riid));
2043 return E_NOINTERFACE;
2046 static ULONG WINAPI factory_AddRef(IClassFactory *iface)
2048 class_factory *factory = impl_from_IClassFactory(iface);
2049 ULONG ref = InterlockedIncrement(&factory->ref);
2051 TRACE("(%p) ref %lu\n", iface, ref);
2053 return ref;
2056 static ULONG WINAPI factory_Release(IClassFactory *iface)
2058 class_factory *factory = impl_from_IClassFactory(iface);
2059 ULONG ref = InterlockedDecrement(&factory->ref);
2061 TRACE("(%p) ref %lu\n", iface, ref);
2063 if (!ref)
2064 free(factory);
2066 return ref;
2069 static HRESULT WINAPI factory_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **obj)
2071 class_factory *factory = impl_from_IClassFactory(iface);
2073 TRACE("%p,%s,%p\n", outer, debugstr_guid(riid), obj);
2075 if (!riid || !obj) return E_INVALIDARG;
2077 *obj = NULL;
2078 if (outer) return CLASS_E_NOAGGREGATION;
2080 return factory->info->constructor(riid, obj);
2083 static HRESULT WINAPI factory_LockServer(IClassFactory *iface, BOOL lock)
2085 FIXME("%p,%d: stub\n", iface, lock);
2086 return S_OK;
2089 static const struct IClassFactoryVtbl factory_vtbl =
2091 factory_QueryInterface,
2092 factory_AddRef,
2093 factory_Release,
2094 factory_CreateInstance,
2095 factory_LockServer
2098 static HRESULT factory_constructor(const struct class_info *info, REFIID riid, void **obj)
2100 class_factory *factory;
2101 HRESULT hr;
2103 factory = malloc(sizeof(*factory));
2104 if (!factory) return E_OUTOFMEMORY;
2106 factory->IClassFactory_iface.lpVtbl = &factory_vtbl;
2107 factory->ref = 1;
2108 factory->info = info;
2110 hr = IClassFactory_QueryInterface(&factory->IClassFactory_iface, riid, obj);
2111 IClassFactory_Release(&factory->IClassFactory_iface);
2113 return hr;
2116 HRESULT WINAPI DllGetClassObject(REFCLSID clsid, REFIID iid, LPVOID *obj)
2118 int i;
2120 TRACE("%s,%s,%p\n", debugstr_guid(clsid), debugstr_guid(iid), obj);
2122 if (!clsid || !iid || !obj) return E_INVALIDARG;
2124 *obj = NULL;
2126 for (i = 0; i < ARRAY_SIZE(class_info); i++)
2128 if (IsEqualCLSID(class_info[i].clsid, clsid))
2129 return factory_constructor(&class_info[i], iid, obj);
2132 FIXME("class %s/%s is not implemented\n", debugstr_guid(clsid), debugstr_guid(iid));
2133 return CLASS_E_CLASSNOTAVAILABLE;