/// <summary>
        /// ウィンドウメッセージハンドラ
        /// </summary>
        /// <param name="hwnd">ウィンドウハンドラ</param>
        /// <param name="msg">ウィンドウメッセージ</param>
        /// <param name="wParam">パラメータ</param>
        /// <param name="lParam">サブパラメータ</param>
        /// <param name="handled">以降の処理をスキップしたい場合はコード内で true を指定します。</param>
        /// <returns>ゼロポインタを返します。</returns>
        private static IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
        {
            var hwndSource = HwndSource.FromHwnd(hwnd);
            var target     = hwndSource.RootVisual;

            if (target != null)
            {
                int    item1   = 0;
                int    devType = 0;
                string driveString;

                if (msg == Shell32.Constant.WM_SHNOTIFY)
                {
                    var driveRootPathBuffer = new StringBuilder("A:\\");
                    switch ((uint)lParam)
                    {
                    case Shell32.Constant.SHCNE_MEDIAINSERTED:
                        // 構造体の一部を読み取る
                        item1 = Marshal.ReadInt32(wParam);
                        // ドライブレターを確定する
                        Shell32.SHGetPathFromIDList((IntPtr)item1, driveRootPathBuffer);
                        // string 型に直す
                        driveString = driveRootPathBuffer.ToString().Substring(0, 1);
                        // コールバック処理をおこなう
                        handled = CheckDrive(target, driveString, true);
                        break;

                    case Shell32.Constant.SHCNE_MEDIAREMOVED:
                        // 構造体の一部を読み取る
                        item1 = Marshal.ReadInt32(wParam);
                        // ドライブレターを確定する
                        Shell32.SHGetPathFromIDList((IntPtr)item1, driveRootPathBuffer);
                        // string 型に直す
                        driveString = driveRootPathBuffer.ToString().Substring(0, 1);
                        // コールバック処理をおこなう
                        handled = CheckDrive(target, driveString, false);
                        break;
                    }
                }
                else if (msg == Shell32.Constant.WM_DEVICECHANGE)
                {
                    switch ((int)wParam)
                    {
                    case Shell32.Constant.DBT_CONFIGCHANGECANCELED:
                        break;

                    case Shell32.Constant.DBT_CONFIGCHANGED:
                        break;

                    case Shell32.Constant.DBT_CUSTOMEVENT:
                        break;

                    case Shell32.Constant.DBT_DEVICEARRIVAL:
                        devType = Marshal.ReadInt32(lParam, 4);
                        if (devType == Shell32.Constant.DBT_DEVTYP_VOLUME)
                        {
                            var vol = (Shell32.DEV_BROADCAST_VOLUME)Marshal.PtrToStructure(lParam, typeof(Shell32.DEV_BROADCAST_VOLUME));
                            driveString = Shell32.GetDriveString(vol.dbcv_unitmask);
                            // コールバック処理をおこなう
                            handled = CheckDrive(target, driveString, true);
                        }
                        break;

                    case Shell32.Constant.DBT_DEVICEQUERYREMOVE:
                        break;

                    case Shell32.Constant.DBT_DEVICEQUERYREMOVEFAILED:
                        break;

                    case Shell32.Constant.DBT_DEVICEREMOVECOMPLETE:
                        devType = Marshal.ReadInt32(lParam, 4);
                        if (devType == Shell32.Constant.DBT_DEVTYP_VOLUME)
                        {
                            var vol = (Shell32.DEV_BROADCAST_VOLUME)Marshal.PtrToStructure(lParam, typeof(Shell32.DEV_BROADCAST_VOLUME));
                            driveString = Shell32.GetDriveString(vol.dbcv_unitmask);
                            // コールバック処理をおこなう
                            handled = CheckDrive(target, driveString, false);
                        }
                        break;

                    case Shell32.Constant.DBT_DEVICEREMOVEPENDING:
                        break;

                    case Shell32.Constant.DBT_DEVICETYPESPECIFIC:
                        break;

                    case Shell32.Constant.DBT_DEVNODES_CHANGED:
                        break;

                    case Shell32.Constant.DBT_QUERYCHANGECONFIG:
                        break;

                    case Shell32.Constant.DBT_USERDEFINED:
                        break;
                    }
                }
            }

            return(IntPtr.Zero);
        }