Hi, I'm trying to get the objectSID from the active directory objects selected in the directory object picker dialog. But IDataObject.GetData() returns always 0x80004001 (E_NOTIMPL) when I supply the attribute 'objectSID' in DSOP_INIT_INFO. Without this attribute (cAttributesToFetch=0), the code works. I also have a sample using the same flags and settings written in Delphi that works fine. So I suppose the marshalling is incorrect, but I don't know where. Below is an excerpt of my code. Thanks very much for any help. Beat [ComImport, Guid("17D6CCD8-3B7B-11D2-B9E0-00C04FD8DBF7")] public class DSObjectPicker {} [ComImport, Guid("0C87E64E-3B7A-11D2-B9E0-00C04FD8DBF7"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] public interface IDsObjectPicker { void Initialize(ref DSOP_INIT_INFO pInitInfo); void InvokeDialog(IntPtr HWND, out IDataObject lpDataObject); } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] public struct DSOP_INIT_INFO { public uint cbSize; [MarshalAs(UnmanagedType.LPWStr)] public string pwzTargetComputer; public uint cDsScopeInfos; public IntPtr aDsScopeInfos; public uint flOptions; public uint cAttributesToFetch; public IntPtr apwzAttributeNames; } // other structs, enums, ... (skipped) public class ObjectPickerWrapper { public ADObject[] ShowObjectPicker(IntPtr parentHandle) { DSObjectPicker picker = new DSObjectPicker(); IDsObjectPicker ipicker = (IDsObjectPicker)picker; DSOP_SCOPE_INIT_INFO[] scopeInitInfo = new DSOP_SCOPE_INIT_INFO[1]; scopeInitInfo[0].cbSize = (uint)Marshal.SizeOf(typeof(DSOP_SCOPE_INIT_INFO)); scopeInitInfo[0].flType = DSOP_SCOPE_TYPE_FLAGS.DSOP_SCOPE_TYPE_GLOBAL_CATALOG; scopeInitInfo[0].FilterFlags.Uplevel.flBothModes = DSOP_FILTER_FLAGS_FLAGS.DSOP_FILTER_USERS; // ... scopeInitInfo[0].FilterFlags.flDownlevel = DSOP_DOWNLEVEL_FLAGS.DSOP_DOWNLEVEL_FILTER_USERS; // ... scopeInitInfo[0].pwzADsPath = null; scopeInitInfo[0].pwzDcName = null; scopeInitInfo[0].hr = 0; IntPtr refScopeInitInfo = Marshal.AllocHGlobal( Marshal.SizeOf(typeof(DSOP_SCOPE_INIT_INFO)) * scopeInitInfo.Length); Marshal.StructureToPtr(scopeInitInfo[0], refScopeInitInfo, true); DSOP_INIT_INFO initInfo = new DSOP_INIT_INFO(); initInfo.pwzTargetComputer = null; initInfo.flOptions = DSOP_INIT_INFO_FLAGS.DSOP_FLAG_MULTISELECT; initInfo.cDsScopeInfos = 1; initInfo.aDsScopeInfos = refScopeInitInfo; string attrName = "objectSID"; IntPtr refAttrName = Marshal.StringToHGlobalUni(attrName); initInfo.cAttributesToFetch = 1; initInfo.apwzAttributeNames = refAttrName; // <== marshalling / memory layout ok?? ipicker.Initialize(ref initInfo); // show the dialog IDataObject dataObj = null; ipicker.InvokeDialog(parentHandle, out dataObj); FORMATETC fmt = new FORMATETC(); fmt.cfFormat = (short)System.Windows.Forms.DataFormats.GetFormat("CFSTR_DSOP_DS_SELECTION_LIST").Id; // -15497 (unsigned 50039) fmt.ptd = IntPtr.Zero; fmt.dwAspect = DVASPECT.DVASPECT_CONTENT; fmt.lindex = -1; fmt.tymed = TYMED.TYMED_HGLOBAL; STGMEDIUM stg = new STGMEDIUM(); // int res = dataObj.QueryGetData(ref fmt); // <== HRESULT is always 0x80004001 (E_NOTIMPL) dataObj.GetData(ref fmt, out stg); // throws 'not implemented' Exception from HRESULT 0x80004001 (E_NOTIMPL) // ... processing stg... (skipped) return new ADObject[0]; } }
.... the marshalling of the string array was incorrect. It can be done like this: public sealed class packLPArray { private IntPtr taskAlloc; private readonly int _length; private IntPtr[] _strings; public packLPArray(string[] theArray) { int sizeIntPtr = IntPtr.Size; int neededSize = 0; if (theArray != null) { this._length = theArray.Length; this._strings = new IntPtr[this._length]; neededSize = this._length * sizeIntPtr; this.taskAlloc = Marshal.AllocCoTaskMem(neededSize); for (int cx = this._length - 1; cx >= 0; cx--) { this._strings[cx] = Marshal.StringToCoTaskMemUni(theArray[cx]); Marshal.WriteIntPtr(this.taskAlloc, cx * sizeIntPtr, this._strings[cx]); } } } public IntPtr arrayPtr { get { return this.taskAlloc; } } ~packLPArray() { if (taskAlloc != IntPtr.Zero) { Marshal.FreeCoTaskMem(this.taskAlloc); int cx = this._length; while(cx-- != 0) Marshal.FreeCoTaskMem(this._strings[cx]); } } } .... packLPArray packit = new packLPArray( new string[] {"SamAccountName","cn","Adspath","objectsid"}); initInfo.cAttributesToFetch = 4; initInfo.apwzAttributeNames = packit.arrayPtr; .... Beat
Don't see what you're looking for? Try a search.
|