E_NOTIMPL in GetData method when querying objectSID from Directory Object Picker
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];
}
}
Date:Tue, 7 Aug 2007 11:13:40 +0200
Author:
|
Re: E_NOTIMPL in GetData method when querying objectSID from Directory Object Picker
.... 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
Date:Mon, 20 Aug 2007 15:31:27 +0200
Author:
|