I create a win32 console project with option add MFC, and MSVS produce some code automate for me,if I wanted drawing some windows, do I need derive my own class from CWinApp? or use an instance of CWinApp directly?
If I use an instance of CWinApp directly,how do I custom InitInstance function to get the frame that I like?
Simply put,If I want make some windows using the code below,how to do that?
int main()
{
int nRetCode = 0;
HMODULE hModule = ::GetModuleHandle(nullptr);
if (hModule != nullptr)
{
// initialize MFC and print and error on failure
if (!AfxWinInit(hModule, nullptr, ::GetCommandLine(), 0))
{
// TODO: change error code to suit your needs
wprintf(L"Fatal Error: MFC initialization failed\n");
nRetCode = 1;
}
else
{
// TODO: code your application's behavior here.
}
}
Related
I have created an MFC Dialog box in a DLL for use in multiple projects and it has functionalities such as:
Getting Listbox data from the main application using the DLL. I can push string data through the main application to the MFC Dialog box but I am getting Assertation errors after compilation.
This process happens in a thread where one thread keeps the Dialog box active and another pushes data as shown in the code below.
void dbox(CDialogClass *dlg)
{
dlg->ShowDlg();
}
void input(CDialogClass *dlg)
{
string str1= "";
while (1)
{
getline(cin, str1);
//cin >> str1;
dlg->SetData(str1);
}
}
int main()
{
HMODULE hModule = ::GetModuleHandle(NULL);
if (hModule != NULL)
{
// initialize MFC and print and error on failure
if (!AfxWinInit(hModule, NULL, ::GetCommandLine(), 0))
{
_tprintf(_T("Fatal Error: MFC initialization failed\n"));
}
else
{
CDialogClass *dlg = new CDialogClass("Title Dbox",300.0f, 300.0f, 0);
thread t1(input, dlg);
thread t2(dbox, dlg);
t1.join();
t2.join();
}
}
return 0;
}
Here dbox() invokes a ShowDlg function which is in an MFC DLL as below:
void CDialogClass::ShowDlg()
{
dlgg->title = title;
dlgg->dialogWidth = D_width;
dlgg->dialogHeight = D_height;
dlgg->pos = pos;
dlgg->Create(IDD_DIALOG1);
dlgg->ShowWindow(SW_SHOWNORMAL);
dlgg->RunModalLoop();
//dlgg->DoModal();
}
SetData() is called by thread input() and it has the below code in the DLL:
void CDialogClass::SetData(string data)
{
p_text = data;
dlgg->calldata(data);
}
Below is the code for my Dialog class in the DLL just for reference if needed-
#include "stdafx.h"
#include "DlgDisp.h"
#include "afxdialogex.h"
#include "Resource.h"
#include <fstream>
#include <Thread>
IMPLEMENT_DYNAMIC(CDlgDisp, CDialogEx)
CDlgDisp::CDlgDisp(CWnd* pParent /*=NULL*/)
: CDialogEx(CDlgDisp::IDD, pParent)
{
}
CDlgDisp::~CDlgDisp()
{
}
void CDlgDisp::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
DDX_Control(pDX, IDC_LIST1, m_listbox);
}
BOOL CDlgDisp::OnInitDialog()
{
//Title manipulations
char *str_title;
str_title = &title[0];
SetWindowText((CAtlString)str_title);
//Size manipulations
CWnd* pctrl = GetDlgItem(IDC_LIST1);
CRect rectctrl;
SetWindowPos(NULL, 0, 0, dialogWidth, dialogHeight, SWP_NOMOVE | SWP_NOZORDER);
pctrl->GetWindowRect(rectctrl);
pctrl->SetWindowPos(NULL, 20, 20, dialogWidth-120, dialogHeight-80, SWP_NOMOVE | SWP_NOZORDER);
UpdateData(FALSE);
return TRUE; // return TRUE unless you set the focus to a control
}
BEGIN_MESSAGE_MAP(CDlgDisp, CDialogEx)
END_MESSAGE_MAP()
void CDlgDisp::calldata(string strdata)
{
char *str_parameter;
str_parameter = &strdata[0];
CString param = _T("");
param.Format(_T("%s"), (CAtlString)str_parameter);
if (pos == 0)
{
m_listbox.InsertString(0, param);
}
else
m_listbox.AddString(param);
UpdateData(FALSE);
}
the flow of the program for references:
CDlgDisp class is the Dialog class derived from CDialogEx class.
CDialogClass is for interaction with external applications which is derived from CDialog class.
CDialogClass has a public member variable of CDlgDisp class.
external application -> object.CdialogClass -> object.CDlgdisp class
when I execute the program it runs well, and I get an error when I try to input data through the console. It does get printed in the Listbox dynamically but then it shows the Assertation Error.
Here is an image after execution
[enter image description here][1]
and here is the image after I enter the data in console and press enter
[enter image description here][2]
what do you guys think the problem is?
[1]: https://i.stack.imgur.com/pXFMD.png
[2]: https://i.stack.imgur.com/eUXZ7.png
Look into the source where the ASSERT ion take place
You find this comment:
// Note: if either of the above asserts fire and you are
// writing a multithreaded application, it is likely that
// you have passed a C++ object from one thread to another
// and have used that object in a way that was not intended.
// (only simple inline wrapper functions should be used)
//
// In general, CWnd objects should be passed by HWND from
// one thread to another. The receiving thread can wrap
// the HWND with a CWnd object by using CWnd::FromHandle.
//
// It is dangerous to pass C++ objects from one thread to
// another, unless the objects are designed to be used in
// such a manner.
MFC window objects use handle maps per thread. This usually doesn't allow you to use the objects for some functions from other threads. It is possible but this is discussed in many other threads.
The way you want to use the MFC isn't possible. Think about synchronisation. If the functions are thread safe that you want to use with the other window you may use SendMessage and the m_hWnd handle directly.
Thank you guys for being first responders to my problem. All the comments were useful and helped me in understanding the problem.
Problem: Since MFC is thread-safe therefore using an object to SetData was creating a memory sharing conflict between both the threads.
Solution: I used a custom message to pass information to be displayed dynamically. Below Links helped completely-
https://blog.csdn.net/xust999/article/details/6267216
On sending end:
::PostMessage(HWND_BROADCAST, WM_UPDATE_DATA, 0, 0);
On receiving end in the header file:
const UINT WM_UPDATE_DATA = ::RegisterWindowMessage(_T("UpdateData"));
Also, in the header file in the Dialog class:
afx_msg LRESULT OnUpdateData(WPARAM wParam, LPARAM lParam);
The above function will be called when the message is posted and all functionalities to be added to it such as-
LRESULT CDlgDisp::OnUpdateData(WPARAM wParam, LPARAM lParam)
{
char *str_parameter;
str_parameter = ¶meter[0];
CString param = _T("");
param.Format(_T("%s"), (CAtlString)str_parameter);
if (pos == 0)
{
m_listbox.InsertString(0, param);
}
else
m_listbox.AddString(param);
return 1;
}
Thank you, Everyone.
Having a HWND with IWebBrowser2 on it. IWebBrowser2 is new CLSID_WEBBROWSER.
When I navigating to youtube,google and etc, sometimes it shows me Script Error. And I want to disable it. How can I do it?
if (MoneyHWND == NULL) {
if (SUCCEEDED(OleInitialize(NULL)))
{
vector<wchar_t> fn(1000);
GetModuleFileName(0, fn.data(), 1000);
PathStripPath(fn.data());
RKEY k(HKEY_CURRENT_USER, L"SOFTWARE\\Microsoft\\Internet Explorer\\Main\\FeatureControl\\FEATURE_BROWSER_EMULATION");
k[fn.data()] = 11001UL; // Use IE 11
MoneyHWND = CreateDialog(GetModuleHandle(0), MAKEINTRESOURCE(IDD_FORMVIEW1), hWnd, MoneyProc);
pBrowser2 = new WebBrowser(MoneyHWND);
RECT rc;
GetClientRect(MoneyHWND, &rc);
pBrowser2->SetRect(rc);
pBrowser2->Navigate(site);
OleUninitialize();
}
}
IWebBrowser2::Silent:
Sets or gets a value that indicates whether the object can display dialog boxes.
Note, that the property is exposed to C and C++ programs using the following signatures:
HRESULT IWebBrowser2::get_Silent(VARIANT_BOOL *pbSilent);
HRESULT IWebBrowser2::put_Silent(VARIANT_BOOL bSilent);
In other words:
// ...
auto hr{ pBrowser2->put_Silent(VARIANT_TRUE) };
if FAILED(hr)
{
// Handle error
// ...
}
I followed all the instructions that is referred here :
http://help.adobe.com/en_US/robohelp/robohtml/WS5b3ccc516d4fbf351e63e3d11aff59c571-7f43.html
My CMainFrame::HtmlHelp overiden handler looks like this :
void CMainFrame::HtmlHelp(DWORD_PTR dwData, UINT nCmd)
{
// TODO: Add your specialized code here and/or call the base class
CWaitCursor wait;
// Get the path to the Help system
CWinApp* pApp = AfxGetApp();
ASSERT_VALID(pApp);
// Set the path to server-based help
CString csOnlineHelpPath = _T("C:\\Help\\Final\\index.htm");
PrepareForHelp();
// must use top level parent (for the case where m_hWnd is in DLL)
CWnd* pWnd = GetTopLevelParent();
// finally, run the RoboHelp Help engine
if (!RH_ShowHelp(pWnd->m_hWnd, csOnlineHelpPath, nCmd, dwData))
AfxMessageBox(AFX_IDP_FAILED_TO_LAUNCH_HELP);
}
The problem is that the help is never opened. I tried to debug the RoboHelp_CSH.cpp file and I found out that at the line #3267 with the code
MultiByteToWideChar(CP_ACP, MB_USEGLYPHCHARS, szTempFile, (int)uLen, bstr, uLen+1);
the bstr buffer have an extra char at the end that makes the following code
hr=s_pstBrowser->Navigate(bstr, &vFlags, &vTargetFrameName, &vPostData, &vHeaders);
HWND hWnd;
hr=s_pstBrowser->get_HWND((long*)&hWnd);
if (SUCCEEDED(hr))
{
::SetForegroundWindow(hWnd);
}
::SysFreeString(bstr);
}
to fail. The original szTempFile has the data below
C:\Users\sdancer\AppData\Local\Temp\robohelp_csh.htm
and the bstr the the following (the DC2 is the symbol I show inside notepad++, unside VS2008 I see an up and down arrow).
C:\Users\sdancer\AppData\Local\Temp\robohelp_csh.htmDC2
What am I doing wrong here ?
I want to use Chromium Embeded Framework in an mfc dll. Therefore I created a mfc test exe and tested a minimalistic implementation of cef (which worked). My next step was to do exactly the same thing with a test mfc dll. The code is almost the same but the cef browser window won't come up.
The application hangs in CefInitialize() and won't return. After debugging, I found that it gets stuck in a WaitForSingleObject/WaitForMultipleObject windows api.
BOOL CMyBrowserDllApp::InitInstance()
{
HINSTANCE hInstance = GetModuleHandle(NULL);
CefMainArgs main_args(hInstance);
CefSettings settings;
settings.no_sandbox = true;
settings.multi_threaded_message_loop = true;
// Execute the secondary process, if any.
int exit_code = CefExecuteProcess(main_args, cefApplication.get(), NULL);
if (exit_code >= 0)
return exit_code;
if(!CefInitialize(main_args, settings, cefApplication.get(), NULL))
{
OutputDebugStringA("Error: CefInitialize failed");
}else
OutputDebugStringA("Info: CefInitialize succeeded");
CWinApp::InitInstance();
return TRUE;
}
Same implementation works if used in a mfc exe directly.
GetModuleHandle returns the base for the exe not the dll. You might want to stash the dll base from:
BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, void *reserved)
I have this function in test2.cpp
void Ctest2App::message(){
MessageBox(0, L"And text here", L"MessageBox caption", MB_OK);
}
I call it from test2Dlg in the following way
void Ctest2Dlg::OnBnClickedButton1()
{
Ctest2App t;
t.message();
}
When I press the button I get a Debug Assertion error. why?
the test2.cpp file-
// test2.cpp : Defines the class behaviors for the application.
//
#include "stdafx.h"
#include "test2.h"
#include "test2Dlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// Ctest2App
BEGIN_MESSAGE_MAP(Ctest2App, CWinApp)
ON_COMMAND(ID_HELP, &CWinApp::OnHelp)
END_MESSAGE_MAP()
// Ctest2App construction
Ctest2App::Ctest2App()
{
// TODO: add construction code here,
// Place all significant initialization in InitInstance
}
// The one and only Ctest2App object
Ctest2App theApp;
// Ctest2App initialization
BOOL Ctest2App::InitInstance()
{
// InitCommonControlsEx() is required on Windows XP if an application
// manifest specifies use of ComCtl32.dll version 6 or later to enable
// visual styles. Otherwise, any window creation will fail.
INITCOMMONCONTROLSEX InitCtrls;
InitCtrls.dwSize = sizeof(InitCtrls);
// Set this to include all the common control classes you want to use
// in your application.
InitCtrls.dwICC = ICC_WIN95_CLASSES;
InitCommonControlsEx(&InitCtrls);
CWinApp::InitInstance();
AfxEnableControlContainer();
// Create the shell manager, in case the dialog contains
// any shell tree view or shell list view controls.
CShellManager *pShellManager = new CShellManager;
// Standard initialization
// If you are not using these features and wish to reduce the size
// of your final executable, you should remove from the following
// the specific initialization routines you do not need
// Change the registry key under which our settings are stored
// TODO: You should modify this string to be something appropriate
// such as the name of your company or organization
SetRegistryKey(_T("Local AppWizard-Generated Applications"));
Ctest2Dlg dlg;
m_pMainWnd = &dlg;
INT_PTR nResponse = dlg.DoModal();
if (nResponse == IDOK)
{
// TODO: Place code here to handle when the dialog is
// dismissed with OK
}
else if (nResponse == IDCANCEL)
{
// TODO: Place code here to handle when the dialog is
// dismissed with Cancel
}
// Delete the shell manager created above.
if (pShellManager != NULL)
{
delete pShellManager;
}
// Since the dialog has been closed, return FALSE so that we exit the
// application, rather than start the application's message pump.
return FALSE;
}
void Ctest2App::message(){
MessageBox(0, L"And text here", L"MessageBox caption", MB_OK);
}
You have attempted to create a second Ctest2App object, but there can only be one in an app. MFC provides a global function to access the already-created app object:
AfxGetApp()->message();