トップページ > 記事閲覧
GuruGuruSMFとDxlibの干渉
名前:8127 日時: 2018/05/01 17:42

DrawKeyInputStringの挙動 hティーティーp://dxlib.o.oo7.jp/cgi/patiobbs/patio.cgi?mode=view&no=4396 で問題の本質がDrawKeyInputStringではなかったので別スレ立てさせていただきました。 GuruGuruSMFという、音声再生ライブラリとdxライブラリを併用しているのですが、 GuruGuruSMFのサイト様 : hティーティーp://gurugurusmf.migmig.net/ これらの初期化と後処理関数を呼ぶ順番の微妙な違いでDrawKeyInputStringの挙動がおかしくなったりするようです。 GuruGuruSMFのバージョンはver.4.0.6最新版、cppのスタティックリンク版使用です。 再現コードを示します。 (GuruGuruSMF4_Cpp_Static.cppをプロジェクトに含め、GuruGuruSMF4_Cpp.hとGuruGuruSMF4.libへのパスを通し、 GuruGuruSMF4.dllを適切な場所に置いた状態で) main.cppの内容: #pragma comment (lib,"GuruGuruSMF4.lib") #include <iostream> #include "DxLib.h" #include "GuruGuruSMF4_Cpp.h" void dxlibInit() { ChangeWindowMode(true); //ウインドウモードにする SetWindowSize(640, 480); if (DxLib_Init() == -1) // DXライブラリ初期化処理 { return; // エラーが起きたら直ちに終了 } SetDrawScreen(DX_SCREEN_BACK); //描画先を裏画面に設定 } void ggsInit() { GGSINITIALIZE(); GGS->OpenDevice(GuruGuruSmf::Device::DirectMusic, NULL); } void ggsEnd() { GGS->CloseDevice(); //ここの順が逆で記事修正しましたがどっちでも影響ないです GGSFREE(); } void update() { char String[256]; int InputHandle; // キー入力ハンドルを作る(キャンセルなし全角文字有り数値入力じゃなし) InputHandle = MakeKeyInput(255, FALSE, FALSE, FALSE); // 作成したキー入力ハンドルをアクティブにする SetActiveKeyInput(InputHandle); // キー入力終了待ちループ // (ProcessMessageをループごとに行う) while (!ProcessMessage()) { // 入力が終了している場合は終了 if (CheckKeyInput(InputHandle) != 0) break; // 画面の初期化 ClearDrawScreen(); // 入力モードを描画 DrawKeyInputModeString(640, 480); // 入力途中の文字列を描画 DrawKeyInputString(0, 0, InputHandle); // 裏画面の内容を表画面に反映させる ScreenFlip(); } // 入力された文字列を取得 GetKeyInputString(String, InputHandle); // 用済みのインプットハンドルを削除する DeleteKeyInput(InputHandle); // 画面の初期化 ClearDrawScreen(); // 入力された文字列を画面に表示する DrawString(0, 0, "あなたが入力した文字列は", GetColor(255, 255, 255)); DrawString(0, 16, String, GetColor(255, 255, 255)); // 裏画面の内容を表画面に反映させる ScreenFlip(); // キー入力待ち WaitKey(); } int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) { ??????? ?????? update(); ?????? ????? return 0; } main.cppの内容(終わり): WinMainの部分ですが、 (A) ggsInit(); dxlibInit(); update(); DxLib_End(); ggsEnd(); の場合、DrawKeyInputStringの入力中の全角文字やDrawKeyInputModeStringの文字がが表示されない不具合が発生する。 (B) dxlibInit(); ggsInit(); update(); ggsEnd(); DxLib_End(); の場合、DxLib_End()実行時に不正アクセスで落ちる(Dxlibのバージョンver3.18以降、それ以前では正常に動作) 0x74F8C22F (msctf.dll) で例外がスローされました (TestDxlibApp.exe 内): 0xC0000005: 場所 0x730E2388 の読み取り中にアクセス違反が発生しました (C) dxlibInit(); ggsInit(); update(); DxLib_End(); ggsEnd(); この順番だと何故か正常に動作、しかしInitとEndの順番が一貫しておらず気持ち悪く、今後も動くかが不安 となります。私も何が原因かよく分かりません・・・ 何かわかる方はおりませんでしょうか・・・
メンテ

Page: 1 |

Re: GuruGuruSMFとDxlibの干渉 ( No.1 )
名前:gdrop 日時:2018/05/01 21:33

Ver.3.19a(※最新TEMP版ではありません)ですが、確かに(A)(B)(C)が上記のようになります。 んで #include "Objbase.h" を追加して int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) { ::CoInitialize(NULL); (A)でも(B)でも ::CoUninitialize(); } のように CoXXXXX ではさめば、エラーなし、IMEもOKになりました。
メンテ
Re: GuruGuruSMFとDxlibの干渉 ( No.2 )
名前:8127 日時:2018/05/02 08:09

