public bool RemoveImage(
            string targetConfName
            ,  string targetImagePath
            , IWin32Window owner
            )
        {
            var targetFormat =
                _saiTextureFormatList
                    .FirstOrDefault(saiTextureFormat =>
                        targetConfName == saiTextureFormat.name);
            if (targetFormat == null)
            {
                throw new ArgumentOutOfRangeException("targetConfName");
            }

            targetImagePath =
                targetFormat.image_vector
                    .FirstOrDefault(imagePath =>
                        targetImagePath == imagePath);
            if (targetImagePath == null)
            {
                throw new ArgumentOutOfRangeException("targetImagePath");
            }

            //エクスプローラーでファイル削除
            var shfop = new SH.SHFILEOPSTRUCT
            {
                hwnd = owner.Handle,
                wFunc = SH.FileFuncFlags.FO_DELETE,
                pFrom = _pathToSaiFolder + "\\" + targetImagePath + '\0' + '\0',
                fFlags = SH.FILEOP_FLAGS.FOF_ALLOWUNDO | SH.FILEOP_FLAGS.FOF_WANTNUKEWARNING | SH.FILEOP_FLAGS.FOF_NOCONFIRMATION
            };
            int res = SH.SHFileOperation(ref shfop);
            if (res == 1223)
            {
                shfop.fAnyOperationsAborted = true;
            }
            else if (res != 0)
            {
                targetFormat.image_vector.Remove(targetImagePath);//IOエラーなファイルを登録として残しておくのも不健康なので。
                throw new System.IO.IOException(); //something happened
            }
            if (shfop.fAnyOperationsAborted == true)
            {
                return false; //ファイル処理中断
            }

            //登録を削除
            targetFormat.image_vector.Remove(targetImagePath);
            return true;
        }
        public bool AddImage(
            string targetConfName
            , string fromPath
            , IWin32Window owner
            )
        {
            var targetFormat =
                _saiTextureFormatList
                    .FirstOrDefault(saiTextureFormat =>
                        targetConfName == saiTextureFormat.name);
            if (targetFormat == null)
            {
                throw new ArgumentOutOfRangeException("targetConfName");
            }

            //ビットマップサイズのチェック
            var original = Bitmap.FromFile( fromPath );
            bool sizeFound = false;
            foreach(Size sz in targetFormat.sizes)
            {
                if (sz == original.Size)
                {
                    sizeFound = true;
                    break;
                }
            }
            if (sizeFound == false)
            {

                string availableSizesString = "";
                foreach( Size sz in targetFormat.sizes )
                {
                    availableSizesString += "「" + sz.Width + " x " + sz.Height + "」";
                }
                CenteredMessageBox.Show( owner
                    , targetConfName+"に登録可能な画像サイズではありませんでした。\n"
                        +"登録しようとしたサイズ: 幅 "+ original.Size.Width + " x 高さ "+ original.Height +"\n"
                        + "登録可能なサイズ: " + availableSizesString
                    , "登録失敗"
                    , MessageBoxButtons.OK
                    , MessageBoxIcon.Error );
                return false;
            }
            original.Dispose();

            //登録済みでないかチェック
            var imagePath = targetFormat.directory + "\\" + Path.GetFileName(fromPath);
            if (targetFormat.image_vector.Contains(imagePath))
            {
                CenteredMessageBox.Show( owner
                    , targetConfName + "に登録済みでした。\n"
                    , "登録失敗"
                    , MessageBoxButtons.OK
                    , MessageBoxIcon.Error );
                return false; //登録済みだったので処理しなかった
            }

            var dst = _pathToSaiFolder+ "\\" + imagePath;

            if (File.Exists(dst))
            {
                //シェルのコピーコマンドで「上書きかスキップ」を選択できるのでファイル操作はそれにまかせる。
                //それだけだとSAIへの登録自体はそのまま続行されるので問い合わせ
                DialogResult res = CenteredMessageBox.Show( owner
                    , "ビットマップファイルがすでに存在します\n"
                        + "登録を続行しますか?:\n"
                        + dst
                    , "登録確認"
                    , MessageBoxButtons.OKCancel
                    , MessageBoxIcon.Question );

                if( res == DialogResult.Cancel )
                    return false;
            }

            // Exploreシェルでファイルをコピーする。
            var shfop = new SH.SHFILEOPSTRUCT
            {
                hwnd = owner.Handle,
                wFunc = SH.FileFuncFlags.FO_COPY,
                pFrom = fromPath + '\0' + '\0',
                pTo = dst + '\0' + '\0',
                fFlags = SH.FILEOP_FLAGS.FOF_ALLOWUNDO
            };
            if (SH.SHFileOperation(ref shfop) != 0)
            {
                return false; //throw new System.IO.IOException(); //something happened
            }
            if (shfop.fAnyOperationsAborted == true)
            {
                return false; //ファイル処理中断
            }

            targetFormat.image_vector.Add(imagePath);
            return true;
        }