Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Getting Path from a Shell IDList Array in C#

1,165 views
Skip to first unread message

dzMike

unread,
Dec 7, 2007, 4:24:01 AM12/7/07
to
Hi

I've scoured the internet for help with this and found no solution. I've got
a program that allows folders to be dragged and dropped onto a list. The path
of the folder(s) is then added to the list. Very simple, yes I know. I use
the standard c# filedrop format for this purpose.

However this doesn't work with virtual folders, obviously the dragdrop
format is instead Shell IDList Array. I've tried this guy's code:

http://www.tech-archive.net/Archive/DotNet/microsoft.public.dotnet.framework.interop/2006-01/msg00041.html

but, like Jason, I can't figure out how to get the paths from the CIDA. I've
tried using SHGetPathFromIDList but I must be doing something wrong as it
either crashes my application or does nothing.

Any help would be massively appreciated,

Thanks All, have a nice day

Jim Barry

unread,
Dec 7, 2007, 7:32:44 AM12/7/07
to
dzMike wrote:
> I can't figure out how to get the paths from the CIDA.

The CIDA structure is adequately documented here:

http://msdn2.microsoft.com/en-us/library/bb773212.aspx

If it contains non-filesystem items then obviously SHGetPathFromIDList will fail for those items.

--
Jim Barry, MVP (Windows SDK)

dzMike

unread,
Dec 7, 2007, 9:13:01 AM12/7/07
to
Jim

Many thanks for this link. I will read, experiment, and post a code snippet
here when done in case anyone else is searching for this.

Thanks again

Mike

dzMike

unread,
Dec 7, 2007, 10:56:03 AM12/7/07
to
Jim

Thanks again for your help. I have declared the CIDA thusly:

[StructLayout(LayoutKind.Sequential)]
public struct CIDA
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
public uint[] aoffset;
}


Then I'm using the following code to get the PIDL of the parent folder (e is
a dragdrop event args):

MemoryStream data = (MemoryStream)e.Data.GetData("Shell IDList Array");
byte[] b = data.ToArray();
IntPtr p = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(CIDA)));
Marshal.Copy(b, 0, p, b.Length);
CIDA cida = (CIDA)Marshal.PtrToStructure(p, typeof(CIDA));

//p is the pointer to the cida
IntPtr parentpidl = (IntPtr)((int)p + cida.aoffset[0]);
string item;
SHGetPathFromIDList((int)parentpidl, out item);

item is always coming back as null. I assume this means the parent folder is
the desktop since I am dragging 'My Documents' from the desktop. However, I
can't figure out how to access the next PIDL in the array, since the size is
constant. I've tried this:

IntPtr parentpidl = (IntPtr)((int)p + cida.aoffset[0] + sizeof(uint));

but this throws an execution engine error. What am I doing wrong?

Thanks for your time,

Mike

Jim Barry

