 |
|
 |
First off, let me say this is a really nifty app - I like it a lot.
I want to put something similar into a VB.NET (VB 2008 Express) app that I'm building for internal use. I've gotten almost everything from this to work. The one place I'm having trouble is figuring out how you assign the images to the different nodes. I see the code for selecting an image based on the object type, but where does it get the source images?
Please bear with me if this is an obvious question, but I'm new to forms programming and don't have listview/treeview controls nailed yet. Add to that I don't know C# at all - that's why I'm building in VB not C#.
Thanks for your help, and for a great app!
David
|
|
|
|
 |
|
 |
Ok, this is actually quite simple. The enum AdImages refers to indexes in the ImageListimageList_adObjects. Basically AdRoot=0 which is the first image in the image
list. Then depending on the object category/SchemaClassName I put a specific image.
|
|
|
|
 |
|
 |
Thanks for the quick response, particularly when the original post was so long ago!
I was able to follow the enum AdImages/assign by object category logic. What I don't see is how/where you're populating imageList_adObjects. I'm using Visual C# 2008 to view the project - I don't know if maybe in the conversion process it hid something from me?
|
|
|
|
 |
|
 |
Doh! Just figured it out. Tunnel vision is a terrible thing - just found the imagelist control in the bottom of the designer window. I think I've got it now. Thanks for your help!
David
|
|
|
|
 |
|
 |
That was exactly the right way!
|
|
|
|
 |
|
 |
Hi
Thanks for your wonderful tool. can i display the attributes/properties of users like fullName,title,email address? if it so please uid me.
Thanks & Regards
R.Palanivel
R.Palanivel 10:01 4 Jan '06
|
|
|
|
 |
|
 |
It is quite simple to do that.
Do you want to display user attributes on the right side when you select a user?
|
|
|
|
 |
|
 |
Thanks for your reply Sven So. Yes i need to display user properties[attributes] in the format of tree stucture.
R.Palanivel 10:01 4 Jan '06
|
|
|
|
 |
|
|
 |
 | Bitmaps  |  | Bruce Cutler | 11:35 16 Dec '03 |
|
 |
Where did you get your bitmaps for the objects? Did you create them yourself? I'm creating a browser for my application and want to use the standard AD icons for the objects.
Bruce Cutler
|
|
|
|
 |
|
 |
Hey,
just download the freeware program resourse hacker from:
http://www.users.on.net/johnson/resourcehacker/
Then you can extract icons (save as ico files) from dll's and exe files like explorer.exe, iexplore.exe and others. After that you can just import the ico files into your imagelist within Visual Studio and use them in your project.
Good luck , Sven
|
|
|
|
 |
|
 |
stotti_no1 wrote:
After that you can just import the ico files into your imagelist within Visual Studio and use them in your project.
And get sued for copyright violation...
Maybe you did not realize it, but Windows (and the rest of the MS programs) is not Open Source. This means you can NOT just use any icon/graphic from Windows you like.
Leon[^] - Enterprise Anti-Spam Server
|
|
|
|
 |
|
 |
Of course if you sell the product, than you are really stupid. But if you use it inhouse or for your personal development I dont see it as such a big issue.
We actually have quite good contact to Microsoft and I developed a rich management interface that uses the Browser functionality and Microsoft icons and they really like it. Basically its build with Microsoft Technology, why shouldnt they like it.
Thanks for your important comment anyway. Of course its valid.
Sven
|
|
|
|
 |
|
 |
