• ベストアンサー

アンマネージDLLで、ダイアログを表示する方法

現在、Visual Studio 2005の、Visual C#、C++/CLI、MFCを使ったシステムを構築しています。 具体的には、MFCで書かれた(拡張DLL)でダイアログを表示。これをC++/CLIでラップし、C#から呼び出して使いたいと思っております。 そこで、http://soudan1.biglobe.ne.jp/qa3834982.htmlを参考にして、以下のように作ったのですが、DLL内のdlg.DoModal()のコールで、 AfxGetResourceHandle()でASSERTが発生してしまいます。 //// C#のフォーム using LogGphWrap; namespace DllTestApp { public partial class Form1 : Form { private void button1_Click(object sender, EventArgs e) { Wrapdll.Wrapper.DlgOpen(this.Handle.ToInt32()); } } } //// Wrapdll(CRLのクラスライブラリ) [Wrapdll.h] [DllImport("MFCdll.dll")] bool dspDlg(int hDib); namespace Wrapdll { public ref class Wrapper { public: static bool DlgOpen(int hDib) { return ( dspDlg(hDib) ) ; } }; } //// MFCdll(MFCの拡張DLL) [MFCdll.h] #include "resource.h" bool dspDlg(HWND hDib); //// MFCdll(MFCの拡張DLL) [MFCdll.cpp] extern "C" int APIENTRY DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) { :   デフォルトのまま : } bool dspDlg (HWND hDib) { AFX_MANAGE_STATE(AfxGetAppModuleState()); AfxMessageBox(_T("ちょっとお試し"), 0, 0) ;  CTestDlg *dlg = new CTestDlg(CWnd::FromHandle(hDib));  dlg->Create(IDD_DIALOG) ; <====この部分でASSERTが発生!!  return TRUE ; } ご存知の方がいらっしゃれば、ご教授ください。 よろしくお願いします。

質問者が選んだベストアンサー

  • ベストアンサー
  • takupy
  • ベストアンサー率100% (3/3)
回答No.1

こんにちは。 異なる言語を使ったプログラムは組んだことないのですが、多分同じではないかと思ってレスさせてください。 質問で書かれているプログラムでは、恐らくDLL側にリソースエディタでダイアログを作成されたと思いますが、DLL側から参照使用としているリソースはそのままではアプリケーション側(呼出元)のリソースを参照としているためにASSERTが発生します。DLL側にセットされたリソースを読もうとはしていません。 これを回避するためにはDLLのインスタンスハンドルを取得して直接読むようにするのが良いと思います。 HMODULE  hModule ; HRSRC   hResource ; hModule    = ::GetModuleHandle( モジュール名 ) ; hResource    = ::FindResource( hModule, MAKEINTRESOURCE( リソースID ), RT_DIALOG ) ; m_hResGlobal  = ::LoadResource( hModule, hResource ) ; m_hResGlobalをクラスのメンバーとして保持しておき、 CTestDlg::Create( CWnd* const lpwndParent ) {    CDialog::CreateIndirect( m_hResGlobal, lpwndParent ) ; } とすればちゃんと表示されると思います。 各関数についてはヘルプを見てください。

take_716
質問者

お礼

takupyさん、レス有難うございました。 ご指摘のように、インスタンスハンドルを取得したのですが、 やはり、ASSERTが発生してしまいます。 デバックでチェックする限りでは、モジュールもリソースも 取得できているようなのですが・・・ HMODULE  hModule ; HRSRC   hResource ; hModule    = ::GetModuleHandle( _T("MFCdll") ) ; hResource    = ::FindResource( hModule, MAKEINTRESOURCE(IDD_DIALOG), RT_DIALOG ) ; m_hResGlobal  = ::LoadResource( hModule, hResource ) ; CTestDlg::Create( CWnd* const lpwndParent ) {    CDialog::CreateIndirect( m_hResGlobal, lpwndParent ) ;<=====この要求時のAfxGetResourceHandle()でASSERTが発生・・・ }

その他の回答 (1)

  • redfox63
  • ベストアンサー率71% (1325/1856)
回答No.2

マネージドから呼び出した場合にMFC周りの初期化がうまくいっていないのが原因のようですよ VC++で Win32APPやMFCEXEで お作りになったMFCDLL.DLLのdispDlgを呼ぶようなアプリを作ってみてはいかがでしょう 多分アサートはされないはずです このとき dlg->Createから呼ばれたCDialog::Createで呼ばれる _AfxCheckDialogTemplate関数でAfxFindResourceHandleを呼び出します この中でAfxGetModuleStateで取得した pModuleStateメンバーの値と マネージから呼ばれた場合とで比較してみましょう マネージから呼ばれた場合 m_hCurrentResourceHandleなどのメンバーがNULLになっているようです

