結果だけでなく過程も見てください

日々の奮闘を綴る日記です。

ファイナルファンタジーXI(FF9) チョコグラフの場所スクリーンショット一覧

# チョコグラフ名 発見場所 スクリーンショット
1 川のほとり チョコボの森1 f:id:taiyakisun:20210725042049j:plain
2 山のはざま チョコボの森1 f:id:taiyakisun:20210725042116j:plain
3 みかいの地 チョコボの森1 f:id:taiyakisun:20210725042126j:plain
4 やすらぎの浜 チョコボの森1 f:id:taiyakisun:20210725042134j:plain
5 枯れた砂浜 チョコボの森1 f:id:taiyakisun:20210725042142j:plain
6 いてつく大地 チョコボの森1 f:id:taiyakisun:20210725042150j:plain
7 忘れられた浅瀬 チョコボの入り江1 f:id:taiyakisun:20210725042158j:plain
8 遠くの浅瀬 チョコボの森1 f:id:taiyakisun:20210725042206j:plain
9 枯れ果てゆく浅瀬 チョコボの入り江1 f:id:taiyakisun:20210725042213j:plain
10 ふかんの浅瀬 チョコボの森1 f:id:taiyakisun:20210725042220j:plain
11 小さな浜辺 チョコボの森1 f:id:taiyakisun:20210725042227j:plain
12 夜あけの浅瀬 チョコボの入り江1 f:id:taiyakisun:20210725042233j:plain
13 閉ざされた森 チョコボの森2 f:id:taiyakisun:20210725042240j:plain
14 緑の高原 チョコボの森2 f:id:taiyakisun:20210725042248j:plain
15 夕ぐれの高原 チョコボの入り江1 f:id:taiyakisun:20210725042255j:plain
16 忘れられた高原 チョコボの森2 f:id:taiyakisun:20210725042302j:plain
17 夕ぐれの海原 チョコボの入り江2 f:id:taiyakisun:20210725042309j:plain
18 チョコボの入り江2 f:id:taiyakisun:20210725042316j:plain
19 冷たい入り江 チョコボの森2 f:id:taiyakisun:20210725042325j:plain
20 霧の近海 チョコグラフのかけら(入り江2だった) f:id:taiyakisun:20210725042336j:plain
21 外側の島 チョコボ空中庭園 f:id:taiyakisun:20210725042343j:plain
22 外側の島2 チョコボの入り江2 f:id:taiyakisun:20210725042350j:plain
23 せいれいの島 チョコボ空中庭園 f:id:taiyakisun:20210725042357j:plain
24 忘れられた島 チョコボ空中庭園 f:id:taiyakisun:20210725042404j:plain

ファイナルファンタジーXI(FF9) DISC4(4章)で買える武器・合成アイテム一覧

武器・防具