unread,
Dec 10, 2007, 11:20:25 AM12/10/07
to
dzMike wrote:
> I have declared the CIDA thusly:
>
> [StructLayout(LayoutKind.Sequential)]
> public struct CIDA
> {
> [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
> public uint[] aoffset;
> }

This approach isn't going to work because .NET interop doesn't support variable length arrays in structures. Basically you need to grovel over the raw data and pull out the offsets on by one. I'm not a C# person, but I managed to cobble together the following code:

[DllImport("shell32.dll")]
public static extern Int32 SHGetPathFromIDList(
IntPtr pidl, StringBuilder pszPath);

[DllImport("shell32.dll")]
public static extern IntPtr ILCombine(
IntPtr pidl1, IntPtr pidl2);

[DllImport("shell32.dll")]
public static extern void ILFree(
IntPtr pidl);

// Copy clipboard data into unmanaged memory.
MemoryStream data = (MemoryStream)Clipboard.GetData("Shell IDList Array");
byte[] b = data.ToArray();
IntPtr p = Marshal.AllocHGlobal(b.Length);
Marshal.Copy(b, 0, p, b.Length);

// Get number of items.
UInt32 cidl = (UInt32)Marshal.ReadInt32(p);

// Get parent folder.
int offset = sizeof(UInt32);
IntPtr parentpidl = (IntPtr)((int)p + (UInt32)Marshal.ReadInt32(p, offset));
StringBuilder path = new StringBuilder(256);
SHGetPathFromIDList(parentpidl, path);

// Get subitems.
for (int i = 1; i <= cidl; ++i)
{
offset += sizeof(UInt32);
IntPtr relpidl = (IntPtr)((int)p + (UInt32)Marshal.ReadInt32(p, offset));
IntPtr abspidl = ILCombine(parentpidl, relpidl);
SHGetPathFromIDList(abspidl, path);
ILFree(abspidl);

dzMike

unread,
Dec 10, 2007, 11:53:01 AM12/10/07
to
Truly excellent cobbling, Jim :). Thank you very much.

Mike Payne

danielstoinski

unread,
Apr 21, 2010, 5:05:25 AM4/21/10
to
Jim,

perfect explanation, best thanks. It works perfectly on W2K, probably the same for XP, Vista etc.

On Windows Mobile 6 I had to add additionally two sizes of Int32 to the offset. Eg. the parent pidl is then

int offset = 3 * sizeof(UInt32);


IntPtr parentpidl = (IntPtr)((int)p + (UInt32)Marshal.ReadInt32(p, offset));

rather than

int offset = sizeof(UInt32);
IntPtr parentpidl = (IntPtr)((int)p + (UInt32)Marshal.ReadInt32(p, offset));

Warning. SHGetPathFromIDList causes segmentation faults if called with a wrong pidl.

Best regards
Daniel Stoinski


Jim Barry wrote:

Re: Getting Path from a Shell IDList Array in C#
10-Dec-07

dzMike wrote:

This approach isn't going to work because .NET interop doesn't support =
variable length arrays in structures. Basically you need to grovel over =
the raw data and pull out the offsets on by one. I'm not a C# person, =


but I managed to cobble together the following code:

[DllImport("shell32.dll")]
public static extern Int32 SHGetPathFromIDList(
IntPtr pidl, StringBuilder pszPath);

[DllImport("shell32.dll")]
public static extern IntPtr ILCombine(
IntPtr pidl1, IntPtr pidl2);

[DllImport("shell32.dll")]
public static extern void ILFree(
IntPtr pidl);

// Copy clipboard data into unmanaged memory.

MemoryStream data =3D (MemoryStream)Clipboard.GetData("Shell IDList =
Array");
byte[] b =3D data.ToArray();
IntPtr p =3D Marshal.AllocHGlobal(b.Length);
Marshal.Copy(b, 0, p, b.Length);

// Get number of items.

UInt32 cidl =3D (UInt32)Marshal.ReadInt32(p);

// Get parent folder.
int offset =3D sizeof(UInt32);
IntPtr parentpidl =3D (IntPtr)((int)p + (UInt32)Marshal.ReadInt32(p, =
offset));
StringBuilder path =3D new StringBuilder(256);
SHGetPathFromIDList(parentpidl, path);

// Get subitems.
for (int i =3D 1; i <=3D cidl; ++i)
{
offset +=3D sizeof(UInt32);
IntPtr relpidl =3D (IntPtr)((int)p + (UInt32)Marshal.ReadInt32(p, =
offset));
IntPtr abspidl =3D ILCombine(parentpidl, relpidl);
SHGetPathFromIDList(abspidl, path);
ILFree(abspidl);
}

--=20


Jim Barry, MVP (Windows SDK)

Previous Posts In This Thread:

On Friday, December 07, 2007 4:24 AM
dzMik wrote:

Getting Path from a Shell IDList Array in C#
Hi

http://www.tech-archive.net/Archive/DotNet/microsoft.public.dotnet.framework.interop/2006-01/msg00041.html

On Friday, December 07, 2007 7:32 AM
Jim Barry wrote:

Re: Getting Path from a Shell IDList Array in C#
dzMike wrote:

The CIDA structure is adequately documented here:

http://msdn2.microsoft.com/en-us/library/bb773212.aspx

If it contains non-filesystem items then obviously SHGetPathFromIDList =


will fail for those items.

--=20


Jim Barry, MVP (Windows SDK)

On Friday, December 07, 2007 9:13 AM
dzMik wrote:

JimMany thanks for this link.
Jim

Many thanks for this link. I will read, experiment, and post a code snippet
here when done in case anyone else is searching for this.

Thanks again

Mike


"Jim Barry" wrote:

On Friday, December 07, 2007 10:56 AM
dzMik wrote:

JimThanks again for your help.
Jim

Thanks again for your help. I have declared the CIDA thusly:

[StructLayout(LayoutKind.Sequential)]
public struct CIDA
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
public uint[] aoffset;
}

Then I'm using the following code to get the PIDL of the parent folder (e is
a dragdrop event args):

