Hi everybody, another question from me... Can anybody provide an example how to operate an AD object, such get/set some properties of an AD user?
For the normal info of an AD user, we can use NetUserGetInfo() to get it. But for the further properties, such as Telephone/Address info, MS SDK assembled them into a CPP interface (that's a little out of my knowing). The following example is from the SDK doc:
The following C++ code example shows how to use the ADsGetObject function to bind to an object.
IADs *pObject;
HRESULT hr;
// Initialize COM.
CoInitialize(NULL);
hr = ADsGetObject(L"LDAP://CN=jeffsmith,DC=fabrikam,DC=com", 
        IID_IADs,
        (void**) &pObject);
if(SUCCEEDED(hr))
{
    // Use the object.
    // Release the object.
    pObject->Release()
}
// Uninitialize COM.
CoUninitialize();
So if I want to access this info in my C program, I need to have the C-std function/variable declare, and know how to use it.
I look into the head file "iads.h", actually they all are there:
typedef struct IADsUserVtbl {
    BEGIN_INTERFACE
    HRESULT (STDMETHODCALLTYPE * QueryInterface) (IADsUser * This, REFIID riid, void **ppvObject);
    ....
    HRESULT (STDMETHODCALLTYPE * get_TelephoneHome) (IADsUser * This, VARIANT * retval);
    HRESULT (STDMETHODCALLTYPE * put_TelephoneHome) (IADsUser * This, VARIANT vTelephoneHome);
#define IADsUser_QueryInterface(This,riid,ppvObject)  (This)->lpVtbl->QueryInterface(This,riid,ppvObject)
...
If there is a simple C-std example showing how to use them or any tips for it, I'll appreciate you very much!
			
			
			
				For C#define WIN32_LEAN_AND_MEAN
#include <windows.h>
//#define INITGUID
#include <ole2.h>
#include <Iads.h>
#include <Adshlp.h>
#pragma comment(lib, "ole32.lib")
#pragma comment(lib, "Activeds.lib")
//#pragma comment(lib, "ADSIid.lib")	// missing from PellesC
//#pragma comment(lib, "uuid.lib")
const IID IID_IADs = {0xFD8256D0, 0xFD15, 0x11CE, {0xAB,0xC4,0x02,0x60,0x8C,0x9E,0x75,0x53}};
IADs *pObject;
HRESULT hr;
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow)
{
// Initialize COM.
	CoInitialize(NULL);
	hr = ADsGetObject(L"LDAP://CN=jeffsmith,DC=fabrikam,DC=com", &IID_IADs, (void **)&pObject);
	if (SUCCEEDED(hr)) {
		// Use the object.
		// Release the object.
		pObject->lpVtbl->Release(pObject);
	}
// Uninitialize COM.
	CoUninitialize();
	return 0;
}
			
			
			
				Thanks Timovjl! I can use the functions to get the AD user properties now. This is the source code for reference:
#include <wchar.h>
#include <stdio.h>
#include <windows.h>
#include <iads.h>
#include <adshlp.h>
#pragma comment(lib, "ole32.lib")
#pragma comment(lib, "oleaut32.lib")
#pragma comment(lib, "Activeds.lib")
const IID iadsuser={0x3e37e320,0x17e2,0x11cf,{0xab,0xc4,0x02,0x60,0x8c,0x9e,0x75,0x53}};
int main(int argc,char *argv[])
{
	IADsUser *pObject;
	HRESULT hr,hr1;
	BSTR bstr;
	VARIANT var;
	// Initialize COM.
	CoInitialize(NULL);
	hr = ADsGetObject(L"LDAP://CN=Full Name,OU=XX,OU=YY,DC=ABC,DC=COM",&iadsuser,(void**)&pObject);
	//hr = ADsGetObject(L"WinNT://ABC.COM/Shortname,user",&iadsuser,(void**)&pObject);
	if(hr==S_OK)
	{
	    // Use the object.
		printf("Success -> ADsGetObject()\n");
		char text[100];
		memset(text,0,sizeof(text));
		hr1=pObject->lpVtbl->get_FullName(pObject,&bstr);
		if(hr1==S_OK){
			printf("Success -> get_FullName()\n");
			wcstombs(text,bstr,wcslen((wchar_t *)bstr));
			printf("%s\n",text);
			SysFreeString(bstr);
		}
		else printf("Fail code=%lx -> get_FullName()\n",hr1);
		memset(text,0,sizeof(text));
		hr1=pObject->lpVtbl->get_EmailAddress(pObject,&bstr);
		if(hr1==S_OK){
			printf("Success -> get_EmailAddress()\n");
			wcstombs(text,bstr,wcslen((wchar_t *)bstr));
			printf("%s\n",text);
			SysFreeString(bstr);
		}
		else printf("Fail code=%lx -> get_EmailAddress()\n",hr1);
		memset(text,0,sizeof(text));
		hr1=pObject->lpVtbl->get_TelephonePager(pObject,&var);
		if(hr1==S_OK){
			printf("Success -> get_TelephonePager()\n");
			wcstombs(text,V_BSTR(&var),wcslen((wchar_t *)V_BSTR(&var)));
			printf("%s\n",text);
			VariantClear(&var);
		}
		else printf("Fail code=%lx -> get_TelephonePager()\n",hr1);
	    // Release the object.
//	    pObject->Release();
		pObject->lpVtbl->Release(pObject);
	}
	else printf("Fail code=%lx -> Release()\n",hr);
	// Uninitialize COM.
	CoUninitialize();
	return 0;
}
For the ADsGetObject(), if I use WinNT format string, then many properties can't be got (this is mentioned in Win SDK document); if I use LDAP format string, I have to use an 'exact' path and full name string to get the object. Then I have further questions now:
1) If I only know the AD user's login name (shortname), I don't know how to find it out or convert it to the full LDAP string;
2) I don't know how to enum or set filter to search a mass of AD users, although I know it's possible technically.
			
			
			
				I just found another set of interface of MS native api for ldap. Here is an example:
http://msdn.microsoft.com/en-us/library/windows/desktop/aa367016(v=vs.85).aspx
It works with a little modification. There is 2 notices:
1) in ldap_bind_s(), if the method is LDAP_AUTH_NEGOTIATE, the DN and Cred can be set to NULL (use current user);
2) in ldap_search_s(), this link is the description of syntax: 
http://msdn.microsoft.com/en-us/library/windows/desktop/aa746475(v=vs.85).aspx
Now I'm studying what info/entry the ldap can provide to me.
			
			
			
				Use ldap_get_dn() to retrieve the full DN string with following the ldap_first_entry() and ldap_next_entry()
			
			
			
				http://msdn.microsoft.com/en-us/library/windows/desktop/ms675089(v=vs.85).aspx
Here all the attributes can be found out.
			
			
			
				I have create a simle program showing how to walk through and enum all objects/users' information under a certain OU.
#define UNICODE
#define COBJMACROS
#include <windows.h>
#include <wchar.h>
#include <iads.h>
#include <adshlp.h>
#pragma comment(lib, "ole32.lib")
#pragma comment(lib, "oleaut32.lib")
#pragma comment(lib, "Activeds.lib")
#pragma comment(lib, "User32.lib")
const IID iads_container={0x001677d0,0xfd16,0x11ce,{0xab,0xc4,0x02,0x60,0x8c,0x9e,0x75,0x53}};
const IID iads={0xfd8256d0,0xfd15,0x11ce,{0xab,0xc4,0x02,0x60,0x8c,0x9e,0x75,0x53}};
int read_all_objects(IADsContainer *p_container)
{
	int num_objects=0;
	HRESULT hr;
	// 1. Build Enumerator for the AD Object
	IEnumVARIANT *p_enum=NULL;
	hr=ADsBuildEnumerator(p_container,&p_enum);
	if(hr!=S_OK) return 0;
	// 2. Enum Each Object
	VARIANT var;
	while(TRUE){
		// 2.1 Enum One Object
		hr=ADsEnumerateNext(p_enum,1,&var,NULL);
		if(hr==S_FALSE) break; // No more object
		num_objects++;
		// 2.2 Query Object's Interface
		IADs *p_ads=NULL;
		//hr=V_DISPATCH(&var)->QueryInterface(&iads,(void **)&p_ads);
		hr=IADs_QueryInterface(V_DISPATCH(&var),&iads,(void **)&p_ads);
		if(hr==S_OK){
			// 2.2.1 Get Object's Name
			BSTR name_str;
			HRESULT hr1;
			hr1=p_ads->lpVtbl->get_Name(p_ads,&name_str);
			if(hr1==S_OK){
				HRESULT hr2;
				// 2.2.1.1 Output Object's Name
				wprintf(L"Object name: %ls\n",(wchar_t *)name_str);
				// 2.2.1.2 Get & Output Object's Full Name
				wprintf(L"Full name: %ls\n",wcschr((wchar_t *)name_str,L'=')+1);
				// 2.2.1.3 Get & Output Object's Principal Name if it's a regular user, Format: accountname@domainname
				VARIANT var_principalname;
				hr2=p_ads->lpVtbl->Get(p_ads,L"userPrincipalName",&var_principalname);
				if(hr2==S_OK){
					wprintf(L"Principal name: %ls\n",(wchar_t *)V_BSTR(&var_principalname));
					VariantClear(&var_principalname);
				}
				// 2.2.1.4 Get & Output Object's Email Address if there is this information
				VARIANT var_mail;
				hr2=p_ads->lpVtbl->Get(p_ads,L"mail",&var_mail);
				if(hr2==S_OK){
					wprintf(L"Email address: %ls\n\n",(wchar_t *)V_BSTR(&var_mail));
					VariantClear(&var_mail);
				}
				// 2.2.1.n-1 Read Sub-Objects
				IADsContainer *p_child_ads;
				hr2=IADsContainer_QueryInterface(p_ads,&iads_container,(void **)&p_child_ads);
				if(hr2==S_OK){
					num_objects+=read_all_objects(p_child_ads);
				}
				// 2.2.1.n Release str space
				SysFreeString(name_str);
			}
			// 2.2.n Release Object
			p_ads->lpVtbl->Release(p_ads);
		}
		// 2.n Clean up VAR
		VariantClear(&var);
	}
	// n. Free Enumerator
	ADsFreeEnumerator(p_enum);
	return num_objects;
}
int read_ad_tree(wchar_t *ldap_tree_name)
{
	HRESULT hr;
	IADsContainer *p_container=NULL;
	hr=ADsGetObject(ldap_tree_name,&iads_container,(void **)&p_container);
	if(hr!=S_OK) return -1;
	return read_all_objects(p_container);
}
int main(int argc,char *argv[])
{
	int ret;
	CoInitialize(NULL);
	ret=read_ad_tree(L"LDAP://OU=DEPTNAME,DC=ABC,DC=COM");
	if(ret>=0) wprintf(L"Success & found %d objects.\n",ret);
	if(ret==-1) wprintf(L"ADsGetObject() error.\n");
	CoUninitialize();
	return 0;
}