アイテム名 値段 売っている場所
ミスリルダガー 950 アレクサンドリア城下町・広場の武器屋 トレノ・武器屋
グラディウス 2300 アレクサンドリア城下町・広場の武器屋 トレノ・武器屋
アイスブランド 3780 アレクサンドリア城下町・広場の武器屋 トレノ・武器屋
パルチザン 1600 アレクサンドリア城下町・広場の武器屋 トレノ・武器屋
アイスランス 2430 アレクサンドリア城下町・広場の武器屋 トレノ・武器屋
猫の爪 4000 アレクサンドリア城下町・広場の武器屋 トレノ・武器屋
ポイズンナックル 5000 アレクサンドリア城下町・広場の武器屋 トレノ・武器屋 イプセンの古城・モグネット
星くずのロッド 760 アレクサンドリア城下町・広場の武器屋 トレノ・武器屋
いやしのロッド 1770 アレクサンドリア城下町・広場の武器屋 トレノ・武器屋
ラミアのふえ 3800 アレクサンドリア城下町・広場の武器屋 トレノ・武器屋 イプセンの古城・モグネット
炎のつえ 1100 アレクサンドリア城下町・広場の武器屋
氷のつえ 980 アレクサンドリア城下町・広場の武器屋
雷のつえ 1200 アレクサンドリア城下町・広場の武器屋
オークスタッフ 2400 アレクサンドリア城下町・広場の武器屋 トレノ・武器屋 イプセンの古城・モグネット
円月輪 200 アレクサンドリア城下町・広場の武器屋
ガラスの腕輪 250 アレクサンドリア城下町・広場の武器屋
ボーンリスト 330 アレクサンドリア城下町・広場の武器屋
ミスリルの腕輪 500 アレクサンドリア城下町・広場の武器屋
魔法の腕輪 1000 アレクサンドリア城下町・広場の武器屋 トレノ・武器屋 ダゲレオ・武器屋
ミスリルのこて 980 アレクサンドリア城下町・広場の武器屋 トレノ・武器屋
雷神のこて 1200 アレクサンドリア城下町・広場の武器屋 トレノ・武器屋
ラミアのティアラ 800 アレクサンドリア城下町・広場の武器屋 トレノ・武器屋 ダゲレオ・武器屋
みこしかつぎ帽子 1000 アレクサンドリア城下町・広場の武器屋 トレノ・武器屋
みじりはちまき 1200 アレクサンドリア城下町・広場の武器屋 トレノ・武器屋
バルビュータ 600 アレクサンドリア城下町・広場の武器屋
ミスリルヘルム 1000 アレクサンドリア城下町・広場の武器屋 トレノ・武器屋
ゴールドヘルム 1800 アレクサンドリア城下町・広場の武器屋 トレノ・武器屋
魔術師の服 1850 アレクサンドリア城下町・広場の武器屋 トレノ・武器屋
サバイバルベスト 2900 アレクサンドリア城下町・広場の武器屋 トレノ・武器屋
ブリガンダイン 4300 アレクサンドリア城下町・広場の武器屋 トレノ・武器屋
ミスリルアーマー 1830 アレクサンドリア城下町・広場の武器屋 トレノ・武器屋
プレイトメイル 2320 アレクサンドリア城下町・広場の武器屋 トレノ・武器屋
ダガー 320 トレノ・武器屋
メイジマッシャー 500 トレノ・武器屋 イプセンの古城・モグネット
さんごの剣 4000 トレノ・武器屋
マルチナラケット 750 トレノ・武器屋 イプセンの古城・モグネット
リネンキュラッサ 800 トレノ・武器屋
オリハルコン 17000 ダゲレオ・武器屋
ディフェンダー 9340 ダゲレオ・武器屋
アルテマソード 14000 ダゲレオ・武器屋
ホーリーランス 11000 ダゲレオ・武器屋
アベンジャー 16000 ダゲレオ・武器屋
カイザーナックル 18000 ダゲレオ・武器屋
ミスリルラケット 2250 ダゲレオ・武器屋
フォーク 1100 ダゲレオ・武器屋
ビストロフォーク 10300 ダゲレオ・武器屋
ライジングサン 500 ダゲレオ・武器屋 イプセンの古城・モグネット
エゴイストの腕輪 2000 ダゲレオ・武器屋
ドラゴンリスト 4800 ダゲレオ・武器屋
パワーリスト 5100 ダゲレオ・武器屋
まもりのこて 6000 ダゲレオ・武器屋
イージスのこて 7000 ダゲレオ・武器屋
魔術師の帽子 600 ダゲレオ・武器屋
金の髪飾り 3700 ダゲレオ・武器屋 イプセンの古城・モグネット
ヒュプノクラウン 4400 ダゲレオ・武器屋
閃光魔帽 5200 ダゲレオ・武器屋
アダマン帽 6100 ダゲレオ・武器屋
プラチナヘルム 4600 ダゲレオ・武器屋
カエサルヘルム 7120 ダゲレオ・武器屋
魔人の胸当て 10250 ダゲレオ・武器屋
ミネルバビスチェ 12200 ダゲレオ・武器屋
忍びの衣 14000 ダゲレオ・武器屋
プラチナアーマー 10500 ダゲレオ・武器屋
キャラビニエール 12300 ダゲレオ・武器屋
ドラゴンメイル 14000 ダゲレオ・武器屋
アイアンソード 660 イプセンの古城・モグネット
ミスリルスピア 1100 イプセンの古城・モグネット
ミスリルロッド 560 イプセンの古城・モグネット
ニードルフォーク 3100 イプセンの古城・モグネット
ンカイの腕輪 3000 イプセンの古城・モグネット
ヒスイの腕輪 3400 イプセンの古城・モグネット
ベネチアシールド 2800 イプセンの古城・モグネット
レッドキャップ 3000 イプセンの古城・モグネット
クロスヘルム 2200 イプセンの古城・モグネット
ダイヤヘルム 3000 イプセンの古城・モグネット
力だすき 7200 イプセンの古城・モグネット
大地の衣 8700 イプセンの古城・モグネット
シールドアーマー 4300 イプセンの古城・モグネット
デモンズメイル 5900 イプセンの古城・モグネット
ウィザードロッド 3990 黒魔道士の村
セイレーンのふえ 7000 黒魔道士の村
魔導師のつえ 6000 黒魔道士の村
シーフの帽子 7100 黒魔道士の村
司祭の帽子 8300 黒魔道士の村
黒装束 16300 黒魔道士の村

合成屋

