when inserting an USB-Flash drive, Windows normally opens the Autoplay dialog that offers to browse the drive or if there are multimedia files it offers to choose an app to open them.
We developed a media player that is connected to the USB-Drive and registers itself as Mass Storage Device.
What I need is, that when inserting the Player that this Dialog is not shown, but instead my own application is launched.
Ideally the application would be on the Flash Drive itself, but as I understood is that Autorun is disabled for USB-Drives.
It would be enough if a preinstalled application is launched. I already tried to catch the WM_DRIVE_CHANGE message, but this only works if my application is the top most window, otherwise the Autoplay Dialog is displayed.
after a long research on Google I found this forum post:
http://social.msdn.microsoft.com/Forums/uk-UA/windowssdk/thread/aef929cb-62ac-4371-b7de-2c07adf3c6a7
I followed this and here is the working code:
[Flags()]
public enum AutorunContent : int
{
AutorunInf = 2,
AudioCD = 4,
DVDMovie = 8,
BlankCD = 16,
BlankDVD = 32,
UnknownContent = 64,
AutoPlayPictures = 128,
AutoPlayMusics = 256,
AutoPlayMovies = 512
}
[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("DDEFE873-6997-4e68-BE26-39B633ADBE12")]
public interface IQueryCancelAutoPlay
{
[PreserveSig]
int AllowAutoPlay(
[MarshalAs(UnmanagedType.LPWStr)] string pszPath,
[MarshalAs(UnmanagedType.U4)] AutorunContent dwContentType,
[MarshalAs(UnmanagedType.LPWStr)] string pszLabel,
[MarshalAs(UnmanagedType.U4)] int dwSerialNumber);
}
public class RunningObjectTableEntry : IDisposable
{
private int cookie;
private IRunningObjectTable rot = null;
private IMoniker monkey = null;
private RunningObjectTableEntry() { }
/// <summary>
/// Creates a new entry for the given object
/// </summary>
/// <param name="obj">Object to make an entry for. Only one object per class should ever be registered.</param>
public RunningObjectTableEntry(object obj)
{
int hr = GetRunningObjectTable(0, out rot);
if (hr != 0)
{
throw new COMException("Could not retreive running object table!", hr);
}
Guid clsid = obj.GetType().GUID;
hr = CreateClassMoniker(ref clsid, out monkey);
if (hr != 0)
{
Marshal.ReleaseComObject(rot);
throw new COMException("Could not create moniker for CLSID/IID \"" + clsid + "\"!", hr);
}
cookie = rot.Register(0x01, obj, monkey); //weak reference, but allow any user
}
[DllImport("ole32.dll", ExactSpelling = true)]
private static extern int GetRunningObjectTable([MarshalAs(UnmanagedType.U4)] int reserved, out IRunningObjectTable pprot);
[DllImport("ole32.dll", CharSet = CharSet.Unicode, ExactSpelling = true)]
private static extern int CreateClassMoniker([In] ref Guid g, [Out] out IMoniker ppmk);
#region IDisposable Members
/// <summary>
/// De-registers the object and class from the Running Object Table
/// </summary>
public void Dispose()
{
Marshal.ReleaseComObject(monkey);
rot.Revoke(cookie);
Marshal.ReleaseComObject(rot);
}
#endregion
}
[ComVisible(true)]
[Guid("331F1768-05A9-4ddd-B86E-DAE34DDC998A")]
[ClassInterface(ClassInterfaceType.None)]
public class Autoplay : IQueryCancelAutoPlay, IDisposable
{
private RunningObjectTableEntry rotEntry;
public Autoplay()
{
rotEntry = new RunningObjectTableEntry(this);
}
#region IQueryCancelAutoPlay Members
public int AllowAutoPlay(string pszPath, AutorunContent dwContentType, string pszLabel, int dwSerialNumber)
{
if (pszLabel == "FUNKEYPLAY") //This is the name of my volume that should not call autoplay
{
return 1;
}
else
{
return 0;
}
//Console.WriteLine("QueryCancelAutoPlay:");
//Console.WriteLine(" " + pszPath);
//Console.WriteLine(" " + dwContentType.ToString("x"));
//Console.WriteLine(" " + pszLabel);
//Console.WriteLine(" " + dwSerialNumber.ToString());
}
#endregion
#region IDisposable Members
public void Dispose()
{
rotEntry.Dispose();
}
#endregion
}
}