take_716
質問者

お礼

redfox63さん、有難うございます。 いろいろと試してみたのですが、結局、 マネージDLLで作り直す方向で考えています。 ご指導有難うございました。

関連するQ&A

  • CXXXApp::InitInstance内でDLLの呼び出し

    CXXXApp::InitInstance内でDLLの呼び出しをしています。 呼び出すDLLは、MFCの共有DLLで作成しました。 DLLの内容は、単純にダイアログを表示しているだけです。 そこで、問題が発生しています。 DLLを呼び出すと、アクセスバイオレイションで落ちてしまいます。 どうも、ダイアログの親ウインドウが無いのが問題のようです。どうすれば解決するでしょうか? Exe--------------- BOOL CXXXXApp::InitInstance() { HINSTANCE hDll = NULL; int (__stdcall *lpdlg)( ); hDll = ::LoadLibrary("test.dll"); (FARPROC&)lpdlg = ::GetProcAddress(hDll, "dlgtest"); (*lpdlg)( ); ::FreeLibrary(hDll); } DLL内--------------------- AFX_MANAGE_STATE(AfxGetStaticModuleState()); AfxSetResourceHandle(AfxGetResourceHandle()); CTestDlg dlg; dlg.DoModal();

  • DLLでダイアログ

    VC++6.0にてMFCを使うDLLを作成しています。 関連HPを参考になんとかDLLを作ることが出来ました。 そこで今度はDLL側でダイアログボックスを作成して表示させようとしたところうまくいきません。 エラーも無くスルーされてしまいます。 こういう使い方は出来ないのでしょうか。 ↓DLL関数のソースファイルです。 ---------------------------------------------- #include "StdAfx.h" #include "Defs.h" #include "Func.h" #include "resource.h" #include "testdlg.h" #include "dlg2.h" int WINAPI DllFunc( CString &p_rcStr, CWnd *p_pcWnd ) { TestDlg dlg; Cdlg2 dlg2; dlg.ps = p_rcStr; dlg2.DoModal();//なにも出ない AfxMessageBox(p_rcStr);//コレはOK dlg.DoModal();//何もでない return TRUE; } --------------------------------------------

  • VC++.NET DLLからのダイアログの表示

    こんばんは。 VC++.NETでDLLを作成しました。 内容はダイアログを表示させるだけの単純なもので DLLの種類はMFC拡張DLLで作成しました。 (CDIALOGを継承したクラスTESTDIALOGのコンストラクタ、デストラクタがあるだけのもの) これをテスト用の単純なMFCアプリケーションで呼び出したところ ダイアログを表示させることができましたが 別の複雑なアプリケーション(DLLからDLLを呼ぶなどしている)で 呼び出したところダイアログが表示されません。 コンパイルエラーなどもでないし 何がいけないのか分かりません。 呼び出し側ではメニューにイベントハンドラを作ってそこで TESTDIALOG dlg; dlg.DoModal(); としているだけなのですが・・・ (デバッガで追ったところMFCのdlgcore.cppのCDialog::DoModalの m_lpDialogTemplateNameが不適切なptrとなる辺りに原因はありそうなのですが何故そうなるのかわかりません。) どなたかダイアログが表示されない原因がお分かりになる方 よろしくお願いします。

  • メインダイアログを表示させずにファイル選択ダイアログを表示

    VC++2005のMFCダイアログベースでプログラムを作成しています。 自動生成されたプログラムを何も変更しないまま実行すると、 メインのダイアログが表示されますが、 そのダイアログを表示させずに、ファイル選択ダイアログを表示させたいのです。 自分で実装しビルド実行したところ、期待動作をしましたが、 ファイル選択ダイアログを閉じた後に、画像のようなエラーが発生してしまいます。 エラーを発生させず、期待動作をさせる良い実装方法をご存知の方おられましたら、 ご教示お願い致します。 【変更実装(エラー発生)】 BOOL CtestApp::InitInstance() { … CtestDlg dlg; m_pMainWnd = &dlg; // INT_PTR nResponse = dlg.DoModal(); //コメントアウト dlg.OnBnClickedButton1(); //ファイル選択ダイアログを表示する関数 //if (nResponse == IDOK) //コメントアウト //else if (nResponse == IDCANCEL) //コメントアウト … } void CtestDlg::OnBnClickedButton1() { CFileDialog ReadDlg( TRUE, NULL, "*.txt", OFN_HIDEREADONLY | OFN_FILEMUSTEXIST, "txtファイル(*.txt)", this ); … }

  • 実行時dllを動かしたい

    のですがサイトで見つけたdllの作り方を見て 大人気の無償Borland C++5.51を使って //mydll.cpp #include <windows.h> BOOL __stdcall MyBeep() { return MessageBeep(0); } int __stdcall MyMessageBox(LPCTSTR lpszMessage) { return MessageBox(NULL,lpszMessage,"",0); } を bcc32 -WD mydll してmydll.dllを作り //myexe.cpp #include <windows.h> typedef int (__stdcall *pMyFunction)(LPCTSTR); int APIENTRY WinMain(HINSTANCE,HINSTANCE,LPSTR,int) { HINSTANCE hLib; pMyFunction pMyMessageBox; hLib = LoadLibrary("mydll.dll"); if(hLib) { pMyMessageBox=(pMyFunction)GetProcAddress(hLib,"MyMessageBox"); if(pMyMessageBox)(*pMyMessageBox)("HELLO!!"); FreeLibrary(hLib); } return 0; } を bcc32 -W myexe してmyexe.exeを作り myexe.exe したのですがHELLO!!がでません。 どうしたらいいのでしょうか?

  • ダイアログ表示後に1回だけ実行

    ダイアログベースのプログラムで、ダイアログを表示後にメッセージボックスを表示しようとして、下のプログラムのようにしたのですがダイアログが表示される前にメッセージボックスが表示されてしまいます。 ダイアログが表示された直後に1回だけ表示されるようにするにはどうすればいいですか? #include<Windows.h> #include "resource.h" HINSTANCE hinst; INT_PTR CALLBACK dlgproc(HWND,UINT,WPARAM,LPARAM); int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow) { hinst=hInstance; DialogBox(hinst,TEXT("mydlgmain"),NULL,dlgproc); } INT_PTR CALLBACK dlgproc(HWND hwnd,UINT msg,WPARAM wp,LPARAM lp) { TCHAR moji[]=TEXT("ダイアログ表示"); switch(msg) { case WM_INITDIALOG: MessageBox(hwnd,moji,TEXT(""),MB_OK); return(INT_PTR)TRUE; case WM_CLOSE: EndDialog(hwnd,LOWORD(wp)); return (INT_PTR)TRUE; } return(INT_PTR)FALSE; } --- 実行環境 --- Microsoft Visual C++ 2010 Express WIN32 ユニコードビルド C言語

  • MFCのexeのプログラムを MFCのdllに書き換えたい

    VC++6.0を使用しています 新規作成 MFC AppWizard(exe) 新規 OK [ステップ1] ダイアログベース 次へ [ステップ2/4] 次へ [ステップ3/4] 次へ [ステップ4/4] 終了 で作られた、雛型のexeをそっくりMFCのDLLに書き換えたい と考えています exeで作られたアプリを他のユーザーがVB6.0からDLLとして呼び出したいので書き換えて欲しいと頼まれました MFCのDLLも雛型は簡単に出来上がるのですが 以下の関数を独立したオブジェクトにして、VB6.0からDLLの関数VBFUNC1として呼び出したいのですが、VBから呼び出すと AfxEnableControlContainer();でアサートで引っ掛かってしまいます ダイアログを使用したMFCのEXEをDLLとして使う場合の、コーディングについてご指南ください BOOL CAaaApp::VBFUNC1() //BOOL CAaaApp::InitInstance() {   AfxEnableControlContainer(); #ifdef _AFXDLL   Enable3dControls(); #else   Enable3dControlsStatic(); #endif   CAaaDlg dlg;   m_pMainWnd = &dlg;   int nResponse = dlg.DoModal();   if (nResponse == IDOK)   {   }   else if (nResponse == IDCANCEL)   {   }   return FALSE; }

  • DLLをGetProcAddress()で実行できない。

    dllの操作の練習をしております。以下のソースのどこがおかしいのでしょうか? add.dllの内容は単にa+bの結果をメッセージボックスに表示させるだけの処理です。add.lib(インポートライブラリ)をリンクさせればうまく動きます。 しかし、GetProcAddress()を使って明示的にdllを呼び出そうとすると、コンパイルエラーで ADD(hWnd,5,5); の行に 「int (__stdcall *)(void)' : 実引数が多すぎます。」 となります。このメッセージの意味もわかりません。 以下のソースのどこがおかしいのでしょうか?コンパイラはVC++6.0でOSはWin2000です。 #include<windows.h> void CALLBACK ADD(HWND hwnd,int a, int b); //ウィンドウプロージャ(ここは別に普通) LRESULT CALLBACK WndProc(HWND hWnd , UINT msg , WPARAM wp , LPARAM lp) { switch (msg) { case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hWnd , msg , wp , lp); } int WINAPI WinMain(HINSTANCE hInstance , HINSTANCE hPrevInstance , PSTR lpCmdLine , int nCmdShow) { static FARPROC ADD;  //あやしい HWND hWnd; MSG msg; WNDCLASS winc;     //ウィンドウを作る処理 //~(省略)~ /****明示的にdllを呼び出す****/ ADD = GetProcAddress( LoadLibrary(TEXT("add.dll")) , TEXT("ADD")); ADD(hWnd,5,5); /****************************/ while (GetMessage(&msg , NULL , 0 , 0 )) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } お願いします。

  • VC++&グローバルフックについて質問です

    vc++2008,Windows Vistaの環境でプログラムを作成しています。 以下、aが押されたら、設定したhWndにWM_KEYDOWN,VK_LEFTのメッセージを送るプログラムのつもりで書きました。 http://www.shos.info/develop/cwin/tipswin.html#windows008 を参考にしています。 しかし、dllにしてWinMainで呼び出したのですが動作しません。 エラーも出ないのでなぜ動かないのかがわかりません。 このプログラムをちゃんと動かすにはどうしたらいいでしょうか。 どうかご指摘ください。よろしくお願いします。 //hook.h #ifdef HOOKAPI #else #define HOOKAPI extern "C" __declspec(dllimport) #endif HOOKAPI HINSTANCE _hInstance; HOOKAPI HHOOK _hHook; HOOKAPI HWND _hWnd; HOOKAPI BOOL Set(HWND hWnd); HOOKAPI void Reset(); //hook.cpp #include <windows.h> #define HOOKAPI extern "C" __declspec(dllexport) #include "hook.h" #pragma data_seg(".share") HHOOK _hHook = NULL; HWND _hWnd = NULL; HINSTANCE _hInstance; #pragma data_seg() #pragma comment(linker, "/section:.share,rws") LRESULT CALLBACK HookProc(int nCode, WPARAM wParam, LPARAM lParam) { /* ここでは 'A' が押されたら予め設定済みの _hWnd にメッセージを送る */ if (nCode >= 0 && nCode != HC_NOREMOVE && wParam == 'A') { PostMessage(_hWnd, WM_KEYDOWN, VK_LEFT, 0); CallNextHookEx(_hHook, nCode, wParam, lParam); return 1; } return CallNextHookEx(_hHook, nCode, wParam, lParam); } BOOL Set(HWND hWnd) { /* キーのフック */ _hHook = SetWindowsHookEx(WH_KEYBOARD, (HOOKPROC)HookProc, _hInstance, 0); /* ここで hInstance は DLL のインスタンス ハンドル */ _hWnd = hWnd; return (_hHook != NULL); } void Reset() { if (_hHook != NULL) { UnhookWindowsHookEx(_hHook); _hHook = NULL; } }

  • C# COM DELL へコールバックを設定したい

    MFCとC# COM DELLのプログラムを行ってます。 今回、MFCからC#COM DLLへコールバック関数を設定して C# COM DLLからそのコールバックを呼び出したいですが、どうしてもうまくいきません。 コードを記述します。どうか助けてください。 ------------------------------------------------------------------ MFC C++ delegate bool CallBack(int hwnd, int lParam); class CMyDlg : public CDialog { Init() { cpi = NULL; CoInitialize(NULL); HRESULT hr = CoCreateInstance(CLSID_InterfaceImplementation, NULL, CLSCTX_INPROC_SERVER, IID_IManagedInterface, (LPVOID*)&cpi); retval = 0; if (FAILED(hr)) { printf("Couldn't create the instance!... 0x%x\n", hr); } else { CallBack^ myCallBack = gcnew CallBack(&Report); cpi->SetCallback( myCallBack ); } } static bool Report(int hwnd, int lParam) { return true; } } ; ------------------------------------------------------------------ C# COM DLL namespace DLL_COM_TEST { public delegate bool CallBack(int hwnd, int lParam); public interface IDLL_COM_TESTInterface { void Execute(); void SetCallback(CallBack funcCB); } public class IDLL_COM_TESTImplementation: IDLL_COM_TESTInterface { CallBack funcCB_E; public void SetCallback(CallBack funcCB) { funcCB_E = funcCB; } public void Execute() { funcCB_E(1111, 1); } } ------------------------------------------------------------------ エラー内容 error C3756: 'CallBack': デリゲートの定義が既存のシンボルと競合します。 'CallBack' の宣言を確認してください。 'myCallBack' : 定義されていない識別子です。 error C2061: 構文エラー: 識別子'CallBack' error C2065: 'myCallBack' : 定義されていない識別子です。

専門家に質問してみよう