アイテム名 値段 素材1 素材2 売っている場所
エンジェルブレス 9000 ミスリルダガー グラディウス ダゲレオ・合成屋 アレクサンドリア・合成屋 トレノ・合成屋 黒魔道士の村・合成屋
サルガタナス 12000 グラディウス ゾーリンシェイプ ダゲレオ・合成屋 黒魔道士の村・合成屋
もめんのローブ 1000 リスト とんがり帽子 ダゲレオ・合成屋 アレクサンドリア・合成屋 トレノ・合成屋
シルクのローブ 2000 シルクの服 バンダナ ダゲレオ・合成屋 アレクサンドリア・合成屋 トレノ・合成屋
魔術師のローブ 3000 魔道士のつえ 魔術師の服 ダゲレオ・合成屋 アレクサンドリア・合成屋
飽食のローブ 6000 ミスリルフォーク もめんのローブ ダゲレオ・合成屋
白のローブ 8000 大地の衣 ヒスイの腕輪 ダゲレオ・合成屋
黒のローブ 8000 大地の衣 ンカイの腕輪 ダゲレオ・合成屋
カチューシャ 1000 三角帽子 ラバーヘルム ダゲレオ・合成屋 アレクサンドリア・合成屋 トレノ・合成屋
さんごの指輪 1200 雷のつえ ロッド ダゲレオ・合成屋 アレクサンドリア・合成屋 トレノ・合成屋
魔術師のくつ 1500 ゲルミナスブーツ ボーンリスト ダゲレオ・合成屋 アレクサンドリア・合成屋 トレノ・合成屋
バレッタ 1800 ニードルフォーク バルビュータ ダゲレオ・合成屋 アレクサンドリア・合成屋 トレノ・合成屋
パワーベルト 2000 ガラスのバックル チェインメイル ダゲレオ・合成屋 アレクサンドリア・合成屋 トレノ・合成屋
マダインの指輪 3000 ボーンリスト 星くずのロッド ダゲレオ・合成屋 アレクサンドリア・合成屋 トレノ・合成屋
妖精のピアス 3200 魔法の腕輪 金の針 ダゲレオ・合成屋 アレクサンドリア・合成屋 トレノ・合成屋
イクステンション 3500 ラミアのティアラ マルチナラケット ダゲレオ・合成屋 アレクサンドリア・合成屋 トレノ・合成屋
リフレクトリング 7000 アンクレット マダインの指輪 ダゲレオ・合成屋 アレクサンドリア・合成屋 トレノ・合成屋
アンクレット 4000 金のチョーカー ペリドット ダゲレオ・合成屋 アレクサンドリア・合成屋 トレノ・合成屋
フェザーブーツ 4000 魔術師のくつ フェニックスの羽 ダゲレオ・合成屋 アレクサンドリア・合成屋 トレノ・合成屋
黒帯 4000 ねじりはちまき サバイバルベスト ダゲレオ・合成屋 アレクサンドリア・合成屋 トレノ・合成屋
パールルージュ 5000 ムーンストーン エリクサー ダゲレオ・合成屋 アレクサンドリア・合成屋 トレノ・合成屋
プロミストリング 6000 キマイラの腕輪 ルビー ダゲレオ・合成屋
バトルブーツ 6500 フェザーブーツ ウイングエッジ ダゲレオ・合成屋
転生の指輪 7000 ダイヤモンド アンクレット ダゲレオ・合成屋
天使のイヤリング 8000 妖精のピアス バレッタ ダゲレオ・合成屋
ガーネット 350 原石 万能薬 ダゲレオ・合成屋 黒魔道士の村・合成屋
アメジスト 200 原石 迷惑チン ダゲレオ・合成屋 黒魔道士の村・合成屋
ペリドット 100 原石 金の針 ダゲレオ・合成屋 黒魔道士の村・合成屋
サファイア 200 原石 毒消し ダゲレオ・合成屋 黒魔道士の村・合成屋
オパール 100 原石 ポーション ダゲレオ・合成屋 黒魔道士の村・合成屋
トパーズ 100 原石 目薬 ダゲレオ・合成屋 黒魔道士の村・合成屋
盗賊のこて 50000 ミスリルの腕輪 サルガタナス ダゲレオ・合成屋
オーガニクス 700 メイジマッシャー メイジマッシャー アレクサンドリア・合成屋 トレノ・合成屋 黒魔道士の村・合成屋
エクスプローダ 1000 メイジマッシャー ミスリルダガー アレクサンドリア・合成屋 トレノ・合成屋 黒魔道士の村・合成屋
ルーントゥース 2000 ミスリルダガー ミスリルダガー アレクサンドリア・合成屋 トレノ・合成屋 黒魔道士の村・合成屋
デザートブーツ 300 皮の帽子 皮の服 アレクサンドリア・合成屋 トレノ・合成屋 黒魔道士の村・合成屋
黄色いスカーフ 400 羽根付き帽子 とんがり帽子 アレクサンドリア・合成屋 トレノ・合成屋 黒魔道士の村・合成屋
ガラスのバックル 500 ガラスの腕輪 皮のリスト アレクサンドリア・合成屋 トレノ・合成屋 黒魔道士の村・合成屋
ゲルミナスブーツ 900 デザートブーツ フォーク アレクサンドリア・合成屋 トレノ・合成屋 黒魔道士の村・合成屋
金のチョーカー 1300 リネンキュラッサ 金の針 アレクサンドリア・合成屋 トレノ・合成屋 黒魔道士の村・合成屋
バタフライソード 300 ダガー メイジマッシャー 黒魔道士の村・合成屋
マサムネ 16000 ゾーリンシェイプ オリハルコン 黒魔道士の村・合成屋
デュエルクロー 16000 ドラゴンクロー タイガーファング 黒魔道士の村・合成屋
司祭のラケット 11000 エアラケット カチューシャ 黒魔道士の村・合成屋
ブレイサー 24000 グラディウス ゾーリンシェイプ 黒魔道士の村・合成屋
ガントレット 8000 ミスリルのこて ドラゴンリスト 黒魔道士の村・合成屋
黄金のスカラー 15000 ゴールドヘルム 金の髪飾り 黒魔道士の村・合成屋
サークレット 20000 ヒュプノクラウン ロゼッタの腕輪 黒魔道士の村・合成屋
グランドヘルム 20000 クロスヘルム パワーベルト 黒魔道士の村・合成屋
ラバーコンシャス 20000 ミネルバビスチェ エゴイストの腕輪 黒魔道士の村・合成屋
ブレイブスーツ 26000 ミスリルベスト ミスリルロッド 黒魔道士の村・合成屋
光のローブ 20000 魔術師のローブ ガラスの腕輪 黒魔道士の村・合成屋
グランドアーマー 45000 ミスリルソード ミスリルアーマー 黒魔道士の村・合成屋
エルメスのくつ 12000 バトルブーツ エメラルド 黒魔道士の村・合成屋
ロゼッタの指輪 24000 マダインの指輪 ホーリーランス 黒魔道士の村・合成屋
ラピスラズリ 400 原石 デッドペッパー 黒魔道士の村・合成屋