I am trying to get all machines in my active directory, but if I supply rootDSE in the binding, I only get machines from the domain that I am logged in to. Here is my set up:
we have DOMAIN, which I am logged in to, then we have DOMAIN.SUBDOMAIN. With rootDSE, I can only get machines in DOMAIN. I can get the machines form DOMAIN.SUBDOMAIN if I specify SUBDOMAIN in the binding (LDAP://SUBDOMAIN).
Any suggestions on how I would get machines from both the Domain and the subdomain?
Thanks
Steve
|
|
|
|
 |
|
|
 |
|
 |
Lets try to keep this professional here, ok?
GEEZ.. can we ban Scatter? SSD rocks though!;P
|
|
|
|
 |
|
 |
You mean instead of having one topNode in the TreeView, you want to have severals.. He should probably by default find out, if there are any child domains. Shouldnt be any problem to implement. I can take a look if you want.
Sven
|
|
|
|
 |
|
 |
I haven't been able to figure out how to do it with the DirectoryServices namespace so I decided to go down and dirty and get it using WinAPIs, I did not place any error handling on this so you will have to do this. Also if you need more info on return values I included a few links on the remarks and comments to help you out. This should be able to return all of the Domain Names in LDAP Format (e.g. dc=domain,dc=ext) for all domains registered in your Global Catalog Server, Also since I'm repeating the process for every site you might need to look for duplicated entries in the DomainNames string array. Good Luck <------ Code Begin ------> using System; using System.Security.Permissions; using System.Runtime.InteropServices; namespace UserCreatorAD { /// <summary> /// Summary description for ADEnumerator. /// </summary> [SecurityPermissionAttribute(SecurityAction.LinkDemand, UnmanagedCode=true)] public class ADEnumerator { /// <summary> /// WinAPI DsBind /// </summary> /// <param name="DomainController">[in] The name of the domain /// controller formated "\\name.domain.domain this should /// be left null so we can bind to the Global Catalog</param> /// <param name="DnsDomain">[in] The name of the domain you want /// to bind to this should also be left null in order /// to bind to the Global Catalog</param> /// <param name="phDS">[out] pointer to the Directory Services /// Bind Handle</param> /// <returns>Error code</returns> /// <remarks>http://msdn.microsoft.com/library/default.asp?url=/library/en-us/ad/ad/dsbind.asp</remarks> [DllImport("ntdsapi.dll")] private static extern int DsBind( string DomainController, string DnsDomain, out System.IntPtr phDS); /// <summary> /// WinAPI DsUnBind /// </summary> /// <param name="phDs">[in] The pointer to the Directory /// Services Bind Handle</param> /// <returns>Error Code</returns> /// <remarks>http://msdn.microsoft.com/library/default.asp?url=/library/en-us/ad/ad/dsunbind.asp</remarks> [DllImport("ntdsapi.dll")] private static extern int DsUnBind( System.IntPtr phDs); /// <summary> /// WinAPI DsListSites /// </summary> /// <param name="hDS">[in] Pointer to the Directory /// Services Bind handle</param> /// <param name="ppSites">[out] pointer to a structure /// of type DsNameResult which contains an array of /// DsNameResultItem structures with the LDAP names /// of the sites in the Global Catalog.</param> /// <returns>Error Code</returns> /// <remarks>http://msdn.microsoft.com/library/default.asp?url=/library/en-us/ad/ad/dslistserversinsite.asp</remarks> [DllImport("ntdsapi.dll")] private static extern int DsListSites( System.IntPtr hDS, out System.IntPtr ppSites); /// <summary> /// WinAPI DsListDomainsInSite /// </summary> /// <param name="hDS">[in] Pointer to Directory /// Services Bind Handle.</param> /// <param name="sSite">The name of the site aquired /// from DsListSites WinAPI</param> /// <param name="ppDomains">pointer to the handle of /// a structure of type DsNameResult</param> /// <returns>Error Code</returns> /// <remarks>http://msdn.microsoft.com/library/default.asp?url=/library/en-us/ad/ad/dslistdomainsinsite.asp</remarks> [DllImport("ntdsapi.dll")] private static extern int DsListDomainsInSite( System.IntPtr hDS, string sSite, out System.IntPtr ppDomains); /// <summary> /// WinAPI DsFreeNameResult /// </summary> /// <param name="pResult">[in] The Pointer to the /// DsNameResult structure to be freed from /// memory</param> [DllImport("ntdsapi.dll")] private static extern void DsFreeNameResult( System.IntPtr pResult); /// <summary> /// The pointer to the Directory Service bind handle. /// </summary> private System.IntPtr DSBindHandle; private Error thisLastError; public ADEnumerator() { } /// <summary> /// Finds the domain names /// in LDAP format for all /// the domains in the global /// catalog server /// </summary> /// <param name="DomainNames">[out] An array /// of strings containing the domain names</param> /// <returns>true for success false for failure.</returns> public bool FindDomains(out string[] DomainNames) { //For Error handling. int MyError; //Pointer to the DsNameResult structure for the sites. System.IntPtr pSites = IntPtr.Zero; //Pointer to the DsNameResult structure for the Domains. System.IntPtr pDomains = IntPtr.Zero; //The structure which will hold the name of the sites. DsNameResult rSites; //The structure which will hold the name of the domains. DsNameResult rDomains; //Lets bind the program to the GCS. //and find the sites it contains. MyError = DsBind(null,null,out DSBindHandle); DsListSites(DSBindHandle, out pSites); //Now we marshal the pointer to the DsNameResult Structure. rSites = (DsNameResult) Marshal.PtrToStructure( pSites, typeof(DsNameResult)); //Lets fin how many sites are there and point //to the first Item in the Array. int ItemCount = rSites.cItems; System.IntPtr pItems = rSites.rItems; //This varibles will hold the names of the sites. DsNameResultItem rItem; string[] SiteNames = new string[ItemCount]; //Now we loop through all of the items in the array //and save their names. for(int i = 0; i < ItemCount; i++) { //Again we marshal the pointer //but this time to the DsNameResultItem //Structure so we can read the names //of the sites. rItem = (DsNameResultItem) Marshal.PtrToStructure( pItems, typeof(DsNameResultItem)); //we save the name in our own array. SiteNames[i] = rItem.pName; //we find the size of the object. int SizeOfItem = Marshal.SizeOf(rItem); //And now we add the size to the existing pointer //so we can move to the next structure in the //unmanaged Array. pItems = (System.IntPtr)((int)pItems + SizeOfItem); } //since we don't know how many domains are in each site //it is easier for us to use an ArrayList object to //store those since we can add items dynamically to it. System.Collections.ArrayList sDN = new System.Collections.ArrayList(); //Now we loop through all of the sites and find //the domains that are in it. //The entire process is almost the same as the sites //so I'm not going to bother commenting it all, //but we have a loop within a loop to find all domains. foreach(string thisSite in SiteNames) { MyError = DsListDomainsInSite(DSBindHandle,thisSite,out pDomains); rDomains = (DsNameResult)Marshal.PtrToStructure(pDomains,typeof(DsNameResult)); pItems = rDomains.rItems; for(int i = 0; i < rDomains.cItems; i++) { rItem = (DsNameResultItem)Marshal.PtrToStructure(pItems,typeof(DsNameResultItem)); sDN.Add(rItem.pName); int SizeOfItem = Marshal.SizeOf(rItem); pItems = (System.IntPtr)((int)pItems + SizeOfItem); } //Since we don't need the unmanaged structure //anymore we free that memory. DsFreeNameResult(pDomains); } //And now that we don't need the sites anymore either //we free that memory as well. DsFreeNameResult(pSites); //Unbind the program from the GC. DsUnBind(DSBindHandle); //Save the anems in the out array. DomainNames = new string[sDN.Count]; for(int i = 0; i < sDN.Count; i++) { DomainNames[i] = (string)sDN[i]; } //and we are done. return true; } public Error LastError { get{return thisLastError;} } } public struct Error { public int ErrNumber; public string ErrMsg; } /// <summary> /// Created to mimic the unmanaged structure /// DS_NAME_RESULT_ITEM. /// </summary> [StructLayout(LayoutKind.Sequential)] public struct DsNameResultItem { public int status; public string pDomain; public string pName; } /// <summary> /// Created to mimic the unmanged structure /// DS_NAME_RESULT. /// </summary> [StructLayout(LayoutKind.Sequential)] public struct DsNameResult { public int cItems; public System.IntPtr rItems; } } <------ Code End ------>
|
|
|
|
 |
|
 |
Program quits (with error) when sorting columns that have blank entries.
Joseph
|
|
|
|
 |
|
 |
Hey Joseph,
I know what the problem is. Need to find some time to fix it. Give me until next week.
|
|
|
|
 |
|
 |
This still doesn't seem to be working.
Joseph
|
|
|
|
 |
|
 |
We use AD not LDAP, so If I replace your LDAP:// with WinNT:// it should ideally work fine. However I am having problems resolving the proerty defaultNamingContext in WinNT. Any suggesstions? Also, I am putting in a known domain name should I be entering the forrest name instead?
Thanks. dom
|
|
|
|
 |
|
 |
If you use AD (Active Directory) than it should just work fine, because its made for it. ADSI (Active Directory Services Interface) supports 2 providers one is LDAP, which you could also use to connect to other LDAP directories (Active Directory is also an LDAP directory). Winnt is mainly used to connect to NT4 domains, but can still be used to access Active Directory for backwards compatibility. In your case Winnnt doesnt has such property defaultNamingContext. If your computer is in Active Directory and you are logged on with a user from AD my example should just work fine. With the call to the rootDSE he will get information about your AD domain, and then in the second call connect to AD with defaultNamingContext, e.g. "dc=test,dc=com". Just try the example without changing anything. Please come back, if it still doesnt work for you.
|
|
|
|
 |
|
 |
Thanks. I guess it has to be on a machine that is in the directory... even when I supply it a domain, username and password. Thanks for the help. I noticed a bug in your app though... If you highlight one node, then go to another, then go back to the orignal, you get duplicate child nodes.
Thanks,
Dom
|
|
|
|
 |
|
 |
Yes I see the bug now. Small thing. In the AfterSelect method I just added a e.Node.Nodes.Clear(); Its a simple workaround, in a real application, you would not want to reload the stuff all the time. You want to refresh by F5 or a context menu. Could be added later. Thanks for your findings.
Sven
|
|
|
|
 |