Show dialog from MFC DLL - c++

I loaded the form but only buttons without functions
HMODULE hModule = LoadLibrary(L"Tools.dll");
if (hModule != NULL)
{
AfxSetResourceHandle(hModule);
CDialog dgl(MAKEINTRESOURCE(199), NULL);
dgl.DoModal();
}
so how I can load a full function of form
and I don't have the DLL source code

To show Dialog box from MFC dll , like scenario - you have exported function in DLL and from that function you call DoModel().This template actually stored in DLL module.You need to switch module state for current handle to be used.You can do this by using :
AFX_MANAGE_STATE(AfxGetStaticModuleState());
AFX_MODULE_STATE AfxGetStaticModuleState()
->The AFX_MODULE_STATE structure contains global data for the module,that is the portion of the module state that is pushed or popped.
IN DLL code will be like this :
AFX_MANAGE_STATE(AfxGetStaticModuleState());
CMyDlg objMyDlg;
iRet = objMyDlg.DoModal();

This is possible only if you are sure that dialog class implementation is MFC based and the class is exported from Tools.dll. You can try inspect your .dll with Dependency Walker utility.
Please note the compiler mangles constructor name. This is what I got for the following declaration.
class __declspec(dllexport) TestDialog : public CDialog
{
public:
TestDialog()
:CDialog(10)
{
}
};
Mangled constructor name: ??_7TestDialog##6B#
Probably you will be able to recreate dialog class header based on the results of your inspection. You should also make sure you have the same version of MFC both for Tools.dll and your application.

Related

CWindowImpl - Create() returns error code 1406

I just tried to setup a small win32 project, and was just about to create a window.
I created a dialog in the resource designer and set up this class for my window:
#pragma once
#include "stdafx.h"
class TTTMainDialog : public CWindowImpl<TTTMainDialog>
{
public:
DECLARE_WND_CLASS(_T("TTTDlg"))
enum { IDD = IDD_TTT_DIALOG };
BEGIN_MSG_MAP_EX(MusicPlayerDialog)
MSG_WM_INITDIALOG(OnInitDialog);
MSG_WM_CLOSE(OnClose);
MSG_WM_DESTROY(OnDestroy);
END_MSG_MAP()
TTTMainDialog();
~TTTMainDialog();
private:
const BOOL OnInitDialog(const CWindow wndFocus, const LPARAM lInitParam);
void OnClose();
void OnDestroy();
};
As you can see, I added the window class declaration, I inherited CWindowImpl, I registered the dialog. I don't think I forgot something here.
In the class which is supposed to create the dialog, I tried to create it like this:
TTTMainDialog myDialog;
HWND handle = myDialog.Create(NULL);
myDialog.ShowWindow(nCmdShow);
However, the Create method does return NULL all the time. I checked the error code with GetLastError(), and it turns out i am getting error code 1406, or "ERROR_TLW_WITH_WSCHILD".
The msdn documentation says the following about this error:
"Cannot create a top-level child window."
I tried to google up on this, but there is not much to find.
If I had to take a guess I would say the problem is caused by some window class name details, but i'm really not sure.
Any advice?
You are trying to build a window class from wrong pieces.
The error is pretty descriptive: you are trying to create a parentless window with a WS_CHILD style and this does not work out.
You get the child style from default template parameter: CWindowImpl -> CWindowImplBaseT -> TWinTraits -> CControlWinTraits. CControlWinTraits is supposed for use with child control windows.
If you are going to use a dialog template (IDD_TTT_DIALOG) then the proper base class is CDialogImpl, which is already prepared to use proper window styles. Also, it has what it takes to create both modal and modeless dialogs. The latter act more like windows and are non-blocking but in the same time take dialog template resource with predefined controls.
Small example for CDialogImpl use
Or, another one

Why is it CString::LoadString works in the main module(.exe) of my app but will not work in my extensionDLL?