合成に関するメモ

アイテムコンプリートを目指す場合。

ムーンストーン コンデヤ・パタの石板を使って交換してはいけない。スティルツキンから5555ギルで買う等して入手しよう
パールルージュ オークションで手に入るので合成してはいけない
デュエルクロー 素材となるドラゴンクローがゲーム中1個しかないため合成してはいけない。デスゲイズから盗もう

C# DirectShowで動画を再生する方法

当方Windows 10でVisual Studio Community 2019を使用しています。

参照の追加

C#のプロジェクトを右クリック→追加→COM参照を選択します。
f:id:taiyakisun:20210617180605p:plain

[ActiveMovie control type library]にチェックを入れ、OKを押します。
f:id:taiyakisun:20210617180821p:plain

もしActiveMovie control type libraryが存在しない場合などは次の方法でdllを追加してください。

[参照]→[参照]ボタン→C:\Windows\System32\quartz.dllを選択して、③が追加されたことを確認します。
f:id:taiyakisun:20210617181041p:plain

必要なパッケージ

using QuartzTypeLib;

コード

C#でフォームアプリケーションでプロジェクトを作成します。

GUI

デザイナーで以下のコンポーネントを追加します。
・Panel (名前:panel1)
・Button (名前:button1)
ここでは、ボタンを押すとpanelに動画が再生されるようにコードを書きます。

C#のコード

private FilgraphManager objFilterGraph = null;
private IBasicAudio objBasicAudio = null;
private IVideoWindow objVideoWindow = null;
private IMediaEvent objMediaEvent = null;
private IMediaEventEx objMediaEventEx = null;
private IMediaPosition objMediaPosition = null;
private IMediaControl objMediaControl = null;

private const int WM_APP = 0x8000;
private const int WM_GRAPHNOTIFY = WM_APP + 1;
private const int EC_COMPLETE = 0x01;
private const int WS_CHILD = 0x40000000;
private const int WS_CLIPCHILDREN = 0x2000000;

enum MediaStatus { None, Stopped, Paused, Running };
private MediaStatus currentStatus = MediaStatus.None;

private void button1_Click(object sender, EventArgs e)
{
    objFilterGraph = new FilgraphManager();

    // ここに固定で再生したい動画ファイルのフルパスを書く
    objFilterGraph.RenderFile(@"C:\temp\midori.avi");

    objBasicAudio = objFilterGraph as IBasicAudio;
    objBasicAudio.Volume = -1000;    // 音量を少し下げておく

    try
    {
        objVideoWindow = objFilterGraph as IVideoWindow;
        objVideoWindow.Owner = (int)panel1.Handle;
        objVideoWindow.WindowStyle = WS_CHILD | WS_CLIPCHILDREN;        
        objVideoWindow.SetWindowPosition(panel1.ClientRectangle.Left,
                                            panel1.ClientRectangle.Top,
                                            panel1.ClientRectangle.Width,
                                            panel1.ClientRectangle.Height);
    }
    catch (Exception ex)
    {
        objVideoWindow = null;
    }

    objMediaEvent = objFilterGraph as IMediaEvent;

    // メッセージの傍受 DirectShowを親ウィンドウに送信します
    objMediaEventEx = objFilterGraph as IMediaEventEx;
    objMediaEventEx.SetNotifyWindow((int)this.Handle, WM_GRAPHNOTIFY, 0);

    // ビデオまたはオーディオトラックを開始および停止する
    objMediaControl = objFilterGraph as IMediaControl;

    // 再生開始
    objMediaControl.Run();
    currentStatus = MediaStatus.Running;
}

フォーム終了時などに実行する解放処理は以下の通りです。

if (objMediaControl != null)
{
    objMediaControl.Stop();
}

currentStatus = MediaStatus.Stopped;

if (objMediaEventEx != null)
{
    objMediaEventEx.SetNotifyWindow(0, 0, 0);
}