MemoryStream data = (MemoryStream)e.Data.GetData("Shell IDList Array");
byte[] b = data.ToArray();


IntPtr p = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(CIDA)));
Marshal.Copy(b, 0, p, b.Length);
CIDA cida = (CIDA)Marshal.PtrToStructure(p, typeof(CIDA));

//p is the pointer to the cida
IntPtr parentpidl = (IntPtr)((int)p + cida.aoffset[0]);
string item;
SHGetPathFromIDList((int)parentpidl, out item);

item is always coming back as null. I assume this means the parent folder is
the desktop since I am dragging 'My Documents' from the desktop. However, I
can't figure out how to access the next PIDL in the array, since the size is
constant. I've tried this:

IntPtr parentpidl = (IntPtr)((int)p + cida.aoffset[0] + sizeof(uint));

but this throws an execution engine error. What am I doing wrong?

Thanks for your time,

Mike

On Monday, December 10, 2007 11:20 AM
Jim Barry wrote:

Re: Getting Path from a Shell IDList Array in C#
dzMike wrote:

This approach isn't going to work because .NET interop doesn't support =
variable length arrays in structures. Basically you need to grovel over =
the raw data and pull out the offsets on by one. I'm not a C# person, =


but I managed to cobble together the following code:

[DllImport("shell32.dll")]
public static extern Int32 SHGetPathFromIDList(
IntPtr pidl, StringBuilder pszPath);

[DllImport("shell32.dll")]
public static extern IntPtr ILCombine(
IntPtr pidl1, IntPtr pidl2);

[DllImport("shell32.dll")]
public static extern void ILFree(
IntPtr pidl);

// Copy clipboard data into unmanaged memory.

MemoryStream data =3D (MemoryStream)Clipboard.GetData("Shell IDList =
Array");
byte[] b =3D data.ToArray();
IntPtr p =3D Marshal.AllocHGlobal(b.Length);
Marshal.Copy(b, 0, p, b.Length);

// Get number of items.

UInt32 cidl =3D (UInt32)Marshal.ReadInt32(p);

// Get parent folder.
int offset =3D sizeof(UInt32);
IntPtr parentpidl =3D (IntPtr)((int)p + (UInt32)Marshal.ReadInt32(p, =
offset));
StringBuilder path =3D new StringBuilder(256);
SHGetPathFromIDList(parentpidl, path);

// Get subitems.
for (int i =3D 1; i <=3D cidl; ++i)
{
offset +=3D sizeof(UInt32);
IntPtr relpidl =3D (IntPtr)((int)p + (UInt32)Marshal.ReadInt32(p, =
offset));
IntPtr abspidl =3D ILCombine(parentpidl, relpidl);
SHGetPathFromIDList(abspidl, path);
ILFree(abspidl);
}

--=20


Jim Barry, MVP (Windows SDK)

On Monday, December 10, 2007 11:53 AM
dzMik wrote:

Re: Getting Path from a Shell IDList Array in C#


Truly excellent cobbling, Jim :). Thank you very much.

Mike Payne


"Jim Barry" wrote:

On Wednesday, April 21, 2010 5:01 AM
Daniel Stoinski wrote:

Works perfectly on desktop, remark for Windows Mobile
Jim,

perfect explanation, best thanks. It works perfectly on W2K, probably the same for XP, Vista etc.

On Windows Mobile 6 I had to add additionally two sizes of Int32 to the offset. Eg. the parent pidl is then

int offset = 3 * sizeof(UInt32);


IntPtr parentpidl = (IntPtr)((int)p + (UInt32)Marshal.ReadInt32(p, offset));

rather than

int offset = sizeof(UInt32);
IntPtr parentpidl = (IntPtr)((int)p + (UInt32)Marshal.ReadInt32(p, offset));

Warning. SHGetPathFromIDList causes segmentation faults if called with a wrong pidl.

Best regards
Daniel Stoinski

On Wednesday, April 21, 2010 5:04 AM
Daniel Stoinski wrote:

Works perfectly on desktop, remark for Windows Mobile
Jim,

perfect explanation, best thanks. It works perfectly on W2K, probably the same for XP, Vista etc.

On Windows Mobile 6 I had to add additionally two sizes of Int32 to the offset. Eg. the parent pidl is then

int offset = 3 * sizeof(UInt32);


IntPtr parentpidl = (IntPtr)((int)p + (UInt32)Marshal.ReadInt32(p, offset));

rather than

int offset = sizeof(UInt32);
IntPtr parentpidl = (IntPtr)((int)p + (UInt32)Marshal.ReadInt32(p, offset));

Warning. SHGetPathFromIDList causes segmentation faults if called with a wrong pidl.

Best regards
Daniel Stoinski


Submitted via EggHeadCafe - Software Developer Portal of Choice
Book Review: C# 4.0 In a Nutshell [O'Reilly]
http://www.eggheadcafe.com/tutorials/aspnet/6dc05c04-c7f9-40cc-a2da-88dde2e6d891/book-review-c-40-in-a.aspx

danielstoinski

unread,
Apr 21, 2010, 5:01:33 AM4/21/10
to
Jim,

perfect explanation, best thanks. It works perfectly on W2K, probably the same for XP, Vista etc.

On Windows Mobile 6 I had to add additionally two sizes of Int32 to the offset. Eg. the parent pidl is then

int offset = 3 * sizeof(UInt32);


IntPtr parentpidl = (IntPtr)((int)p + (UInt32)Marshal.ReadInt32(p, offset));

rather than

int offset = sizeof(UInt32);
IntPtr parentpidl = (IntPtr)((int)p + (UInt32)Marshal.ReadInt32(p, offset));

Warning. SHGetPathFromIDList causes segmentation faults if called with a wrong pidl.

Best regards
Daniel Stoinski

Jim Barry wrote:

Re: Getting Path from a Shell IDList Array in C#
10-Dec-07

dzMike wrote:

This approach isn't going to work because .NET interop doesn't support =
variable length arrays in structures. Basically you need to grovel over =
the raw data and pull out the offsets on by one. I'm not a C# person, =


but I managed to cobble together the following code:

[DllImport("shell32.dll")]
public static extern Int32 SHGetPathFromIDList(
IntPtr pidl, StringBuilder pszPath);

[DllImport("shell32.dll")]
public static extern IntPtr ILCombine(
IntPtr pidl1, IntPtr pidl2);

[DllImport("shell32.dll")]
public static extern void ILFree(
IntPtr pidl);

// Copy clipboard data into unmanaged memory.

MemoryStream data =3D (MemoryStream)Clipboard.GetData("Shell IDList =
Array");
byte[] b =3D data.ToArray();

IntPtr p =3D Marshal.AllocHGlobal(b.Length);
Marshal.Copy(b, 0, p, b.Length);

// Get number of items.

UInt32 cidl =3D (UInt32)Marshal.ReadInt32(p);

// Get parent folder.


int offset =3D sizeof(UInt32);
IntPtr parentpidl =3D (IntPtr)((int)p + (UInt32)Marshal.ReadInt32(p, =
offset));

StringBuilder path =3D new StringBuilder(256);
SHGetPathFromIDList(parentpidl, path);

// Get subitems.


for (int i =3D 1; i <=3D cidl; ++i)
{
offset +=3D sizeof(UInt32);
IntPtr relpidl =3D (IntPtr)((int)p + (UInt32)Marshal.ReadInt32(p, =
offset));

IntPtr abspidl =3D ILCombine(parentpidl, relpidl);
SHGetPathFromIDList(abspidl, path);
ILFree(abspidl);
}

--=20


Jim Barry, MVP (Windows SDK)

Previous Posts In This Thread:

http://www.tech-archive.net/Archive/DotNet/microsoft.public.dotnet.framework.interop/2006-01/msg00041.html

http://msdn2.microsoft.com/en-us/library/bb773212.aspx

--=20


Jim Barry, MVP (Windows SDK)

On Friday, December 07, 2007 9:13 AM
dzMik wrote:

JimMany thanks for this link.
Jim

Many thanks for this link. I will read, experiment, and post a code snippet
here when done in case anyone else is searching for this.

Thanks again

Mike


"Jim Barry" wrote:

On Friday, December 07, 2007 10:56 AM
dzMik wrote:

JimThanks again for your help.
Jim

Thanks again for your help. I have declared the CIDA thusly:

[StructLayout(LayoutKind.Sequential)]
public struct CIDA
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
public uint[] aoffset;
}