I have this MFC app that loads strings from string resource using CString::LoadString function. Each of the apps dialogue box's classes and its associated resources are contained in an MFC extension DLL.
CString::LoadString loads strings from the main module's(.exe) resource's string resource successfully but fails to load string from the DLL's resource's string resource.
In each case I get my instance handle for load string from CWinApp object by calling :
CWinApp *WinApp = AfxGetApp(),
and of course the instance's handle is WinApp->m_hInstance which I use as the first argument in my call to CString::LoadString function.
What could be the cause and what could be the solution.
Are you passing the EXE's HINSTANCE to load a string from the extension library? Sounds like it.
With MFC, if you have extension libraries and you make sure your string identifiers are unique, you just need to call the CString::LoadString(UINT nID) version. Because extension libraries create CDynLinkLibrary structures that go into a global linked list, the LoadString(UINT) function will search through all your MFC libraries until it finds the HINSTANCE that contains that string, and then it will load from there. If you insist on using the LoadString() function with an HINSTANCE argument, be sure to use the HINSTANCE of the extension DLL, and not the extension of the EXE when you want to load a string or dialog from the DLL.
For small projects, like less than a dozen DLLs, you probably manage to just use unique IDs for everything. When you get into the insanely large projects like 100+ DLLs, then you have to use other techniques like specially named functions in your DLL that call AfxSetResourceHandle() or know to always use the HINSTANCE of the DLL. That's another topic.
Just to complement Joe Willcoxson's answer, be sure to check that every MFC Extension DLL you are using,needs a special initialization code, similar to the example below:
#include "stdafx.h"
#include <afxdllx.h>
static AFX_EXTENSION_MODULE MyExtDLL = { NULL, NULL };
extern "C" int APIENTRY
DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
{
if (dwReason == DLL_PROCESS_ATTACH)
{
TRACE0("MyExt.DLL Initializing!\n");
// Extension DLL one-time initialization
if (!AfxInitExtensionModule(MyExtDLL, hInstance))
return 0;
new CDynLinkLibrary(MyExtDLL);
}
else if (dwReason == DLL_PROCESS_DETACH)
{
TRACE0("MyExt.DLL Terminating!\n");
// Terminate the library before destructors are called
AfxTermExtensionModule(MyExtDLL);
}
return 1; // ok
}
This code just takes care of CDynLinkLibrary creation, the key to share resources between MFC modules.
If all this are setup correctly -- and without ID clashes -- then it's simply a mather of calling:
CString str;
str.LoadString(IDS_MY_STRING_ID);
anywhere in your code, no matter where the string actually persists.
A good start point on resource IDs and numbering can be found in this link.

Can't create modal dialog from MFC DLL

I'm trying to launch a modal dialog from a DLL loaded by an MFC application. I'm using VS2010 and both the EXE and DLL use MFC in a static library.
I call DoModal() in my DLL to launch the dialog, with the parent being a CWnd* pointing to the main window from the MFC app. The dialog resource is in the DLL.
This eventually leads to the MFC library function CWnd::CreateDlgIndirect, which has this debug check:
#ifdef _DEBUG
if ( AfxGetApp()->IsKindOf( RUNTIME_CLASS( COleControlModule ) ) )
{
TRACE(traceAppMsg, 0, "Warning: Creating dialog from within a COleControlModule application is not a supported scenario.\n");
}
#endif
AfxGetApp() returns NULL so the code in the debug check fails. If I compile in release, the dialog appears, but doesn't seem to work (all the fields are empty even though I set defaults, some button's don't appear).
I've tried adding AFX_MANAGE_STATE(AfxGetStaticModuleState()); to the top of the function that launches the dialog, and it doesn't make any difference.
What am I missing?
Edit: here's the code I use to call the dialog.
HMODULE oldResMod = AfxGetResourceHandle();
AFX_MANAGE_STATE(AfxGetStaticModuleState());
AfxSetResourceHandle(GetThisModule());
CWnd wndParent;
wndParent.Attach(parent);
CExportOptionsDlg dlg(&wndParent);
dlg.project_name = project->GetName();
if (dlg.DoModal() != IDOK)
{
wndParent.Detach();
AfxSetResourceHandle(oldResMod);
return false; // cancelled
}
// ... (get some data from the dialog members) ...
wndParent.Detach();
AfxSetResourceHandle(oldResMod);
return true; // OK
Check that you've actually created a CWinApp somewhere in your current module (DLL/EXE).
Every module should have one, and only one, CWinApp object. Typically, you would make the CWinApp object a global variable such that it is created and destroyed when the module is loaded and unloaded, respectively.