if (objVideoWindow != null)
{
    objVideoWindow.Visible = 0;
    objVideoWindow.Owner = 0;
}

if (objMediaControl != null) objMediaControl = null;
if (objMediaPosition != null) objMediaPosition = null;
if (objMediaEventEx != null) objMediaEventEx = null;
if (objMediaEvent != null) objMediaEvent = null;
if (objVideoWindow != null) objVideoWindow = null;
if (objBasicAudio != null) objBasicAudio = null;
if (objFilterGraph != null) objFilterGraph = null;

一時停止する場合は以下のコードを実行します。

objMediaControl.Pause();

一時停止を再開する場合は以下のコードを実行します。

objMediaControl.Run();

動画を末尾まで再生したことを検知して止めるためのコードは以下の通りです。
メッセージプロシージャをオーバーライドして特定のメッセージだけ処理を追加する形にしています。

protected override void WndProc(ref Message m)
{
    if (m.Msg == WM_GRAPHNOTIFY)
    {
        int lEventCode;
        int lParam1, lParam2;

        while (true)
        {
            try
            {
                objMediaEventEx.GetEvent(out lEventCode,
                    out lParam1,
                    out lParam2,
                    0);

                objMediaEventEx.FreeEventParams(lEventCode, lParam1, lParam2);

                if (lEventCode == EC_COMPLETE)
                {
                    objMediaControl.Stop();
                    objMediaPosition.CurrentPosition = 0;
                    currentStatus = MediaStatus.Stopped;
                }
            }
            catch (Exception)
            {
                break;
            }
        }
    }

    base.WndProc(ref m);
}

トラックバー(シークバー)の設置

どうせなのでトラックバーも設置してしまいましょう。
トラックバー設置により、再生位置をクリックしたりドラッグしたりして、好きな位置に飛べるようにします。

GUIの設置

デザイナ画面でTrackbarを設置します。変数名はデフォルトのtrackBar1とします。

コード

button1_Click関数で再生を開始するときにトラックバーの設定コードを追加します。
まずトラックバーの取りうる値をMinimumとMaximumに設定します。
ここでは動画の秒数をMaximumに設定します。

private void button8_Click(object sender, EventArgs e)
{
    :
    // 再生開始
    objMediaControl.Run();
    currentStatus = MediaStatus.Running;

    // トラックバーの設定
    this.trackBar1.Minimum = 0;
    this.trackBar1.Maximum = (int)objMediaPosition.Duration;
    this.trackBar1.Value = 0;
    this.trackBar1.TickFrequency = 1;

再生中にトラックバーを更新する関数を作成します。

private void updateTrackBar()
{
    if (this.currentStatus == MediaStatus.Running && this.objMediaPosition != null)
    {
        this.trackBar1.Value = (int)objMediaPosition.CurrentPosition;
    }
    else
    {
        this.trackBar1.Minimum = 0;
        this.trackBar1.Maximum = 0;
        this.trackBar1.Value = 0;
    }
}

上述したトラックバー更新関数をコールするコードを追加します。
まずは動画の再生が完了したときにトラックバーを0に戻すため、WndProc関数にコードを追加します。

protected override void WndProc(ref Message m)
{
    :
    if (lEventCode == EC_COMPLETE)
    {
        :
        updateTrackBar();
    }
}

次に、1秒に1度トラックバーを更新するためにタイマーを設定し、そこからupdateTrackBar関数を呼び出します。

private void Form1_Load(object sender, EventArgs e)
{
    :
    // トラックバーの更新
    Timer trackbar_timer = new Timer();
    trackbar_timer.Interval = 1000;
    trackbar_timer.Enabled = true;
    trackbar_timer.Start();
    trackbar_timer.Tick += (sender, e) =>
    {
        if (this.currentStatus == MediaStatus.Running)
        {
            this.updateTrackBar();
        }
    };

続いて、マウスクリックとマウスの移動でシークバーを更新するようにします。
MouseDownとMouseMoveイベントハンドラを作成してください。

MouseDownについては、クリックされた場所とトラックバーの幅から比率を計算して、その場所に再生位置を設定するだけです。

private void trackBar1_MouseDown(object sender, MouseEventArgs e)
{
    if (this.currentStatus == MediaStatus.Running && this.objMediaPosition != null)
    {
        if (e.Button == MouseButtons.Left)
        {
            double pos = ((double)e.X / this.trackBar1.Width) * (this.trackBar1.Maximum - this.trackBar1.Minimum);

            // トラックバー
            this.trackBar1.Value = (int)(pos);

            // 動画再生位置
            this.objMediaPosition.CurrentPosition = pos;
        }
    }
}

MouseMoveについては、基本的にMouseDownと同じですが、範囲外にマウスをドラッグされた場合の対応コードを追加したものとなります。

private void trackBar1_MouseMove(object sender, MouseEventArgs e)
{
    if (this.currentStatus == MediaStatus.Running && this.objMediaPosition != null)
    {
        if (e.Button == MouseButtons.Left)
        {
            double pos = ((double)e.X / this.trackBar1.Width) * (this.trackBar1.Maximum - this.trackBar1.Minimum);

            try
            {
                if ((int)(pos) >= this.trackBar1.Minimum && (int)pos <= this.trackBar1.Maximum)
                {
                    // トラックバー
                    this.trackBar1.Value = (int)(pos);

                    // 動画再生位置
                    this.objMediaPosition.CurrentPosition = pos;
                }
            }
            catch(ArgumentException)
            {
                // 位置を超えて設定してしまった場合は例外が飛ぶが無視する
            }
            catch(Exception ex)
            {
                MessageBox.Show(ex.Message, "error");
            }
        }
    }
}

C#でデスクトップのアイコン情報を取得したり、位置を変更したりする方法

これによりアイコン位置を記憶して復元するなどの操作をすることができます。
工夫次第ではアイコンの自動整理なんかもできそうです。

エラー処理をいれていないので適宜実装お願いします。



GUI構成

サンプルとしてフォームアプリケーションで、ボタン「button1」とリストボックス「listBox1」を配置します。
button1を押すことで取得したアイコンの情報をlistBox1に表示します。

なお、使うかどうかわからないのですがアイコン情報をすべて取得している箇所があります。
ここはご参考で(DEBUG:と書いている箇所)



デスクトップのアイコン情報の取得

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Runtime.InteropServices;
enum WindowMessage
{
	WM_KEYDOWN = 0x0100,
}

public const uint PROCESS_VM_OPERATION = 0x8;
public const uint PROCESS_VM_READ = 0x10;
public const uint PROCESS_VM_WRITE = 0x20;
public const uint MEM_RESERVE = 0x2000;
public const uint MEM_COMMIT = 0x1000;
public const uint PAGE_READWRITE = 0x4;
public const int LVM_GETITEM = 0x1005;
public const int LVM_GETITEMPOSITION = 0x1010;
public const int LVM_SETITEMPOSITION = 0x100F;
public const uint MEM_RELEASE = 0x8000;

public const uint LVM_FIRST = 0x1000;
public const uint LVM_GETITEMCOUNT = LVM_FIRST + 4;
public const uint LVM_GETITEMW = LVM_FIRST + 75;

public const int LVIF_TEXT = 0x0001;

[DllImport("user32.dll")]
public static extern IntPtr FindWindow(string strclassName, string strWindowName);

[DllImport("user32", EntryPoint = "FindWindowEx")]
public static extern IntPtr FindWindowEx(IntPtr hWnd1, IntPtr hWnd2, string lpsz1, string lpsz2);

[DllImport("user32.dll")]
public static extern int SendMessage(IntPtr hWnd, uint wMsg, int wParam, int lParam);

[DllImport("user32.dll")]
public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);

[DllImport("kernel32.dll")]
public static extern IntPtr OpenProcess(uint dwDesiredAccess, bool bInheritHandle, uint dwProcessId);

[DllImport("kernel32.dll")]
public static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect);

