I'm trying to display a standard open file dialog that can select folders, using the IFileOpenDialog interface in C#, Visual Studio 2010.
I'm trying to use the minimal code, so I've only defined the methods I need in the interfaces:
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// Disable warning CS0108: 'x' hides inherited member 'y'. Use the new keyword if hiding was intended.
\#pragma warning disable 0108
namespace FolderDialog
{
internal static class IIDGuid
{
internal const string IModalWindow = "b4db1657-70d7-485e-8e3e-6fcb5a5c1802";
internal const string IFileDialog = "42f85136-db7e-439c-85f1-e4075d135fc8";
internal const string IFileOpenDialog = "d57c7288-d4ad-4768-be02-9d969532d960";
}
internal static class CLSIDGuid
{
internal const string FileOpenDialog = "DC1C5A9C-E88A-4dde-A5A1-60F82A20AEF7";
}
static class NativeMethods
{
[Flags]
internal enum FOS : uint
{
FOS_PICKFOLDERS = 0x00000020
}
}
[ComImport(),
Guid(IIDGuid.IModalWindow),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IModalWindow
{
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime),
PreserveSig]
int Show([In] IntPtr parent);
}
[ComImport(),
Guid(IIDGuid.IFileDialog),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IFileDialog : IModalWindow
{
// Defined on IModalWindow - repeated here due to requirements of COM interop layer
// --------------------------------------------------------------------------------
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime),
PreserveSig]
int Show([In] IntPtr parent);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void SetOptions([In] NativeMethods.FOS fos);
}
[ComImport(),
Guid(IIDGuid.IFileOpenDialog),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IFileOpenDialog : IFileDialog
{
// Defined on IModalWindow - repeated here due to requirements of COM interop layer
// --------------------------------------------------------------------------------
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime),
PreserveSig]
int Show([In] IntPtr parent);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void SetOptions([In] NativeMethods.FOS fos);
}
// ---------------------------------------------------
// .NET classes representing runtime callable wrappers
[ComImport,
ClassInterface(ClassInterfaceType.None),
TypeLibType(TypeLibTypeFlags.FCanCreate),
Guid(CLSIDGuid.FileOpenDialog)]
internal class FileOpenDialogRCW
{
}
// ---------------------------------------------------------
// Coclass interfaces - designed to "look like" the object
// in the API, so that the 'new' operator can be used in a
// straightforward way. Behind the scenes, the C# compiler
// morphs all 'new CoClass()' calls to 'new CoClassWrapper()'
[ComImport,
Guid(IIDGuid.IFileOpenDialog),
CoClass(typeof(FileOpenDialogRCW))]
internal interface NativeFileOpenDialog : IFileOpenDialog
{
}
}
If I only call
IFileDialog dialog = null;
try
{
dialog = new NativeFileOpenDialog();
dialog.Show(IntPtr.Zero);
}
finally
{
if (dialog != null)
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(dialog);
}
it works fine and it opens the File Dialog without any errors.
If I try:
IFileDialog dialog = null;
try
{
dialog = new NativeFileOpenDialog();
dialog.SetOptions(NativeMethods.FOS.FOS_PICKFOLDERS);
dialog.Show(IntPtr.Zero);
}
finally
{
if (dialog != null)
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(dialog);
}
so If I add a call to the SetOptions method before the Show method call, I get an exception: "Attempted to read or write protected memory. This is often an indication that other memory is corrupt."
I get this trying to run on .Net 2.0 or even 4.0.
What is the error here? Why does just calling the Show method work, but if I try another method before it fails?