How To register a Windows Class and Find the Window using registered class

I am creating an MFC application which will be launched on click on Explorer Context (Rightclick) menu.
But I need to launch only single instance of the application. For that I have to use FindWindow and AfxRegisterClass
I tried to register the class in my MFC app as below:
BOOL CNDSClientDlg::InitInstance()
{
//Register Window Updated on 16th Nov 2010, #Subhen
// Register our unique class name that we wish to use
WNDCLASS wndcls;
memset(&wndcls, 0, sizeof(WNDCLASS));
//Class name for using FindWindow later
wndcls.lpszClassName = _T("NDSApp");
// Register new class and exit if it fails
if(!AfxRegisterClass(&wndcls)) // [C]
{
return FALSE;
}
}
and called the method in the constructor of the MFC class. I verified that the class is being registered while I am starting the application.
Now in my shell Extension I am trying to find the Class registered in my MFC as below:
CWnd *pWndPrev = NULL;
pWndPrev = CWnd::FindWindow(_T("NDSApp"),NULL);
if(pWndPrev != NULL)
pWndPrev->BringWindowToTop();
But I am not able to get the CWnd to Window. Not able to figure it out. Please let me know if I am missing something or doing something wrong.
FindWindow finds window instances not window classes. In your app which registers the class you need to actually create a window so that the extension can find that window.
(Finding the window by class name is fine; the problem is you haven't actually created anything to find.)
Also, I suspect if you try to create a window based on the window-class you've registered it will fail because you've left most of the WNDCLASS structure null. See the example you linked to for better default values. (e.g. You must provide a wndproc and hinstance.)

How to use wxTheApp macro outside the module it is declared?

I'm using wxWidgets 2.8.9, built with the default settings under Windows XP, VC9. And I have absolutely standard EXE with IMPLEMENT_APP like this:
#include <wx/wx.h>
#include <wx/image.h>
#include "MainFrame.h"
class MyMainApp: public wxApp {
public:
bool OnInit();
};
IMPLEMENT_APP(MyMainApp)
bool MyMainApp::OnInit()
{
wxInitAllImageHandlers();
wxFrame* frame_mainFrame = new MainFrame(NULL, wxID_ANY, wxEmptyString);
SetTopWindow(frame_mainFrame);
frame_mainFrame->Show();
return true;
}
The MainFrame is a wxFrame with a "HelloWorld" text. This works fine when everything is linked in the EXE. The problem is, I would like to reuse this MainFrame class in another application and therefore I would like to have it in a DLL, so I can use the DLL code from everywhere.
Because my DLL has different export macro than wxWidgets, I can't export any derived from wxFrame class outside my Dll, so I make a factory class, which simply has one static method create(), returning new MainFrame(NULL, wxID_ANY, wxEmptyString);
So far so good. I have now a DLL, containing the MainFrame class, and one more FrameFactory class. Only the FrameFactory class is exported from my DLL and I can create the MainFrame in the EXE, in the OnInit() method like this: wxFrame* frame_mainFrame = FrameFactory::create();
The problem is that the constructor of the base class wxFrame calls wxTopLevelWindowMSW::CreateFrame(...), where the macro wxTheApp is invoked. This wxTheApp macro is actually a call to wxApp::GetInstance(). I was surprised that my wxApp instance is NULL when MainFrame is not in the EXE.
Could somebody familiar with wxWidgets help me what am I doing wrong? I made several more expreriments and always wxTheApp is NULL when the code using this instance variable is used in a different module, than the one where macro IMPLEMENT_APP is called.
I don't use wxWidgets myself (go Qt!) But did you by any chance statically link your DLL to wxWidgets, such that the EXE and the DLL each have their own copy of the lib...?
http://wiki.wxwidgets.org/Creating_A_DLL_Of_An_Application
That would explain why your DLL's global variables for tracking the instance would be null (while the EXEs were set up in app initialization). If this is the case I'd be concerned about your SetInstance() workaround...who knows what other singletons there are:
When to use dynamic vs. static libraries