Then I'm using the following code to get the PIDL of the parent folder (e is
a dragdrop event args):

MemoryStream data = (MemoryStream)e.Data.GetData("Shell IDList Array");
byte[] b = data.ToArray();


IntPtr p = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(CIDA)));
Marshal.Copy(b, 0, p, b.Length);
CIDA cida = (CIDA)Marshal.PtrToStructure(p, typeof(CIDA));

//p is the pointer to the cida
IntPtr parentpidl = (IntPtr)((int)p + cida.aoffset[0]);
string item;
SHGetPathFromIDList((int)parentpidl, out item);

item is always coming back as null. I assume this means the parent folder is
the desktop since I am dragging 'My Documents' from the desktop. However, I
can't figure out how to access the next PIDL in the array, since the size is
constant. I've tried this:

IntPtr parentpidl = (IntPtr)((int)p + cida.aoffset[0] + sizeof(uint));

but this throws an execution engine error. What am I doing wrong?

Thanks for your time,

Mike

On Monday, December 10, 2007 11:20 AM
Jim Barry wrote:

Re: Getting Path from a Shell IDList Array in C#
dzMike wrote:

This approach isn't going to work because .NET interop doesn't support =
variable length arrays in structures. Basically you need to grovel over =
the raw data and pull out the offsets on by one. I'm not a C# person, =


but I managed to cobble together the following code:

[DllImport("shell32.dll")]
public static extern Int32 SHGetPathFromIDList(
IntPtr pidl, StringBuilder pszPath);

[DllImport("shell32.dll")]
public static extern IntPtr ILCombine(
IntPtr pidl1, IntPtr pidl2);

[DllImport("shell32.dll")]
public static extern void ILFree(
IntPtr pidl);

// Copy clipboard data into unmanaged memory.

MemoryStream data =3D (MemoryStream)Clipboard.GetData("Shell IDList =
Array");
byte[] b =3D data.ToArray();

IntPtr p =3D Marshal.AllocHGlobal(b.Length);
Marshal.Copy(b, 0, p, b.Length);

// Get number of items.

UInt32 cidl =3D (UInt32)Marshal.ReadInt32(p);

// Get parent folder.


int offset =3D sizeof(UInt32);
IntPtr parentpidl =3D (IntPtr)((int)p + (UInt32)Marshal.ReadInt32(p, =
offset));

StringBuilder path =3D new StringBuilder(256);
SHGetPathFromIDList(parentpidl, path);

// Get subitems.


for (int i =3D 1; i <=3D cidl; ++i)
{
offset +=3D sizeof(UInt32);
IntPtr relpidl =3D (IntPtr)((int)p + (UInt32)Marshal.ReadInt32(p, =
offset));

IntPtr abspidl =3D ILCombine(parentpidl, relpidl);
SHGetPathFromIDList(abspidl, path);
ILFree(abspidl);
}

--=20


Jim Barry, MVP (Windows SDK)

On Monday, December 10, 2007 11:53 AM
dzMik wrote:

Re: Getting Path from a Shell IDList Array in C#
Truly excellent cobbling, Jim :). Thank you very much.

Mike Payne


"Jim Barry" wrote:


Submitted via EggHeadCafe - Software Developer Portal of Choice

Excel 2007 Filter Tool
http://www.eggheadcafe.com/tutorials/aspnet/ae703d26-58da-423a-a2cb-1f3a46fbea8f/excel-2007-filter-tool.aspx

danielstoinski

unread,
Apr 21, 2010, 5:04:48 AM4/21/10
to
Jim,

perfect explanation, best thanks. It works perfectly on W2K, probably the same for XP, Vista etc.

On Windows Mobile 6 I had to add additionally two sizes of Int32 to the offset. Eg. the parent pidl is then

int offset = 3 * sizeof(UInt32);


IntPtr parentpidl = (IntPtr)((int)p + (UInt32)Marshal.ReadInt32(p, offset));

rather than

int offset = sizeof(UInt32);
IntPtr parentpidl = (IntPtr)((int)p + (UInt32)Marshal.ReadInt32(p, offset));