[DllImport("kernel32.dll")]
public static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, IntPtr lpBuffer, int nSize, ref uint vNumberOfBytesRead);

[DllImport("kernel32.dll")]
public static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, IntPtr lpBuffer, int nSize, ref uint vNumberOfBytesRead);

[DllImport("kernel32.dll")]
public static extern bool VirtualFreeEx(IntPtr hProcess, IntPtr lpAddress, uint dwSize, uint dwFreeType);

[DllImport("kernel32.dll")]
public static extern bool CloseHandle(IntPtr hObject);

// アイコンアイテムの情報を所持する構造体
// 構造体の情報は→を参照 https://docs.microsoft.com/ja-jp/windows/win32/api/commctrl/ns-commctrl-lvitema
public struct LVITEM
{
	public int mask;
	public int iItem;
	public int iSubItem;
	public int state;
	public int stateMask;
	public IntPtr pszText;
	public int cchTextMax;
	public int iImage;
	public IntPtr lParam;
	public int iIndent;
	public int iGroupId;
	public int cColumns;
	public IntPtr puColumns;
	public IntPtr piColFmt;
	public int iGroup;
}

private void button1_Click(object sender, EventArgs e)
{
	GetIconPosition();
}

public static int MakeLParam(int wLow, int wHigh)
{
	return (((short)wHigh << 16) | (wLow & 0xffff));
}