gdrop様、ご返信ありがとうございます。 CoXXXXXではさんだところ、期待通りの挙動になることをこちらでも確認いたしました。 恐らくDxlibとGuruGuruSMFの双方がCOMに依存していて、初期化/終了処理が重複することが不具合の原因なのだと思いましたが もしよろしければなぜこうすれば期待通りになるのか理由を教えていただけないでしょうか? ttp://dxlib.o.oo7.jp/cgi/patiobbs/patio.cgi?mode=past&no=2826 ttp://dxlib.o.oo7.jp/cgi/patiobbs/patio.cgi?mode=past&no=2966&p=1 等を見るとDxlib_Init()で::CoInitializeEx()が呼ばれるようなのでなぜ自前で呼ぶと挙動が変わるのかが気になります。
メンテ
Re: GuruGuruSMFとDxlibの干渉 ( No.3 )
名前:gdrop 日時:2018/05/02 11:44

DxLib ---> CoInitializeEx(NULL, COINIT_APARTMENTTHREADED) ---> STA GuruGuruSMF ---> CoInitializeEx(NULL, COINIT_MULTITHREADED) ---> MTA で初期化されているので、DxLibのモード、つまりSTAでそろえりゃいいのかなと思ったくらいです。 CoInitialize(NULL) で最初にSTAに設定すれば、その後DxLibやGuruGuruSMFが内部でCoInitializeExを実行しても S_OK以外のエラーになって無視されます。(つまりSTAのまま) ※ちなみに、WinMainの最後に追加した CoUninitialize() は不要です。(見た目の演出的にはさんだだけ) GuruGuruSMFはソースが公開されているので改造してみましたが  @CoInitializeEx/CoUninitialize を全てコメントアウトする (※DxLibに任せる)  ACoInitializeEx(NULL, COINIT_MULTITHREADED) を CoInitializeEx(NULL, COINIT_APARTMENTTHREADED) に全て変更する のどっちもやってみましたがちゃんとMIDIが鳴りました。
メンテ
Re: GuruGuruSMFとDxlibの干渉 ( No.4 )
名前:8127(解決) 日時:2018/05/02 22:19

gdrop様、詳細な解説ありがとうございます。 なるほど、DxLibは既にCoInitializeされている場合は無視する挙動だったのですね。それならば納得がいきました。 今回は長々と付き合っていただきありがとうございました。 MIDIもちゃんと再生されています。
メンテ
Re: GuruGuruSMFとDxlibの干渉 ( No.5 )
名前:gdrop 日時:2018/05/02 23:12

■8127様  ちょっと訂正です。  GuruGuruSMF はCOM初期化のエラーチェックが無いのでそのまま通過します。  DxLibではCOM初期化の戻り値をチェックしているので、STA/MTAの異なるモードで初期化しようとした場合はログに  「COMの初期化... 失敗」と書きますが、DxLib_Init()自体は失敗扱いではないので、そのまま進みます。  ※同じモードで初期化する場合も戻り値はエラーですが、FAILED(hr)は通過するエラーなので成功扱いです。 ■管理人様  COMの初期化の際にはログに成功/失敗が書き込まれますが、アプリ終了の際のCOMの終了ではログには何も書き込まれません。  DxWindow.cpp   // COMインターフェースを終了する   extern int TerminateCom( void )  は呼ばれないのでしょうか?
メンテ
Re: GuruGuruSMFとDxlibの干渉 ( No.6 )
名前:管理人 日時:2018/05/04 00:38

> gdropさん > COMの初期化の際にはログに成功/失敗が書き込まれますが、アプリ終了の際のCOMの終了ではログには何も書き込まれません。 すみません、TerminateCom は呼ばれていたのですが、バグでこの関数が呼ばれる前に WinData.ComInitializeFlag が FALSE になってしまっていて CoUninitialize が呼ばれていませんでした 修正版をアップしましたので、よろしければお使いください m(_ _;m https://dxlib.xsrv.jp/temp/DxLibVCTest.zip // Windows版 VisualC++ 用 https://dxlib.xsrv.jp/temp/DxLibBCCTest.zip // Windows版 BorlandC++ 用 https://dxlib.xsrv.jp/temp/DxLibBCC2Test.zip // Windows版 C++ Builder 10.1 Berlin 用 https://dxlib.xsrv.jp/temp/DxLibGCC_MinGWTest.zip // Windows版 MinGW 用 https://dxlib.xsrv.jp/temp/DxLibDotNet.zip // Windows版 .NET用 https://dxlib.xsrv.jp/temp/DxLibMakeTest.zip // ソース (中身を既存のライブラリのファイルに上書きして、BCCをお使いの 場合は『再構築』を、VCをお使いの場合は『リビルド』を、 Dev-C++をお使いの方は「Rebuild All(Ctrl+F11)」をして下さい)
メンテ
Re: GuruGuruSMFとDxlibの干渉 ( No.7 )
名前:gdrop(解決) 日時:2018/05/04 08:07

ご対応ありがとうございます。COM終了がログに記録されるのを確認いたしました。 ※自分のスレではないので恐縮ですが、解決マークを付けさせていただきます。
メンテ

Page: 1 |

題名
名前
コメント
パスワード (記事メンテ時に使用)

   クッキー保存