in C# project I'd like to get a picture from a WPD camera device via
drag&drop. I can transfer normal objects via WPD API from the WPD device
without any problems. But if I use drag&drop there is something missing.
Checking the Clipboard Data with ClipSpy I can see:
WPD NSE
WPD NSE PnPDevicePath
WPD NSE StoragePUID
With the WPD NSE data I can access the camera device and the storage object.
But how can I access the dragged picture or object?
There is also the "Shell IDList Array" which seems to contain the
WPD_OBJECT_PERSISTENT_UNIQUE_ID, but how can I interprete the "Shell IDList
Array"?
Thanks
You are dragging from the device to your application?
What is the complete list of clipboard formats you see?
The Shell IDList Array is a list of IDs that identify the shell items
being dragged.
The structure is documented here:
http://msdn.microsoft.com/en-us/library/bb776902.aspx
http://msdn.microsoft.com/en-us/library/bb773212(VS.85).aspx
But ideally you will use something like:
SHCreateShellItemArrayFromDataObject
...to get the Shell Items and query them for the IStream - or their
IDataObject which may contain the desired image resource.
bjarke
Yes I'm dragging from the device to my application.
Clipspy reports the following formats:
Shell IDList Array
FileContents <Data unavailable>
FileGroupDescriptorW
WPD Storage Attributes
Preferred DropEffect
WPD NSE
WPD NSE PnPDevicePath
WPD NSE StoragePUID
Shell Object Offsets
UsingDefaultDragImage
DragImageBits
DragContext
InShellDragLoop
Yes I think using SHCreateShellItemArrayFromDataObject would be great, but
there is no corresponding C# version available, I already googled. My interop
knowledge is not that good, I already tried with the following:
[DllImport("shell32.dll", CharSet = CharSet.Unicode, SetLastError =
true)]
internal static extern int SHCreateShellItemArrayFromDataObject(
System.Runtime.InteropServices.ComTypes.IDataObject pdo,
ref Guid riid,
[MarshalAs(UnmanagedType.Interface)] out IShellItemArray ppv);
by calling with
var mydata = data as
System.Runtime.InteropServices.ComTypes.IDataObject;
ShellHelper.IShellItemArray nativeShellItemArray;
retCode =
ShellHelper.SHCreateShellItemArrayFromDataObject(mydata, ref guid, out
nativeShellItemArray);
But it doesen't work, the return HResult codes says no interface:
E_NOINTERFACE = 0x80004002,
Maybe the defintion of nativeShellItemArray is wrong:
[ComImport,
Guid(ShellIIDGuid.IShellItemArray),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IShellItemArray
{
// Not supported: IBindCtx.
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType =
MethodCodeType.Runtime)]
void BindToHandler(
[In, MarshalAs(UnmanagedType.Interface)] IntPtr pbc,
[In] ref Guid rbhid,
[In] ref Guid riid,
out IntPtr ppvOut);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType =
MethodCodeType.Runtime)]
void GetPropertyStore(
[In] int Flags,
[In] ref Guid riid,
out IntPtr ppv);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType =
MethodCodeType.Runtime)]
void GetPropertyDescriptionList(
[In] ref PropertyKey keyType,
[In] ref Guid riid,
out IntPtr ppv);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType =
MethodCodeType.Runtime)]
void GetAttributes(
[In] SIATTRIBFLAGS dwAttribFlags,
[In] SFGAO sfgaoMask,
out SFGAO psfgaoAttribs);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType =
MethodCodeType.Runtime)]
void GetCount(out uint pdwNumItems);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType =
MethodCodeType.Runtime)]
void GetItemAt(
[In] uint dwIndex,
[MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi);
// Not supported: IEnumShellItems (will use GetCount and
GetItemAt instead).
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType =
MethodCodeType.Runtime)]
void EnumItems([MarshalAs(UnmanagedType.Interface)] out IntPtr
ppenumShellItems);
}
As I said I'm no expert in Interop. The above code I wrote after looking at
the windows api codepack from:
http://code.msdn.microsoft.com/WindowsAPICodePack
Mike
"bviksoe" wrote:
> ....to get the Shell Items and query them for the IStream - or their
Part of the code:
var mydata = data as
System.Runtime.InteropServices.ComTypes.IDataObject;
ShellHelper.IShellItemArray nativeShellItemArray;
guid = new Guid(ShellIIDGuid.IShellItemArray);
retCode =
ShellHelper.SHCreateShellItemArrayFromDataObject(mydata, ref guid, out
nativeShellItemArray);
ShellHelper.IShellItem2 nativeShellItem;
if (CoreErrorHelper.Succeeded(retCode))
{
string displayname;
uint items = 0;
nativeShellItemArray.GetCount(out items);
if (items > 0)
{
for (uint item = 0; item < items; item++)
{
nativeShellItemArray.GetItemAt(item, out
nativeShellItem);
nativeShellItem.GetDisplayName(ShellHelper.SIGDN.SIGDN_DESKTOPABSOLUTEPARSING, out displayname);
Console.WriteLine("Parsingname: {0}",
displayname);
}
}
}
Using SHCreateShellItemArrayFromDataObject makes using the CIDA structure
obsolete and is much more clear.
Mike
These are the ones you want. That way you can avoid the dependency on SHCreateShellItemArrayFromDataObject, which is not available on pre-Vista systems, and you can support a wider variety of drag-drop sources (e.g. Zip Folders).
CFSTR_FILECONTENTS and CFSTR_FILEDESCRIPTOR are described in the topic Bjarke linked to before:
http://msdn.microsoft.com/en-us/library/bb776902.aspx
--
Jim Barry, Microsoft MVP