private void GetIconPosition()
{
	// デスクトップのウィンドウハンドルを取得する
	IntPtr hWndDesktop; 
	hWndDesktop = FindWindow("Progman", "Program Manager");
	hWndDesktop = FindWindowEx(hWndDesktop, IntPtr.Zero, "SHELLDLL_DefView", null);
	hWndDesktop = FindWindowEx(hWndDesktop, IntPtr.Zero, "SysListView32", null);

        if (hWndDesktop == IntPtr.Zero)
        {
            // 壁紙を変更した場合等Program Manager→SHELLDLL_DefView→SysListView32ではなく
            // WorkerW→SHELLDLL_DefView→SysListView32になることがあるので、両方試す。
            // WorkerWは複数あるのでループして目的の物が見つかるまで探す。
            IntPtr hWorkerW = IntPtr.Zero;
            IntPtr hShellViewWin = IntPtr.Zero;

            do
            {
                hWorkerW = FindWindowEx(IntPtr.Zero, hWorkerW, "WorkerW", null);
                hShellViewWin = FindWindowEx(hWorkerW, IntPtr.Zero, "SHELLDLL_DefView", null);
            } while (hShellViewWin == IntPtr.Zero && hWorkerW != IntPtr.Zero);

            hWndDesktop = FindWindowEx(hShellViewWin, IntPtr.Zero, "SysListView32", null);
        }

	if (hWndDesktop == IntPtr.Zero)
	{
		MessageBox.Show("Desktop hwnd could not be retrieved.", "Error");
		return;
	}

	// アイコンの数を取得
	int iconCount = SendMessage(hWndDesktop, LVM_GETITEMCOUNT, 0, 0);

	// デスクトップ(explorer.exe)のプロセスIDを取得する
	uint dwProcessId;
	GetWindowThreadProcessId(hWndDesktop, out dwProcessId);

	// 取得したプロセスIDをオープンする
	IntPtr hProcess = OpenProcess(PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE, false, dwProcessId);
	if (hProcess == null)
        {
		MessageBox.Show("Desktop process could not be retrieved.", "Error");
		return;
        }

	// hProcessに関連するメモリーを確保する
	IntPtr pProcInfo = VirtualAllocEx(hProcess, IntPtr.Zero, 4096, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);

	for (int i = 0; i < iconCount; i++)
	{
		byte[] iconNameBytes = new byte[256];

		LVITEM[] vItem = new LVITEM[1];
		vItem[0].mask = LVIF_TEXT;
		vItem[0].iItem = i;
		vItem[0].iSubItem = 0;
		vItem[0].cchTextMax = iconNameBytes.Length;
		vItem[0].pszText = (IntPtr)((int)pProcInfo + Marshal.SizeOf(typeof(LVITEM)));	// LVITEMの後ろの領域を指す領域とする
		uint vNumberOfBytesRead = 0;

		// vItemに情報を書き込む
		// Marshal.UnsafeAddrOfPinnedArrayElement(vItem, 0)は配列vItemの0番目を意味する
		WriteProcessMemory(hProcess, pProcInfo, Marshal.UnsafeAddrOfPinnedArrayElement(vItem, 0), Marshal.SizeOf(typeof(LVITEM)), ref vNumberOfBytesRead);

		// インデックスiのアイテムを取得する
		SendMessage(hWndDesktop, LVM_GETITEMW, i, pProcInfo.ToInt32());
		ReadProcessMemory(hProcess, (IntPtr)((int)pProcInfo + Marshal.SizeOf(typeof(LVITEM))), Marshal.UnsafeAddrOfPinnedArrayElement(iconNameBytes, 0), iconNameBytes.Length, ref vNumberOfBytesRead);

		// byte配列からアイコンの名前を取得する
		string vText = Encoding.Unicode.GetString(iconNameBytes, 0, (int)vNumberOfBytesRead);
		// \0以降にもデータがある可能性があるため最初の\0(=文字列の末尾)まで抜き出してそれをアイコン名とする
		int endOfTextIndex = vText.IndexOf('\0');
		string IconName = vText.Substring(0, endOfTextIndex);
		
		// アイコン位置を取得する
		SendMessage(hWndDesktop, LVM_GETITEMPOSITION, i, pProcInfo.ToInt32());
		Point[] vPoint = new Point[1];
		ReadProcessMemory(hProcess, pProcInfo, Marshal.UnsafeAddrOfPinnedArrayElement(vPoint, 0), Marshal.SizeOf(typeof(Point)), ref vNumberOfBytesRead);

		string IconLocation = vPoint[0].ToString();

		// DEBUG:アイテム情報をすべて取得してみる
		SendMessage(hWndDesktop, LVM_GETITEM, i, pProcInfo.ToInt32());
		ReadProcessMemory(hProcess, pProcInfo, Marshal.UnsafeAddrOfPinnedArrayElement(vItem, 0), Marshal.SizeOf(typeof(LVITEM)), ref vNumberOfBytesRead);

		// リストボックスに情報を追加する
		listBox1.Items.Add("location:" + IconLocation + "  name:" + IconName + "   iItem:" + vItem[0].iItem);
	}

	// hProcessに関連するメモリーを解放する
	VirtualFreeEx(hProcess, pProcInfo, 0, MEM_RELEASE);

	CloseHandle(hProcess);

        // 最後にアイコン描画が更新されないことがあるため
	SendMessage(hWndDesktop, (uint)WindowMessage.WM_KEYDOWN, VK_F5, 0);
}



デスクトップのアイコンを移動させる

事前に[デスクトップのアイコン情報の取得]を参考にしてアイコン情報を取得しておいてください。
デスクトップのウィンドウハンドル(hWndDesktop)およびアイコンのインデックス(i)が必要になります。
ここでは例としてアイコン名がabcだったら座標(350, 50)へ移動させるものとします。

IconName = IconName.Replace("\0", "");
if (IconName.Equals("abc"))
{
    SendMessage(hWndDesktop, LVM_SETITEMPOSITION, i, MakeLParam(350, 50));
}



