質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.10%

WPFアプリケーションをdll化して、VC++で起動したい

解決済

回答 1

投稿

  • 評価
  • クリップ 1
  • VIEW 219

taruto_11

score 1

前提・実現したいこと

WPF(C#,MVVMパターン)で、自作ゲーム(C++)のデバッグ中に値を変更出来るGUIを作成しています。
このGUIをdllにして、C++側で自作ゲームと一緒に起動したいと考えています。
WPF側の関数をDllExportでC++側に表示して使用する所までは出来ましたが、以下のエラーが発生します。

発生している問題・エラーメッセージ

ハンドルされない例外が 0x75E6C632 (KernelBase.dll) で発生しました(Game.exe 内): 0xE0434352 (パラメーター: 0x80131509, 0x00000000, 0x00000000, 0x00000000, 0x72810000)。

該当のソースコード

    public partial class App : Application
    {
        protected override void OnStartup( StartupEventArgs e )
        {

            base.OnStartup( e );

            //ウィンドウをインスタンス化します
            var window = new MainView();

            //ウィンドウに対する ViewModel をインスタンス化します
            var view_model = new MainViewModel();

            //ウィンドウに対する ViewModel をデータコンテキストに指定します
            window.DataContext = view_model;

            //ウィンドウを表示する
            window.Show();

            //ウィンドウを最前面に表示する
            window.Activate();
            //ウィンドウを最前面に保持する
            window.Topmost = true;
        }

        [DllExport]
        public static void Create()
        {
            GUI.App app = new GUI.App();

            app.Run();//ここでエラーが発生する
        }

    }
    const TCHAR* pemodule = _T("./GUI/bin/Debug/x86/GUI.dll");
    HMODULE lib = LoadLibrary(pemodule);

    typedef void(__cdecl *Create)();

    auto create = reinterpret_cast<Create>(GetProcAddress(lib, "Create"));

    //window生成
    create();

試したこと

WPF側の関数読み取りは成功しています。( Debug.WriteLine("OK")  等は通るため)
「App.xaml があると失敗する」と書いてあったサイトがあったので試しましたが、ダメでした。
色々書き換えた結果、 app.Run() と var window = new MainView(); の2つでエラーが発生することが分かりました。
DllExport ではなく C++/CLI で試しましたが、こちらでもダメでした。 (コードは残ってないです、すみません。)
dll内をデバッグ出来るようにしたかったのですが、今の所は出来ていません。

補足情報(FW/ツールのバージョンなど)

Visual Studio 2015

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • Zuishin

    2019/08/14 23:11

    C++/CLI で新しく作ってコードを残すのがいいと思います。

    キャンセル

回答 1

check解決した方法

0

すみません、自己解決しました。
DllExportを使用した方法は一旦止めて、C++/CLIで再度行いましたが、私の環境では使用できませんでした。(チーム内の環境を変える必要があったため)
あまり詳しくは調べてないのですが、COMを使用した方法で解決出来ました。
特に参考にさせて頂いたサイトを貼っておきます。
コードは貼ってあるサイトを参考にしています。(どのように改良したか残してあります。活用してください。)

参考にさせて頂いたサイト

https://archive.fo/SWmZa
https://www.84kure.com/blog/2014/07/17/c-cからcのdllを呼ぶ方法/

using GUI.ViewModels;
using GUI.Views;
using System.Diagnostics;


namespace GUI
{

    //++ C++側に見せる関数を記述するクラス
    public class Link
    {

        #region ウィンドウ生成

        private GUI.App app = new GUI.App();

        public void Create()
        {
            app.Run();
        }

        public void Delete()
        {
            app.Shutdown();
        }

        #endregion ウィンドウ生成

    }


}
//!++ 追加
#pragma comment(lib, "comsupp.lib")
#pragma comment(lib, "comsuppw.lib")


#include <Windows.h>
#include <comutil.h>
#include <objbase.h>

//グローバル変数
IDispatch *pIDisp = NULL;
IUnknown *pIUnk = NULL;

//プロトタイプ宣言
int Init(void);
long Finalize(void);
//int Sum(int p_Number1, int p_Number2);
void CreateGUIWindow();

int main()
{
    //変数宣言
    int l_Result = 0;

    //初期処理
    Init();

    //合計処理
    //l_Result = Sum(5, 7);
    CreateGUIWindow();

    //後処理
    Finalize();


    return 0;
}

//***************************************************************************//
//初期化関数
//***************************************************************************//
int Init(void)
{
    CLSID clsid;

    //COM初期化
    CoInitialize(0);

    HRESULT hr = S_OK;

    //ProcIDからCLSIDを取得
    //! (ネームスペース名.クラス名)
    hr = CLSIDFromProgID(L"GUI.Link", &clsid);
    if (FAILED(hr))
    {
        return -1;
    }

    //Instanceの生成
    hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, IID_IUnknown, (void**)&pIUnk);
    if (FAILED(hr))
    {
        return -2;
    }

    //インターフェースの取得(pIDispは共通変数)
    hr = pIUnk->QueryInterface(IID_IDispatch, (void**)&pIDisp);
    if (FAILED(hr))
    {
        return -3;
    }

    //正常終了
    return 0;
}

//***************************************************************************//
//後始末処理
//***************************************************************************//
long Finalize(void)
{
    pIDisp->Release();
    pIUnk->Release();
    CoUninitialize();
    return 0;
}

//***************************************************************************//
//合計処理呼出処理
//***************************************************************************//
//int Sum(int num_1, int num_2)
void CreateGUIWindow()
{
    //DISPIDの取得(関数名の設定)
    DISPID dispid = 0;
    OLECHAR *Func_Name[] = { L"Create" };//? Create : 呼び出したい関数
    HRESULT h_result = pIDisp->GetIDsOfNames(IID_NULL, Func_Name, 1, LOCALE_SYSTEM_DEFAULT, &dispid);
    if (FAILED(h_result))
    {
        return;
    }

    //パラメータ作成
    //! 引数の設定
    DISPPARAMS parameter;
    memset(&parameter, 0, sizeof(DISPPARAMS));

    parameter.cNamedArgs = 0;
    parameter.rgdispidNamedArgs = NULL;
    parameter.cArgs = 0; //! 呼び出す関数の引数の数

    //+ 引数設定  詳しくは http://marupeke296.com/IKDADV_CPP_VARIANT.html 
    //! 呼び出す引数分、配列を確保する
    //! (順番に注意…逆になる)
    //VARIANTARG* pVarg = new VARIANTARG[parameter.cArgs];

    ////+ 後ろから1つ目の引数設定
    ////? vt : 引数の型によって種類を変える必要がある
    ////? intVal : 引数がint型であるため
    //pVarg[0].vt = VT_I4;
    //pVarg[0].intVal = num_2;

    ////+ 後ろから2つ目の引数設定
    //pVarg[1].vt = VT_I4;
    //pVarg[1].intVal = num_1;

    ////+ 設定した引数分の情報を格納する
    //parameter.rgvarg = pVarg;

    //! 関数の結果が入っている
    //VARIANT vResult;
    //VariantInit(&vResult);

    //呼び出し
    //!? nullptr : 元はvResultが入っていました
    pIDisp->Invoke(dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD, &parameter, nullptr, NULL, NULL);

    //delete[] pVarg;

    //return vResult.intVal;
}

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.10%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る