Warning. SHGetPathFromIDList causes segmentation faults if called with a wrong pidl.

Best regards
Daniel Stoinski


Jim Barry wrote:

Re: Getting Path from a Shell IDList Array in C#
10-Dec-07

dzMike wrote:

This approach isn't going to work because .NET interop doesn't support =
variable length arrays in structures. Basically you need to grovel over =
the raw data and pull out the offsets on by one. I'm not a C# person, =


but I managed to cobble together the following code:

[DllImport("shell32.dll")]
public static extern Int32 SHGetPathFromIDList(
IntPtr pidl, StringBuilder pszPath);

[DllImport("shell32.dll")]
public static extern IntPtr ILCombine(
IntPtr pidl1, IntPtr pidl2);

[DllImport("shell32.dll")]
public static extern void ILFree(
IntPtr pidl);

// Copy clipboard data into unmanaged memory.

MemoryStream data =3D (MemoryStream)Clipboard.GetData("Shell IDList =
Array");
byte[] b =3D data.ToArray();

IntPtr p =3D Marshal.AllocHGlobal(b.Length);
Marshal.Copy(b, 0, p, b.Length);

// Get number of items.

UInt32 cidl =3D (UInt32)Marshal.ReadInt32(p);

// Get parent folder.


int offset =3D sizeof(UInt32);
IntPtr parentpidl =3D (IntPtr)((int)p + (UInt32)Marshal.ReadInt32(p, =
offset));

StringBuilder path =3D new StringBuilder(256);
SHGetPathFromIDList(parentpidl, path);

// Get subitems.


for (int i =3D 1; i <=3D cidl; ++i)
{
offset +=3D sizeof(UInt32);
IntPtr relpidl =3D (IntPtr)((int)p + (UInt32)Marshal.ReadInt32(p, =
offset));

IntPtr abspidl =3D ILCombine(parentpidl, relpidl);
SHGetPathFromIDList(abspidl, path);
ILFree(abspidl);
}

--=20


Jim Barry, MVP (Windows SDK)

Previous Posts In This Thread:

http://www.tech-archive.net/Archive/DotNet/microsoft.public.dotnet.framework.interop/2006-01/msg00041.html

http://msdn2.microsoft.com/en-us/library/bb773212.aspx

--=20


Jim Barry, MVP (Windows SDK)

On Friday, December 07, 2007 9:13 AM
dzMik wrote:

JimMany thanks for this link.
Jim

Many thanks for this link. I will read, experiment, and post a code snippet
here when done in case anyone else is searching for this.

Thanks again

Mike


"Jim Barry" wrote:

On Friday, December 07, 2007 10:56 AM
dzMik wrote:

JimThanks again for your help.
Jim

Thanks again for your help. I have declared the CIDA thusly:

[StructLayout(LayoutKind.Sequential)]
public struct CIDA
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
public uint[] aoffset;
}

Then I'm using the following code to get the PIDL of the parent folder (e is
a dragdrop event args):

MemoryStream data = (MemoryStream)e.Data.GetData("Shell IDList Array");
byte[] b = data.ToArray();


IntPtr p = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(CIDA)));
Marshal.Copy(b, 0, p, b.Length);
CIDA cida = (CIDA)Marshal.PtrToStructure(p, typeof(CIDA));

//p is the pointer to the cida
IntPtr parentpidl = (IntPtr)((int)p + cida.aoffset[0]);
string item;
SHGetPathFromIDList((int)parentpidl, out item);

item is always coming back as null. I assume this means the parent folder is
the desktop since I am dragging 'My Documents' from the desktop. However, I
can't figure out how to access the next PIDL in the array, since the size is
constant. I've tried this:

IntPtr parentpidl = (IntPtr)((int)p + cida.aoffset[0] + sizeof(uint));

but this throws an execution engine error. What am I doing wrong?

Thanks for your time,

Mike

On Monday, December 10, 2007 11:20 AM
Jim Barry wrote:

Re: Getting Path from a Shell IDList Array in C#
dzMike wrote:

This approach isn't going to work because .NET interop doesn't support =
variable length arrays in structures. Basically you need to grovel over =
the raw data and pull out the offsets on by one. I'm not a C# person, =


but I managed to cobble together the following code:

[DllImport("shell32.dll")]
public static extern Int32 SHGetPathFromIDList(
IntPtr pidl, StringBuilder pszPath);

[DllImport("shell32.dll")]
public static extern IntPtr ILCombine(
IntPtr pidl1, IntPtr pidl2);

[DllImport("shell32.dll")]
public static extern void ILFree(
IntPtr pidl);

// Copy clipboard data into unmanaged memory.

MemoryStream data =3D (MemoryStream)Clipboard.GetData("Shell IDList =
Array");
byte[] b =3D data.ToArray();

IntPtr p =3D Marshal.AllocHGlobal(b.Length);
Marshal.Copy(b, 0, p, b.Length);

// Get number of items.

UInt32 cidl =3D (UInt32)Marshal.ReadInt32(p);

// Get parent folder.


int offset =3D sizeof(UInt32);
IntPtr parentpidl =3D (IntPtr)((int)p + (UInt32)Marshal.ReadInt32(p, =
offset));

StringBuilder path =3D new StringBuilder(256);
SHGetPathFromIDList(parentpidl, path);

// Get subitems.


for (int i =3D 1; i <=3D cidl; ++i)
{
offset +=3D sizeof(UInt32);
IntPtr relpidl =3D (IntPtr)((int)p + (UInt32)Marshal.ReadInt32(p, =
offset));

IntPtr abspidl =3D ILCombine(parentpidl, relpidl);
SHGetPathFromIDList(abspidl, path);
ILFree(abspidl);
}

--=20


Jim Barry, MVP (Windows SDK)

On Monday, December 10, 2007 11:53 AM
dzMik wrote:

Re: Getting Path from a Shell IDList Array in C#
Truly excellent cobbling, Jim :). Thank you very much.

Mike Payne


"Jim Barry" wrote:

On Wednesday, April 21, 2010 5:01 AM
Daniel Stoinski wrote:

Works perfectly on desktop, remark for Windows Mobile

Jim,

perfect explanation, best thanks. It works perfectly on W2K, probably the same for XP, Vista etc.

On Windows Mobile 6 I had to add additionally two sizes of Int32 to the offset. Eg. the parent pidl is then

int offset = 3 * sizeof(UInt32);


IntPtr parentpidl = (IntPtr)((int)p + (UInt32)Marshal.ReadInt32(p, offset));

rather than

int offset = sizeof(UInt32);
IntPtr parentpidl = (IntPtr)((int)p + (UInt32)Marshal.ReadInt32(p, offset));

Warning. SHGetPathFromIDList causes segmentation faults if called with a wrong pidl.

Best regards
Daniel Stoinski


Submitted via EggHeadCafe - Software Developer Portal of Choice

BizTalk: Incorporating conditional If / Else Functoid Logic in a map.
http://www.eggheadcafe.com/tutorials/aspnet/f6fc20ab-5c6a-4f04-8a0b-bba39e4bbcf0/biztalk-incorporating-co.aspx

danielstoinski

unread,
Apr 21, 2010, 2:06:59 PM4/21/10
to
See also
http://serialcs.svn.sourceforge.net/viewvc/serialcs/trunk/serialcs/Clip.cs?view=markup

Daniel Stoinski wrote:

Works perfectly on desktop, remark for Windows Mobile

21-Apr-10

Jim,

perfect explanation, best thanks. It works perfectly on W2K, probably the same for XP, Vista etc.

On Windows Mobile 6 I had to add additionally two sizes of Int32 to the offset. Eg. the parent pidl is then

int offset = 3 * sizeof(UInt32);
IntPtr parentpidl = (IntPtr)((int)p + (UInt32)Marshal.ReadInt32(p, offset));

rather than

int offset = sizeof(UInt32);
IntPtr parentpidl = (IntPtr)((int)p + (UInt32)Marshal.ReadInt32(p, offset));

Warning. SHGetPathFromIDList causes segmentation faults if called with a wrong pidl.

Best regards
Daniel Stoinski

Previous Posts In This Thread:


Submitted via EggHeadCafe - Software Developer Portal of Choice

A Framework to Animate WPF and Silverlight Pages Similar to the PowerPoint Slides
http://www.eggheadcafe.com/tutorials/aspnet/7390a840-dd39-4c35-9940-c7354940d878/a-framework-to-animate-wp.aspx

0 new messages