懸案

アイコン名をキーに位置を記憶しておき、それをもとにアイコン位置を復元する方法を考え付くと思いますが、Windowsはショートカットであれば同名のファイルを作成できてしまいます。
そうなると復元するときに異なる2つのアイコンを同じ場所に移動させることになり、おかしな挙動をすることになります。まぁほとんどないと思うので同名のファイルを作らないでといった注意書きをする程度でいいと思います。



Windows版のGoogle Chromeからの通知を切る方法

Windows版のChromeを使っていて、Youtubeなどからライブ開始の通知がぽろろーんという音ともにポップアップされるのがうざったいときがありますよね。この記事ではWindowsの設定で、Chromeからの通知を切る方法をご紹介します。

通知オフの手順

1.Windowsスタートボタン→設定(歯車マーク)を選ぶ
2.[システム]を選ぶ
3.[通知とアクション]を選ぶ
4.[送信元ごとの通知の受信設定]からGoogle Chromeのスイッチを「オフ」に設定する

時間帯で通知をオフにする方法

1.Windowsスタートボタン→設定(歯車マーク)を選ぶ
2.[システム]を選ぶ
3.[集中モード]を選ぶ
4.時間帯等で通知を受け取るかどうかの条件を設定する

bluetoothデバイスが不明なデバイスとして認識されてしまった場合の対処方法

Windows10の大型アップデート等でこの現象になることがあるようです。
ドライバーがインストールされない(コード28)、OSに互換性のあるドライバーがないと言われ、デバイスが使用できない状態に。

以下を実施することで解決できました。

1.デバイスマネージャーを開く
2.不明なデバイスを右クリックしてドライバーの更新を選ぶ
3.「コンピューターを参照してドライバーを検索」を選ぶ
4.「コンピューター上の利用可能なドライバーの一覧から選択します」を選ぶ
5.「Broadcom」の「BCM2033 Bluetooth 2.4....」を選んで「次へ」
6. ドライバーに互換性がないうんぬん言われるかもしれないが無視してインストールする

5.で選択するドライバーはそれっぽいのを選んでいますが、ダメな場合はいくつか試してみてください。Bluetoothは本来OSに元から入っているドライバーで十分動作するはずなので、おそらくはこの対処方法で解決すると思います。

ちなみに自分が持っているbluetoothバイスはUSB接続の↓です。
不明なデバイスは「BCM20702A0」という名前でした。
そのため上記5.でも頭にBCMが付いたドライバーを選択したのでした。
www.amazon.co.jp

突然Windows PCがお亡くなりなったときのレスキュー作業など

12年間使用していたマザーボードがお亡くなりになりました…。
突然のことだったのでディスクのバックアップはあまりとっていなかったのでここにレスキュー作業について書いていきたいと思います。適宜追記します。

ここでは新しいシステムドライブをCドライブ、レスキュー対象をDドライブとします。



Google Chromeのお気に入りの移行

1.まずChromeをインストールします。
2.以下のフォルダーをリネームします。

C:\Users\ユーザー名\AppData\Local\Google\Chrome\User Data\Default
 ↓
C:\Users\ユーザー名\AppData\Local\Google\Chrome\User Data\Default.old

3.以下の通りフォルダーをまるまるコピーします。

D:\Users\ユーザー名\AppData\Local\Google\Chrome\User Data\Default
 ↓
C:\Users\ユーザー名\AppData\Local\Google\Chrome\User Data\Default



CLIP STUDIO PAINTの設定の移行

1.まずCLIP STUDIO PAINTをインストールして、起動&ライセンス認証を完了させます。
2.CLIP STUDIO PAINTを終了します。
3.以下のフォルダーをリネームします。

C:\Users\Tatsuro\Documents\CELSYS
 ↓
C:\Users\Tatsuro\Documents\CELSYS.old

4.以下の通りフォルダーをまるまるコピーします。

D:\Users\Tatsuro\Documents\CELSYS
 ↓
C:\Users\Tatsuro\Documents\CELSYS

ただこれだけだと、クリスタ内のコンポーネントの位置などが復元できていないような…。



ドラゴンクエスト11(Steam)のセーブデータ移行

1.Steamでドラゴンクエスト11をインストールしておく
2.以下のフォルダーをリネームします。

C:\Users\taiyakisun\Documents\My Games\ドラゴンクエスト XI S
 ↓
C:\Users\taiyakisun\Documents\My Games\ドラゴンクエスト XI S.old

3.以下の通りフォルダーをまるまるコピーします。

D:\Users\Tatsuro\Documents\My Games\ドラゴンクエスト XI S
 ↓
C:\Users\Tatsuro\Documents\My Games\ドラゴンクエスト XI S



スタートアップに起動したいアプリケーションのショートカットを置く

C:\Users\taiyakisun\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup



「送る」に置きたいアプリケーションを追加する(自分の場合は秀丸)

以下のいずれかをエクスプローラーのパスに入力する。

shell:sendto
C:\Users\taiyakisun\AppData\Roaming\Microsoft\Windows\SendTo



プライバシーポリシー お問い合わせ