I am currently trying to perform an LDAP query in c++ to get the memberOf attribute of a given user. I have a function written that successfully gets the attribute if they are only in one group. The problem is that when they are in more than one group it only returns the first one. When I look at the user in Active Directory browser I can see that it says they have 2 entries for memberOf, but when I use my function I only get the first. Is there a way to modify my function to pull back all the entries or am I completely on the wrong path?
bool FindADMembership(CStringArray* pUserArray,IDirectorySearch *pContainerToSearch, CString sAMAccountName){
if(pContainerToSearch==NULL||pUserArray==NULL)
return false;
CString strSearchFilter;
strSearchFilter.Format("(&(objectClass=user)(objectCategory=person)(sAMAccountName=%s))", sAMAccountName);
BSTR b = strSearchFilter.AllocSysString();
LPOLESTR pszSearchFilter = b;
ADS_SEARCHPREF_INFO SearchPrefs;
SearchPrefs.dwSearchPref = ADS_SEARCHPREF_SEARCH_SCOPE;
SearchPrefs.vValue.dwType = ADSTYPE_INTEGER;
SearchPrefs.vValue.Integer = ADS_SCOPE_SUBTREE;
DWORD dwNumPrefs = 1;
LPOLESTR pszColumn = NULL;
ADS_SEARCH_COLUMN col;
HRESULT hr;
IADs *pObj = NULL;
IADs * pIADs = NULL;
ADS_SEARCH_HANDLE hSearch = NULL;
hr = pContainerToSearch->SetSearchPreference( &SearchPrefs, dwNumPrefs);
if (FAILED(hr))
return false;
LPOLESTR pszNonVerboseList[] = {L"memberOf"};
LPOLESTR szName = new OLECHAR[MAX_PATH];
int iCount = 0;
hr = pContainerToSearch->ExecuteSearch(pszSearchFilter, pszNonVerboseList,sizeof(pszNonVerboseList)/sizeof(LPOLESTR),&hSearch);
if ( SUCCEEDED(hr) )
{
hr = pContainerToSearch->GetFirstRow( hSearch);
if (SUCCEEDED(hr))
{
while( hr != S_ADS_NOMORE_ROWS )
{
iCount++;
while( pContainerToSearch->GetNextColumnName( hSearch, &pszColumn ) != S_ADS_NOMORE_COLUMNS )
{
hr = pContainerToSearch->GetColumn( hSearch, pszColumn, &col );
if ( SUCCEEDED(hr) )
{
if (0==wcscmp(L"memberOf", pszColumn))
{
wcscpy(szName,col.pADsValues->CaseIgnoreString);
pUserArray->Add(szName);
}
pContainerToSearch->FreeColumn( &col );
}
FreeADsMem( pszColumn );
}
hr = pContainerToSearch->GetNextRow( hSearch);
}
}
else
return false;
pContainerToSearch->CloseSearchHandle(hSearch);
}
else
return false;
return true; }
Edit:
After working on this here is the code to iterate through the results
if (0==wcscmp(L"memberOf", pszColumn)) {
for(int i = 0; i < col.dwNumValues; i++)
{
wcscpy(szName, col.pADsValues[i].CaseIgnoreString);
pUserArray->Add(szName);
}
}
You need to check the number of values and loop over them to get each in turn - pADSValues is an array that could contain > 1 string. The count is returned in dwNumValues.
if (0==wcscmp(L"memberOf", pszColumn))
{
// This code should actually be a loop for i = 0 to dwNumValues - 1
// with each loop checking the next array entry in the list pADsValues
wcscpy(szName,col.pADsValues->CaseIgnoreString);
pUserArray->Add(szName);
}
See docs here.
Related
I am wrote a function which return all the direct reports of the active directory user but it return only the first value rather returning all the direct reports.
void getDirectReports(LPCWSTR pwszAccountName) {
HRESULT hr;
CoInitialize(NULL);
IDirectorySearch* pdSearch = NULL;
ADS_SEARCH_COLUMN col;
CComBSTR path = L"LDAP://WIN-F94H2MP3UJR.Test.local/CN=";
path += pwszAccountName;
path += L",CN=Users,DC=Test,DC=local";
hr = ADsOpenObject(path, L"Administrator", L"Password",
ADS_SECURE_AUTHENTICATION, // For secure authentication
IID_IDirectorySearch,
(void**)&pdSearch);
if (SUCCEEDED(hr)) {
LPWSTR directReports = convert(L"directReports");
LPWSTR pszAttr[] = { directReports};
ADS_SEARCH_HANDLE hSearch;
DWORD dwCount = 0;
DWORD nameSize = sizeof(pszAttr) / sizeof(LPWSTR);
LPWSTR path = convert(L"(&(objectClass=user))");
hr = pdSearch->ExecuteSearch(path, pszAttr, nameSize, &hSearch);
while (pdSearch->GetNextRow(hSearch) != S_ADS_NOMORE_ROWS) {
hr = pdSearch->GetColumn(hSearch,directReports, &col);
if (SUCCEEDED(hr)) {
printf("%S\n", (BSTR)col.pADsValues->CaseIgnoreString);
}
}
}
}
I have 5 direct reports to the ad user and this function only prints the first value alone.
The IDirectorySearch::GetColumn method will give you an ADS_SEARCH_COLUMN structure in your col variable. That documentation tells us that the value in col.pADsValues is an array, with the array size given in the col.dwNumValues.
In C++, accessing an array without the index (like col.pADsValues) is equivalent to reading the first value in the array (col.pADsValues[0]).
You just need to loop through the array.
hr = pdSearch->GetColumn(hSearch,directReports, &col);
if (SUCCEEDED(hr)) {
for (DWORD x = 0; x < col.dwNumValues; x++) {
printf("%S\n", (BSTR)col.pADsValues[x].CaseIgnoreString);
}
}
Iam new to c++. Using the help of MSDN article iam trying to fetch all the computers under a OU in domain using ADSI. But Iam getting 8254L (FILTER_UNKNOWN) error. Iam not sure what iam doing wrong here. I tried to update the filter but no change in the error. Please suggest what iam doing wrong here.
Below is the code am using for getting the list.
// ConsoleApplication3.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <objbase.h>
#include <wchar.h>
#include <activeds.h>
#include <sddl.h>
#include <comutil.h>
#include <string.h>
#include <stdio.h>
HRESULT FindComputers(IDirectorySearch *pContainerToSearch, // IDirectorySearch pointer to the container to search.
LPOLESTR szFilter, // Filter to find specific users.
// NULL returns all user objects.
LPOLESTR *pszPropertiesToReturn, // Properties to return for user objects found.
// NULL returns all set properties.
BOOL bIsVerbose // TRUE indicates that display all properties for the found objects.
// FALSE indicates that only the RDN.
);
// Entry point for the application.
void wmain(int argc, wchar_t *argv[])
{
// Initialize COM.
CoInitialize(NULL);
HRESULT hr = S_OK;
// Get rootDSE and the current user domain container distinguished name.
IADs *pObject = NULL;
IDirectorySearch *pContainerToSearch = NULL;
LPOLESTR szPath = new OLECHAR[MAX_PATH];
BOOL bReturnVerbose = FALSE;
DWORD dwLength = MAX_PATH * 2;
LPOLESTR pszBuffer = new OLECHAR[dwLength];
VARIANT var;
hr = ADsOpenObject(L"LDAP://rootDSE",
NULL,
NULL,
ADS_SECURE_AUTHENTICATION, // Use Secure Authentication.
IID_IADs,
(void**)&pObject);
if (FAILED(hr))
{
wprintf(L"Cannot execute query. Cannot bind to LDAP://rootDSE.\n");
if (pObject)
pObject->Release();
return;
}
if (SUCCEEDED(hr))
{
hr = pObject->Get(_bstr_t("defaultNamingContext"), &var);
if (SUCCEEDED(hr))
{
wprintf(L"bstrVal: %s\n", var.bstrVal);
// Build path to the domain container.
// wcsncpy_s(szPath, L"LDAP://", MAX_PATH);
// wcsncat_s(szPath, var.bstrVal, MAX_PATH - wcslen(szPath));
//hr = ADsOpenObject(szPath,
hr = ADsOpenObject(L"LDAP://OU=IA Computers,OU=Infosys,DC=iaseries,Dc=local",
NULL,
NULL,
ADS_SECURE_AUTHENTICATION, // Use Secure Authentication.
IID_IDirectorySearch,
(void**)&pContainerToSearch);
if (SUCCEEDED(hr))
{
hr = FindComputers(pContainerToSearch, // IDirectorySearch pointer to domainDNS container.
pszBuffer,
NULL, // Return all properties.
bReturnVerbose
);
if (SUCCEEDED(hr))
{
if (S_FALSE == hr)
wprintf(L"Computer object cannot be found.\n");
}
else if (E_ADS_INVALID_FILTER == hr)
wprintf(L"Cannot execute query. Invalid filter was specified.\n");
else
wprintf(L"Query failed to run. HRESULT: %x\n", hr);
}
else
{
wprintf(L"Cannot execute query. Cannot bind to the container.\n");
}
if (pContainerToSearch)
pContainerToSearch->Release();
}
VariantClear(&var);
}
if (pObject)
pObject->Release();
// Uninitialize COM.
CoUninitialize();
delete[] szPath;
delete[] pszBuffer;
getchar();
}
HRESULT FindComputers(IDirectorySearch *pContainerToSearch, // IDirectorySearch pointer to the container to search.
LPOLESTR szFilter, // Filter for finding specific users.
// NULL returns all user objects.
LPOLESTR *pszPropertiesToReturn, // Properties to return for user objects found.
// NULL returns all set properties.
BOOL bIsVerbose // TRUE indicates that all properties for the found objects are displayed.
// FALSE indicates only the RDN.
)
{
if (!pContainerToSearch)
return E_POINTER;
DWORD dwLength = (MAX_PATH * 2)+100;
// Create search filter.
LPOLESTR pszSearchFilter = new OLECHAR[dwLength];
// Add the filter.
//swprintf_s(pszSearchFilter, dwLength, L"((objectClass=Computer)%s)", szFilter);
swprintf_s(pszSearchFilter, dwLength, L"(&(objectClass=*)(objectCategory=Computer)%s)", szFilter);
// Specify subtree search.
ADS_SEARCHPREF_INFO SearchPrefs;
SearchPrefs.dwSearchPref = ADS_SEARCHPREF_SEARCH_SCOPE;
SearchPrefs.vValue.dwType = ADSTYPE_INTEGER;
SearchPrefs.vValue.Integer = ADS_SCOPE_SUBTREE;
DWORD dwNumPrefs = 1;
// COL for iterations.
LPOLESTR pszColumn = NULL;
ADS_SEARCH_COLUMN col;
HRESULT hr = S_OK;
// Interface Pointers
IADs *pObj = NULL;
IADs * pIADs = NULL;
// Search handle.
ADS_SEARCH_HANDLE hSearch = NULL;
// Set search preference.
hr = pContainerToSearch->SetSearchPreference(&SearchPrefs, dwNumPrefs);
if (FAILED(hr))
return hr;
LPOLESTR pszBool = NULL;
DWORD dwBool = 0;
PSID pObjectSID = NULL;
LPOLESTR szSID = NULL;
LPOLESTR szDSGUID = new WCHAR[39];
LPGUID pObjectGUID = NULL;
SYSTEMTIME systemtime;
DATE date;
VARIANT varDate;
LPOLESTR *pszPropertyList = NULL;
LPOLESTR pszNonVerboseList[] = { L"name", L"distinguishedName" };
LPOLESTR szName = new OLECHAR[MAX_PATH];
LPOLESTR szDN = new OLECHAR[MAX_PATH];
VariantInit(&varDate);
int iCount = 0;
DWORD x = 0L;
if (!bIsVerbose)
{
// Return non-verbose list properties only.
hr = pContainerToSearch->ExecuteSearch(pszSearchFilter,
pszNonVerboseList,
sizeof(pszNonVerboseList) / sizeof(LPOLESTR),
&hSearch
);
}
else
{
if (!pszPropertiesToReturn)
{
// Return all properties.
hr = pContainerToSearch->ExecuteSearch(pszSearchFilter,
NULL,
(DWORD)-1,
&hSearch
);
}
else
{
// Specified subset.
pszPropertyList = pszPropertiesToReturn;
// Return specified properties.
hr = pContainerToSearch->ExecuteSearch(pszSearchFilter,
pszPropertyList,
sizeof(pszPropertyList) / sizeof(LPOLESTR),
&hSearch
);
}
}
if (SUCCEEDED(hr))
{
// Call IDirectorySearch::GetNextRow() to retrieve the next data row.
hr = pContainerToSearch->GetFirstRow(hSearch);
if (SUCCEEDED(hr))
{
while (hr != S_ADS_NOMORE_ROWS)
{
// Keep track of count.
iCount++;
if (bIsVerbose)
wprintf(L"----------------------------------\n");
// Loop through the array of passed column names,
// print the data for each column.
while (pContainerToSearch->GetNextColumnName(hSearch, &pszColumn) != S_ADS_NOMORE_COLUMNS)
{
hr = pContainerToSearch->GetColumn(hSearch, pszColumn, &col);
if (SUCCEEDED(hr))
{
// Print the data for the column and free the column.
if (bIsVerbose)
{
// Get the data for this column.
wprintf(L"%s\n", col.pszAttrName);
switch (col.dwADsType)
{
case ADSTYPE_DN_STRING:
for (x = 0; x< col.dwNumValues; x++)
{
wprintf(L" %s\r\n", col.pADsValues[x].DNString);
}
break;
case ADSTYPE_CASE_EXACT_STRING:
case ADSTYPE_CASE_IGNORE_STRING:
case ADSTYPE_PRINTABLE_STRING:
case ADSTYPE_NUMERIC_STRING:
case ADSTYPE_TYPEDNAME:
case ADSTYPE_FAXNUMBER:
case ADSTYPE_PATH:
for (x = 0; x< col.dwNumValues; x++)
{
wprintf(L" %s\r\n", col.pADsValues[x].CaseIgnoreString);
}
break;
case ADSTYPE_BOOLEAN:
for (x = 0; x< col.dwNumValues; x++)
{
dwBool = col.pADsValues[x].Boolean;
pszBool = dwBool ? L"TRUE" : L"FALSE";
wprintf(L" %s\r\n", pszBool);
}
break;
case ADSTYPE_INTEGER:
for (x = 0; x< col.dwNumValues; x++)
{
wprintf(L" %d\r\n", col.pADsValues[x].Integer);
}
break;
case ADSTYPE_OCTET_STRING:
if (_wcsicmp(col.pszAttrName, L"objectSID") == 0)
{
for (x = 0; x< col.dwNumValues; x++)
{
pObjectSID = (PSID)(col.pADsValues[x].OctetString.lpValue);
// Convert SID to string.
ConvertSidToStringSid(pObjectSID, &szSID);
wprintf(L" %s\r\n", szSID);
LocalFree(szSID);
}
}
else if ((_wcsicmp(col.pszAttrName, L"objectGUID") == 0))
{
for (x = 0; x< col.dwNumValues; x++)
{
// Cast to LPGUID.
pObjectGUID = (LPGUID)(col.pADsValues[x].OctetString.lpValue);
// Convert GUID to string.
::StringFromGUID2(*pObjectGUID, szDSGUID, 39);
// Print the GUID.
wprintf(L" %s\r\n", szDSGUID);
}
}
else
wprintf(L" Value of type Octet String. No Conversion.");
break;
case ADSTYPE_UTC_TIME:
for (x = 0; x< col.dwNumValues; x++)
{
systemtime = col.pADsValues[x].UTCTime;
if (SystemTimeToVariantTime(&systemtime,
&date) != 0)
{
// Pack in variant.vt.
varDate.vt = VT_DATE;
varDate.date = date;
VariantChangeType(&varDate, &varDate, VARIANT_NOVALUEPROP, VT_BSTR);
wprintf(L" %s\r\n", varDate.bstrVal);
VariantClear(&varDate);
}
else
wprintf(L" Could not convert UTC-Time.\n", pszColumn);
}
break;
case ADSTYPE_NT_SECURITY_DESCRIPTOR:
for (x = 0; x< col.dwNumValues; x++)
{
wprintf(L" Security descriptor.\n");
}
break;
default:
wprintf(L"Unknown type %d.\n", col.dwADsType);
}
}
else
{
#ifdef _MBCS
// Verbose handles only the two single-valued attributes: cn and ldapdisplayname,
// so this is a special case.
if (0 == wcscmp(L"name", pszColumn))
{
//wcscpy_s(szName, col.pADsValues->CaseIgnoreString);
szName = col.pADsValues->CaseIgnoreString;
}
if (0 == wcscmp(L"distinguishedName", pszColumn))
{
//wcscpy_s(szDN, col.pADsValues->CaseIgnoreString);
szDN = col.pADsValues->CaseIgnoreString;
}
#endif _MBCS
}
pContainerToSearch->FreeColumn(&col);
}
FreeADsMem(pszColumn);
}
if (!bIsVerbose)
wprintf(L"%s\n DN: %s\n\n", szName, szDN);
// Get the next row.
hr = pContainerToSearch->GetNextRow(hSearch);
}
}
// Close the search handle to cleanup.
pContainerToSearch->CloseSearchHandle(hSearch);
}
if (SUCCEEDED(hr) && 0 == iCount)
hr = S_FALSE;
delete[] szName;
delete[] szDN;
delete[] szDSGUID;
delete[] pszSearchFilter;
return hr;
}
Iam able to figure out the issue. Below is the code for working sample.
I haven't cleaned the code much. Please update if you intend to use.
// ConsoleApplication3.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <objbase.h>
#include <wchar.h>
#include <activeds.h>
#include <sddl.h>
#include <comutil.h>
#include <string.h>
#include <stdio.h>
HRESULT FindComputers(IDirectorySearch *pContainerToSearch); // IDirectorySearch pointer to the container to search.
// Entry point for the application.
void wmain(int argc, wchar_t *argv[])
{
// Initialize COM.
CoInitialize(NULL);
HRESULT hr = S_OK;
// Get rootDSE and the current user domain container distinguished name.
IADs *pObject = NULL;
IDirectorySearch *pContainerToSearch = NULL;
LPOLESTR szPath = new OLECHAR[MAX_PATH];
BOOL bReturnVerbose = FALSE;
DWORD dwLength = MAX_PATH * 2;
VARIANT var;
hr = ADsOpenObject(L"LDAP://rootDSE",
NULL,
NULL,
ADS_SECURE_AUTHENTICATION, // Use Secure Authentication.
IID_IADs,
(void**)&pObject);
if (FAILED(hr))
{
wprintf(L"Cannot execute query. Cannot bind to LDAP://rootDSE.\n");
if (pObject)
pObject->Release();
return;
}
if (SUCCEEDED(hr))
{
hr = pObject->Get(_bstr_t("defaultNamingContext"), &var);
if (SUCCEEDED(hr))
{
//wprintf(L"bstrVal: %s\n", var.bstrVal);
// Build path to the domain container.
// wcsncpy_s(szPath, L"LDAP://", MAX_PATH);
// wcsncat_s(szPath, var.bstrVal, MAX_PATH - wcslen(szPath));
//hr = ADsOpenObject(szPath,
hr = ADsOpenObject(L"LDAP://OU=IA Computers,OU=MyDept,DC=Test,Dc=com",
NULL,
NULL,
ADS_SECURE_AUTHENTICATION, // Use Secure Authentication.
IID_IDirectorySearch,
(void**)&pContainerToSearch);
if (SUCCEEDED(hr))
{
hr = FindComputers(pContainerToSearch); // IDirectorySearch pointer to domainDNS container.
if (SUCCEEDED(hr))
{
if (S_FALSE == hr)
wprintf(L"Computer object cannot be found.\n");
}
else if (E_ADS_INVALID_FILTER == hr)
wprintf(L"Cannot execute query. Invalid filter was specified.\n");
else
wprintf(L"Query failed to run. HRESULT: %x\n", hr);
}
else
{
wprintf(L"Cannot execute query. Cannot bind to the container.\n");
}
if (pContainerToSearch)
pContainerToSearch->Release();
}
VariantClear(&var);
}
if (pObject)
pObject->Release();
// Uninitialize COM.
CoUninitialize();
delete[] szPath;
getchar();
}
HRESULT FindComputers(IDirectorySearch *pContainerToSearch) // IDirectorySearch pointer to the container to search.
{
if (!pContainerToSearch)
return E_POINTER;
DWORD dwLength = (MAX_PATH * 2);
// Create search filter.
LPOLESTR pszSearchFilter = new OLECHAR[dwLength];
// Add the filter.
pszSearchFilter = L"((objectCategory=computer))";
// Specify subtree search.
ADS_SEARCHPREF_INFO SearchPrefs;
SearchPrefs.dwSearchPref = ADS_SEARCHPREF_SEARCH_SCOPE;
SearchPrefs.vValue.dwType = ADSTYPE_INTEGER;
SearchPrefs.vValue.Integer = ADS_SCOPE_SUBTREE;
DWORD dwNumPrefs = 1;
// COL for iterations.
LPOLESTR pszColumn = NULL;
ADS_SEARCH_COLUMN col;
HRESULT hr = S_OK;
// Interface Pointers
IADs *pObj = NULL;
IADs * pIADs = NULL;
// Search handle.
ADS_SEARCH_HANDLE hSearch = NULL;
// Set search preference.
hr = pContainerToSearch->SetSearchPreference(&SearchPrefs, dwNumPrefs);
if (FAILED(hr))
return hr;
LPOLESTR pszNonVerboseList[] = { L"name", L"distinguishedName" };
LPOLESTR szName = new OLECHAR[MAX_PATH];
LPOLESTR szDN = new OLECHAR[MAX_PATH];
int iCount = 0;
DWORD x = 0L;
// Return non-verbose list properties only.
hr = pContainerToSearch->ExecuteSearch(pszSearchFilter,
pszNonVerboseList,
sizeof(pszNonVerboseList) / sizeof(LPOLESTR),
&hSearch
);
if (SUCCEEDED(hr))
{
// Call IDirectorySearch::GetNextRow() to retrieve the next data row.
hr = pContainerToSearch->GetFirstRow(hSearch);
if (SUCCEEDED(hr))
{
while (hr != S_ADS_NOMORE_ROWS)
{
// Keep track of count.
iCount++;
// Loop through the array of passed column names,
// print the data for each column.
while (pContainerToSearch->GetNextColumnName(hSearch, &pszColumn) != S_ADS_NOMORE_COLUMNS)
{
hr = pContainerToSearch->GetColumn(hSearch, pszColumn, &col);
if (SUCCEEDED(hr))
{
// Verbose handles only the two single-valued attributes: cn and ldapdisplayname,
// so this is a special case.
if (0 == wcscmp(L"name", pszColumn))
{
//wcscpy_s(szName, col.pADsValues->CaseIgnoreString);
szName = col.pADsValues->CaseIgnoreString;
}
if (0 == wcscmp(L"distinguishedName", pszColumn))
{
//wcscpy_s(szDN, col.pADsValues->CaseIgnoreString);
szDN = col.pADsValues->CaseIgnoreString;
}
pContainerToSearch->FreeColumn(&col);
}
FreeADsMem(pszColumn);
}
wprintf(L"%s\n DN: %s\n\n", szName, szDN);
// Get the next row.
hr = pContainerToSearch->GetNextRow(hSearch);
}
}
// Close the search handle to cleanup.
pContainerToSearch->CloseSearchHandle(hSearch);
}
if (SUCCEEDED(hr) && 0 == iCount)
hr = S_FALSE;
delete[] szName;
delete[] szDN;
delete[] pszSearchFilter;
return hr;
}
Thanks,
Vijay
I need to find all the groups a particular user is a member of. I'm using C++, not Powershell, if this is the wrong forum I apologize.
From what I've found on the web I need to retrieve the memberOf property, but I get an error that the property doesn't exist. Any help would be appreciated. Here's the code:
HRESULT hrObj = E_FAIL;
HRESULT hr = E_FAIL;
ADS_SEARCHPREF_INFO SearchPrefs;
// COL for iterations
ADS_SEARCH_COLUMN col;
// Handle used for searching
ADS_SEARCH_HANDLE hSearch;
// Search entire subtree from root.
SearchPrefs.dwSearchPref = ADS_SEARCHPREF_SEARCH_SCOPE;
SearchPrefs.vValue.dwType = ADSTYPE_INTEGER;
SearchPrefs.vValue.Integer = ADS_SCOPE_SUBTREE;
// Set the search preference.
DWORD dwNumPrefs = 1;
hr = pSearchBase->SetSearchPreference(&SearchPrefs, dwNumPrefs);
if (FAILED(hr))
{
return hr;
}
// Create search filter.
LPWSTR pszFormat = L"(&(objectCategory=person)(objectClass=user)(sAMAccountName=%s))";
int len = wcslen(pszFormat) + wcslen(szFindUser) + 1;
LPWSTR pszSearchFilter = new WCHAR[len];
if(NULL == pszSearchFilter)
{
return E_OUTOFMEMORY;
}
swprintf_s(pszSearchFilter, len, pszFormat, szFindUser);
// Set attributes to return.
LPWSTR pszAttribute[NUM_ATTRIBUTES] = {L"ADsPath"};
// Execute the search.
hr = pSearchBase->ExecuteSearch(pszSearchFilter,
pszAttribute,
NUM_ATTRIBUTES,
&hSearch);
if (SUCCEEDED(hr))
{
// Call IDirectorySearch::GetNextRow() to retrieve the next row of data.
while(pSearchBase->GetNextRow(hSearch) != S_ADS_NOMORE_ROWS)
{
// Loop through the array of passed column names and
// print the data for each column.
for (DWORD x = 0; x < NUM_ATTRIBUTES; x++)
{
// Get the data for this column.
hr = pSearchBase->GetColumn(hSearch, pszAttribute[x], &col);
if (SUCCEEDED(hr))
{
// Print the data for the column and free the column.
// Be aware that the requested attribute is type CaseIgnoreString.
if (ADSTYPE_CASE_IGNORE_STRING == col.dwADsType)
{
IADs *pADS;
hr = ADsOpenObject( col.pADsValues->CaseIgnoreString,
L"Administrator",
L"passW0rd",
ADS_SECURE_AUTHENTICATION,
IID_IADs,
(void**)&pADS);
VARIANT var;
VariantInit(&var);
if (SUCCEEDED(hr))
{
hr = pADS->GetEx(L"memberOf", &var); <-- FAILS!!!
wprintf(L"Found User.\n",szFindUser);
wprintf(L"%s: %s\r\n",pszAttribute[x],col.pADsValues->CaseIgnoreString);
hrObj = S_OK;
}
}
pSearchBase->FreeColumn( &col );
}
else
{
hr = E_FAIL;
}
}
}
// Close the search handle to cleanup.
pSearchBase->CloseSearchHandle(hSearch);
}
delete pszSearchFilter;
if (FAILED(hrObj))
{
hr = hrObj;
}
Unless you're set on using AD directly, it's probably easier to use the Windows Net* functions for the job:
#include <windows.h>
#include <lm.h>
#include <stdio.h>
int main() {
wchar_t user[256];
DWORD size = sizeof(user)/sizeof(user[0]);
GetUserNameW(user, &size);
printf("User: %S\n", user);
printf("Local groups: \n");
LPBYTE buffer;
DWORD entries, total_entries;
NetUserGetLocalGroups(NULL, user, 0, LG_INCLUDE_INDIRECT, &buffer, MAX_PREFERRED_LENGTH, &entries, &total_entries);
LOCALGROUP_USERS_INFO_0 *groups = (LOCALGROUP_USERS_INFO_0*)buffer;
for (int i=0; i<entries; i++)
printf("\t%S\n", groups[i].lgrui0_name);
NetApiBufferFree(buffer);
printf("Global groups: \n");
NetUserGetGroups(NULL, user, 0, &buffer, MAX_PREFERRED_LENGTH, &entries, &total_entries);
GROUP_USERS_INFO_0 *ggroups = (GROUP_USERS_INFO_0*)buffer;
for (int i=0; i<entries; i++)
printf("\t%S\n", ggroups[i].grui0_name);
NetApiBufferFree(buffer);
return 0;
}
Thanks for the reply, I think I found what I was looking for in MSDN.
HRESULT CheckUserGroups(IADsUser *pUser)
{
IADsMembers *pGroups;
HRESULT hr = S_OK;
hr = pUser->Groups(&pGroups);
pUser->Release();
if (FAILED(hr)) return hr;
IUnknown *pUnk;
hr = pGroups->get__NewEnum(&pUnk);
if (FAILED(hr)) return hr;
pGroups->Release();
IEnumVARIANT *pEnum;
hr = pUnk->QueryInterface(IID_IEnumVARIANT,(void**)&pEnum);
if (FAILED(hr)) return hr;
pUnk->Release();
// Enumerate.
BSTR bstr;
VARIANT var;
IADs *pADs;
ULONG lFetch;
IDispatch *pDisp;
VariantInit(&var);
hr = pEnum->Next(1, &var, &lFetch);
while(hr == S_OK)
{
if (lFetch == 1)
{
pDisp = V_DISPATCH(&var);
pDisp->QueryInterface(IID_IADs, (void**)&pADs);
pADs->get_Name(&bstr);
printf("Group belonged: %S\n",bstr);
SysFreeString(bstr);
pADs->Release();
}
VariantClear(&var);
pDisp=NULL;
hr = pEnum->Next(1, &var, &lFetch);
};
hr = pEnum->Release();
return S_OK;
}
I have a piece of HTML source like this:
<FONT color=#5a6571>Beverly Mitchell</FONT> <FONT color=#5a6571>Shawnee Smith</FONT> <FONT color=#5a6571>Glenn Plummer</FONT> <NOBR>more >></NOBR>
I tried to retrieve the "color" value, like this:
MSHTML::IHTMLDocument2Ptr htmDoc1 = NULL;
SAFEARRAY *psaStrings1 = SafeArrayCreateVector(VT_VARIANT, 0, 1);
CoCreateInstance(CLSID_HTMLDocument, NULL, CLSCTX_INPROC_SERVER, IID_IHTMLDocument2, (void**) &htmDoc1);
VARIANT *param1 = NULL;
HRESULT hr = SafeArrayAccessData(psaStrings1, (LPVOID*)¶m1);
param1->vt = VT_BSTR;
param1->bstrVal = SysAllocString(varSrc1.bstrVal);
hr = SafeArrayUnaccessData(psaStrings1);
hr = htmDoc1->write(psaStrings1);
MSHTML::IHTMLElementPtr pElemBody1 = NULL;
MSHTML::IHTMLDOMNodePtr pHTMLBodyDOMNode1 =NULL;
hr = htmDoc1->get_body(&pElemBody1);
if(SUCCEEDED(hr))
{
hr = pElemBody1->QueryInterface(IID_IHTMLDOMNode,(void**)&pHTMLBodyDOMNode1);
if(SUCCEEDED(hr))
{
ProcessDomNodeSmartWrapper(pHTMLBodyDOMNode1, ProcTgtTagStrVec);
}
}
long lLength = 0;
MSHTML::IHTMLElementCollectionPtr pElemColl1 = NULL;
MSHTML::IHTMLElementPtr pChElem1 = NULL;
MSHTML::IHTMLStylePtr pStyle1 = NULL;
IDispatchPtr ppvdisp1 = NULL;
hr = htmDoc1->get_all(&pElemColl1);
hr = pElemColl1->get_length(&lLength);
for(long i = 0; i < lLength; i++)
{
_variant_t name(i);
_variant_t index(i);
ppvdisp1 = pElemColl1->item(name, index);
if(ppvdisp1 && SUCCEEDED(hr))
{
hr = ppvdisp1->QueryInterface(IID_IHTMLElement, (void **)&pChElem1);
if(pChElem1 && SUCCEEDED(hr))
{
BSTR bstrTagName = NULL;
pChElem1->get_tagName(&bstrTagName);
hr = pChElem1->get_style(&pStyle1);
if(pStyle1 && SUCCEEDED(hr))
{
_variant_t varFtCol;
hr = pStyle1->get_color(&varFtCol);
if(hr = S_OK && varFtCol)
{
hmStyles1[wstring(varFtCol.bstrVal)] = L"FontColor";
}
}
if(bstrTagName)
SysFreeString(bstrTagName);
} // if pStyle && SUCCEEDED(hr)
}//if ppvdisp && SUCCEEDED(hr)
}//for
But I can never get the "color" value - varFtCol.bstrVal is a bad pointer when I debug the program. This is what varFtCol showed when I debug the program:
- varFtCol {???} _variant_t
- tagVARIANT BSTR = 0x00000000 tagVARIANT
vt 8 unsigned short
- BSTR 0x00000000 wchar_t *
CXX0030: Error: expression cannot be evaluated
#5a6571 is a hex color represents for RGB value of (90,101,113).
How can I get this color info?
You shouldn't be getting style on pChElem1 because the color is not part of style in your case. Color is part of Font element.
Instead you must call pChElem1->getAttribute("color" . . .)
This will return #5a6571
The following code is in MFC. But you can easily convert to regular Win32 if you are not using MFC.
COLORREF GetColorFromHexString( CString szColor )
{
TCHAR *szScan;
CString strTemp;
CString strColor = szColor;
long lRR = 0,lGG = 0,lBB = 0;
//first we will remove # characters which come from XML document
strColor.TrimLeft(_T('#'));
strColor.TrimRight(_T('#'));
//it should be of the form RRGGBB
if (strColor.GetLength() == 6) {
//get red color, from the hexadecimal string
strTemp = strColor.Left(2);
lRR = _tcstol(LPCTSTR(strTemp),&szScan,16);
//get green color
strTemp = strColor.Mid(2,2);
lGG = _tcstol(LPCTSTR(strTemp),&szScan,16);
//get blue color
strTemp = strColor.Right(2);
lBB = _tcstol(LPCTSTR(strTemp),&szScan,16);
}
return RGB(lRR,lGG,lBB);
}
According to the MSDN documentation, IHTMLStyle::get_color may return either a BSTR or an integer value in the variant. Have you tried assigning varFtCol into an integer value and examining that result?
const int colorValue = static_cast<int>(varFtCol);
As a recommendation, when working with _variant_t, it is usually best to use the built-in casting operators than to direct access the members of the union itself.
I built the AMCap sample under direct show in SDK. It is able to handle 2 or more web cam, how do I modify the program for me to use them simultaneously… like press one button that says ‘start capture’ and make sure that all the cameras start capturing and one button that says ‘stop capture’ to stop all the cameras. i want the frames from different cameras to be save in different files. I am new to C++ and any kind of help is appreciated ! Thanks for your time!
Use GraphEdit tool. There you can build you own graph with all video input devices connected. Please see http://en.wikipedia.org/wiki/GraphEdit
If you're just starting out with DirectShow programming, this might be a bit of a hill climb, but I hope it's of some help, or points you in the right direction.
M$DN has a page describing how to select a capture device. It's a little thin on examples, so I've provided a simple implementation below.
The theory is that you need to enumerate all devices in the CLSID_VideoInputDeviceCategory, and attempt to create a render graph for each valid item in the category.
First I'll show you the code to iterate the names of the devices in the category. Below are 3 static functions you can use to iterate the devices in a category. Once you've added these functions to your project, you can list the devices in the Video Input Device category by calling the following function:
ListDevicesInCategory(CLSID_VideoInputDeviceCategory);
Okay, here are the three functions. ListDevicesInCategory() is where the work happens. It depends on other two functions, FindDeviceInCategory() and CountDevicesInCategory()
#define RFAIL(x) { HRESULT hr = x; if(FAILED(hr)) {return hr;} }
static HRESULT FindDeviceInCategory(IBaseFilter** pSrc, const IID& cls, wstring& wFilterName,int devNum)
{
CComPtr<ICreateDevEnum> spDevEnum;
CComPtr<IEnumMoniker> spEnum;
int i;
RFAIL( spDevEnum.CoCreateInstance(CLSID_SystemDeviceEnum) );
RFAIL( spDevEnum->CreateClassEnumerator(cls, &spEnum, 0) );
if(spEnum == 0)
return E_FAIL;
for(i = 0; i >= 0; i++)
{
CComPtr<IMoniker> spiMoniker;
if( spEnum->Next(1, &spiMoniker, 0) != S_OK )
return E_FAIL;
if( devNum == i)
{
CComVariant varName;
CComPtr<IPropertyBag> spiPropBag;
RFAIL(spiMoniker->BindToStorage(0, 0, IID_IPropertyBag,reinterpret_cast<void**>(&spiPropBag)));
RFAIL(spiPropBag->Read(L"FriendlyName", &varName, 0));
RFAIL(spiMoniker->BindToObject(0, 0, IID_IBaseFilter, reinterpret_cast<void**>(pSrc)));
wFilterName = V_BSTR(&varName);
varName.Clear();
return S_OK;
}
}
return E_FAIL;
}
static HRESULT CountDevicesInCategory( int *pCount, const IID& categoryClass )
{
// pass in a category class like CLSID_VideoInputDeviceCategory, writes the count of the number of filters in that category
// available on the local machine
HRESULT hr = S_OK;
CComPtr<ICreateDevEnum> spIDevEnum;
CComPtr<IEnumMoniker> spIEnum;
CComPtr<IMoniker> spIMoniker;
hr = CoCreateInstance(CLSID_SystemDeviceEnum, 0, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, reinterpret_cast<void**>(&spIDevEnum));
if( ! SUCCEEDED(hr) || hr == S_FALSE )
{
*pCount = 0;
return hr;
}
hr = spIDevEnum->CreateClassEnumerator( categoryClass, &spIEnum, 0 );
if( ! SUCCEEDED(hr) || hr == S_FALSE )
{
*pCount = 0;
return hr;
}
if( spIEnum )
{
while( spIEnum->Next(1, &spIMoniker, 0) == S_OK )
{
(*pCount) ++;
spIMoniker.Detach();
}
}
return S_OK;
}
static HRESULT ListDevicesInCategory( const GUID & cls )
{
CComPtr<IBaseFilter> spSource;
wstring * psNextFilter = NULL;
int nDeviceNum = 0;
int nTotalNumDevices = 0;
HRESULT hr = S_OK;
bool bComplete = false;
DeviceNames CaptureDeviceNames;
if( FAILED(CountDevicesInCategory( &nTotalNumDevices, (IID)cls )) )
bComplete = TRUE;
if( nTotalNumDevices == 0 )
bComplete = TRUE;
while( ! bComplete )
{
psNextFilter = new std::wstring;
hr = FindDeviceInCategory( &spSource, (IID)cls, *psNextFilter, nDeviceNum++ );
if( SUCCEEDED(hr) && spSource )
{
if ( *psNextFilter )
{
wcout << *psNextFilter << endl;
delete *psNextFilter;
psNextFilter = NULL;
}
spSource.Release();
spSource = NULL;
}
else
bComplete = TRUE;
}
return S_OK;
}
Once you've identified an item in a category that you're interested in, you can add it to a graph with the IGraphBuilder::AddFilter call.
To add a filter to your graph, you'll first need to get an IBaseFilter* to that filter. I've got one more function for you to do this with.
Define an IBaseFilter smart pointer:
CComPtr<IBaseFilter> spSource;
Attach to the filter:
m_spSource.Attach(
GetFilter(CLSID_VideoInputDeviceCategory, CComBSTR(L"Osprey-450e Video Device 1A"))
);
Here's that last function - GetFilter:
static IBaseFilter * GetFilter( REFCLSID clsidDeviceClass, CComBSTR & sName )
{
HRESULT hr;
IBaseFilter * pRetFilter = NULL;
ICreateDevEnum * pSysDevEnum = NULL;
IEnumMoniker * pEnum = NULL;
IMoniker * pMoniker = NULL;
int nSameSrcCounter = 0;
hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, (void**)&pSysDevEnum);
if( pSysDevEnum )
hr = pSysDevEnum->CreateClassEnumerator(clsidDeviceClass, &pEnum, 0);
if (hr != S_OK)
return NULL;
USES_CONVERSION;
while ( pEnum->Next(1, &pMoniker, NULL) == S_OK )
{
IPropertyBag *pPropBag = NULL;
VARIANT var;
VariantInit(&var);
pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (void **)&pPropBag);
hr = pPropBag->Read(L"FriendlyName", &var, 0);
if (SUCCEEDED(hr))
{
if(sName == OLE2T(var.bstrVal))
{
hr = pMoniker->BindToObject(NULL, NULL, IID_IBaseFilter, (void**)&pRetFilter);
if (FAILED(hr))
pRetFilter = NULL;
VariantClear(&var);
pPropBag->Release();
pMoniker->Release();
break;
}
}
VariantClear(&var);
pPropBag->Release();
pMoniker->Release();
}
pSysDevEnum->Release();
pEnum->Release();
return pRetFilter;
}