IXMLDOMDocument memory Leak Issue - visual-c++

I have a COM inproc server test application that uses IXMLDOMDocument to write data and send it back to COM client.I uses get_xml() to get BSTR. But when applications ends it's consuming almost > 20 MB memory while if I don't use COM inproc server it uses < 1 MB.
My COM Server Interface method is
[
object,
uuid(BF798ED1-DCDD-4B29-B552-3A17F1D7E4CF),
dual,
nonextensible,
pointer_default(unique)
]
interface IMoLauncher : IDispatch{
[id(1)] HRESULT GetXML([out] BSTR* bStr);
};
it's code is
STDMETHODIMP CMoLauncher::GetXML(BSTR* bStr)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
BOOL result = FALSE;
IXMLDOMDocument* pDoc = NULL;
HRESULT hr = CoCreateInstance(CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER,
IID_IXMLDOMDocument, (void**)&pDoc);
if ( SUCCEEDED(hr) )
{
result = TRUE;
IXMLDOMNode* pEntityNode = InsertDOMElement(pDoc, NULL, L"Entity", NULL);
SerializeXML(pDoc, pEntityNode);
pDoc->get_xml(bStr);
pDoc->Release();
}
return result;
}
And usage code in client is
CoInitialize(NULL);
IMoLauncher* launcher = NULL;
IUnknown* unknown = NULL;
HRESULT result = CoCreateInstance(CLSID_MoLauncher,NULL,CLSCTX_INPROC_SERVER,IID_IMoLauncher,(void**)&launcher);
if(result==S_OK)
{
for(int i=0;i<iterationCount;i++)
{
BSTR bStr;
launcher->GetXML( &bStr);
printf("Iteration %d\n",i);
::SysFreeString(bStr);
}
}
launcher->Release();
CoUninitialize();

You Need to release pEntityNode too!
Every COM pointer returned by an Interface or COM function must be released. You may use smart pointers to avoid such mistakes.

The IXMLDOMNode* returned from CMoLauncher::InsertDOMElement is never released, that's a big leak.
You need to add Release calls for:
The first InsertDOMElement call in CMoLauncher::SerializeXML.
The InsertDOMElement calls in the loop in the same function (adding a local variable in order to do so (return value of InsertDOMElement)
The InsertDOMElement call in CMoLauncher::GetXML (spotted by xMRI)

Related

CView::OnFilePrint crashing MFC application

We have an MFC application that has been used and maintained for many years. Recently we made some administrative changes to some computers that are running the application. Now the software occasionally crashes when printing from the application.
We are using pretty standard MFC code to initiate the printing. We added try/catch blocks around what we felt like are the pertinent areas of the code with no luck. Whatever is failing does not seem to throw.
We get the typical dialog stating that "____ MFC Application has stopped working". Closing the program is the only option.
The windows event logger shows that our application is the Faulting application.
The exception code is 0xc0000005, which appears to be an Access Denied error.
The application is in the CView::OnFilePrint() code when the crash occurs.
We have added some logging, and we know that we get through DoPreparePrinting, and OnBeginPrinting.
We believe that CDC::StartDoc would be the next thing called, then CView::OnPrepareDC. We don't get to OnPrepareDC when we fail.
We don't seem to find the source code for CView::OnFilePrint, so we are not sure what it looks like. From research online, we think that things happen in this order in OnFilePrint:
// what we think is in OnFilePrint:
CView::OnFilePrint()
{
OnPreparePrinting(); <- we get through our override of this
OnBeginPrinting(); <- we get through our override of this
// loop back to here on multiple docs
CDC::StartDoc();
CView::OnPrepareDC(); <- we do not reach our override of this
CView::OnPaint();
CDC::EndPage();
// loop back on multiple docs
...
// finish if last doc...
}
I would like to have the source for it so we could attempt to rewrite it and try to gracefully fail instead of failing by crashing.
I'm looking for:
1) any suggestions as to how to figure out why the process of printing causes our application to crash.
2) A location for where the CView::OnFilePrint code is located, if available.
(the only idea I have left to narrow down the problem is to call our own version of this so that we can step through it and add logging and/or see if we can at least fail gracefully when it the problem occurs.)
The printer is Xerox Phaser 3610, for what its worth.
source code for CView::OnFilePrint should be in C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\atlmfc\src\mfc\viewprnt.cpp, depending on VS version. There could also be a problem with printer initialization/access.
If there is any error it is most likely due to printer initialization. You can override OnFilePrint and add CPrintInfo printInfo for testing. Example:
//ON_COMMAND(ID_FILE_PRINT, &CView::OnFilePrint)
//ON_COMMAND(ID_FILE_PRINT_DIRECT, &CView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT, OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_DIRECT, OnFilePrint)
void CMyView::OnFilePrint()
{
try
{
CPrintInfo printInfo;
}
catch(...)
{
//log error
AfxMessageBox(L"error");
}
CView::OnFilePrint();
}
As noted in comments, another possibility is that there is a bug somewhere else in the code, which may not necessarily be related to printing.
Inside of CView::OnFilePrint, this occurs:
CWnd * hwndTemp = AfxGetMainWnd();
It turns out that if you don't call OnFilePrint from the main thread, this returns NULL.
Due to slight timing changes when the computers were logged onto a domain, OnFilePrint was being called from another thread. This causes the above call to return null, then when this line gets executed:
hwndTemp->EnableWindow(FALSE);
The application crashes.
There are several ways to fix this. One is to use this:
CWnd * hwndTemp = AfxGetApp()->GetMainWnd();
In place of this:
CWnd * hwndTemp = AfxGetMainWnd();
Another way is to assure that OnFilePrint is only called from the main thread.
A cut to the chase version of the code in CView::OnFilePrint is here:
// disable main window while printing & init printing status dialog
// Store the Handle of the Window in a temp so that it can be enabled
// once the printing is finished
CWnd * hwndTemp = AfxGetMainWnd(); // <--- CAN RETURN NULL HERE
hwndTemp->EnableWindow(FALSE); // <--- CRASH WILL OCCUR HERE
CPrintingDialog dlgPrintStatus(this);
Full version of CView::OnFilePrint is below.
The OnFilePrint code, with the problem area noted:
void CView::OnFilePrint()
{
// get default print info
CPrintInfo printInfo;
ASSERT(printInfo.m_pPD != NULL); // must be set
if (LOWORD(GetCurrentMessage()->wParam) == ID_FILE_PRINT_DIRECT)
{
CCommandLineInfo* pCmdInfo = AfxGetApp()->m_pCmdInfo;
if (pCmdInfo != NULL)
{
if (pCmdInfo->m_nShellCommand == CCommandLineInfo::FilePrintTo)
{
printInfo.m_pPD->m_pd.hDC = ::CreateDC(pCmdInfo->m_strDriverName,
pCmdInfo->m_strPrinterName, pCmdInfo->m_strPortName, NULL);
if (printInfo.m_pPD->m_pd.hDC == NULL)
{
AfxMessageBox(AFX_IDP_FAILED_TO_START_PRINT);
return;
}
}
}
printInfo.m_bDirect = TRUE;
}
if (OnPreparePrinting(&printInfo))
{
// hDC must be set (did you remember to call DoPreparePrinting?)
ASSERT(printInfo.m_pPD->m_pd.hDC != NULL);
// gather file to print to if print-to-file selected
CString strOutput;
if (printInfo.m_pPD->m_pd.Flags & PD_PRINTTOFILE && !printInfo.m_bDocObject)
{
// construct CFileDialog for browsing
CString strDef(MAKEINTRESOURCE(AFX_IDS_PRINTDEFAULTEXT));
CString strPrintDef(MAKEINTRESOURCE(AFX_IDS_PRINTDEFAULT));
CString strFilter(MAKEINTRESOURCE(AFX_IDS_PRINTFILTER));
CString strCaption(MAKEINTRESOURCE(AFX_IDS_PRINTCAPTION));
CFileDialog dlg(FALSE, strDef, strPrintDef,
OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT, strFilter, NULL, 0);
dlg.m_ofn.lpstrTitle = strCaption;
if (dlg.DoModal() != IDOK)
return;
// set output device to resulting path name
strOutput = dlg.GetPathName();
}
// set up document info and start the document printing process
CString strTitle;
CDocument* pDoc = GetDocument();
if (pDoc != NULL)
strTitle = pDoc->GetTitle();
else
EnsureParentFrame()->GetWindowText(strTitle);
DOCINFO docInfo;
memset(&docInfo, 0, sizeof(DOCINFO));
docInfo.cbSize = sizeof(DOCINFO);
docInfo.lpszDocName = strTitle;
CString strPortName;
if (strOutput.IsEmpty())
{
docInfo.lpszOutput = NULL;
strPortName = printInfo.m_pPD->GetPortName();
}
else
{
docInfo.lpszOutput = strOutput;
AfxGetFileTitle(strOutput,
strPortName.GetBuffer(_MAX_PATH), _MAX_PATH);
}
// setup the printing DC
CDC dcPrint;
if (!printInfo.m_bDocObject)
{
dcPrint.Attach(printInfo.m_pPD->m_pd.hDC); // attach printer dc
dcPrint.m_bPrinting = TRUE;
}
OnBeginPrinting(&dcPrint, &printInfo);
if (!printInfo.m_bDocObject)
dcPrint.SetAbortProc(_AfxAbortProc);
/**********************************************************************
Problem area.
If the calling thread is not the main thread, the call to AfxGetMainWnd
can return NULL. In this case, hwndTemp->EnableWindow(FALSE) will crash
the application.
**********************************************************************/
// disable main window while printing & init printing status dialog
// Store the Handle of the Window in a temp so that it can be enabled
// once the printing is finished
CWnd * hwndTemp = AfxGetMainWnd(); // <--- CAN RETURN NULL HERE
hwndTemp->EnableWindow(FALSE); // <--- CRASH WILL OCCUR HERE
CPrintingDialog dlgPrintStatus(this);
CString strTemp;
dlgPrintStatus.SetDlgItemText(AFX_IDC_PRINT_DOCNAME, strTitle);
dlgPrintStatus.SetDlgItemText(AFX_IDC_PRINT_PRINTERNAME,
printInfo.m_pPD->GetDeviceName());
dlgPrintStatus.SetDlgItemText(AFX_IDC_PRINT_PORTNAME, strPortName);
dlgPrintStatus.ShowWindow(SW_SHOW);
dlgPrintStatus.UpdateWindow();
// start document printing process
if (!printInfo.m_bDocObject)
{
printInfo.m_nJobNumber = dcPrint.StartDoc(&docInfo);
if (printInfo.m_nJobNumber == SP_ERROR)
{
// enable main window before proceeding
hwndTemp->EnableWindow(TRUE);
// cleanup and show error message
OnEndPrinting(&dcPrint, &printInfo);
dlgPrintStatus.DestroyWindow();
dcPrint.Detach(); // will be cleaned up by CPrintInfo destructor
AfxMessageBox(AFX_IDP_FAILED_TO_START_PRINT);
return;
}
}
// Guarantee values are in the valid range
UINT nEndPage = printInfo.GetToPage();
UINT nStartPage = printInfo.GetFromPage();
if (nEndPage < printInfo.GetMinPage())
nEndPage = printInfo.GetMinPage();
if (nEndPage > printInfo.GetMaxPage())
nEndPage = printInfo.GetMaxPage();
if (nStartPage < printInfo.GetMinPage())
nStartPage = printInfo.GetMinPage();
if (nStartPage > printInfo.GetMaxPage())
nStartPage = printInfo.GetMaxPage();
int nStep = (nEndPage >= nStartPage) ? 1 : -1;
nEndPage = (nEndPage == 0xffff) ? 0xffff : nEndPage + nStep;
VERIFY(strTemp.LoadString(AFX_IDS_PRINTPAGENUM));
// If it's a doc object, we don't loop page-by-page
// because doc objects don't support that kind of levity.
BOOL bError = FALSE;
if (printInfo.m_bDocObject)
{
OnPrepareDC(&dcPrint, &printInfo);
OnPrint(&dcPrint, &printInfo);
}
else
{
// begin page printing loop
for (printInfo.m_nCurPage = nStartPage;
printInfo.m_nCurPage != nEndPage; printInfo.m_nCurPage += nStep)
{
OnPrepareDC(&dcPrint, &printInfo);
// check for end of print
if (!printInfo.m_bContinuePrinting)
break;
// write current page
TCHAR szBuf[80];
ATL_CRT_ERRORCHECK_SPRINTF(_sntprintf_s(szBuf, _countof(szBuf), _countof(szBuf) - 1, strTemp, printInfo.m_nCurPage));
dlgPrintStatus.SetDlgItemText(AFX_IDC_PRINT_PAGENUM, szBuf);
// set up drawing rect to entire page (in logical coordinates)
printInfo.m_rectDraw.SetRect(0, 0,
dcPrint.GetDeviceCaps(HORZRES),
dcPrint.GetDeviceCaps(VERTRES));
dcPrint.DPtoLP(&printInfo.m_rectDraw);
// attempt to start the current page
if (dcPrint.StartPage() < 0)
{
bError = TRUE;
break;
}
// must call OnPrepareDC on newer versions of Windows because
// StartPage now resets the device attributes.
OnPrepareDC(&dcPrint, &printInfo);
ASSERT(printInfo.m_bContinuePrinting);
// page successfully started, so now render the page
OnPrint(&dcPrint, &printInfo);
if ((nStep > 0) && // pages are printed in ascending order
(nEndPage > printInfo.GetMaxPage() + nStep)) // out off pages
{
// OnPrint may have set the last page
// because the end of the document was reached.
// The loop must not continue with the next iteration.
nEndPage = printInfo.GetMaxPage() + nStep;
}
// If the user restarts the job when it's spooling, all
// subsequent calls to EndPage returns < 0. The first time
// GetLastError returns ERROR_PRINT_CANCELLED
if (dcPrint.EndPage() < 0 && (GetLastError()!= ERROR_SUCCESS))
{
HANDLE hPrinter;
if (!OpenPrinter(LPTSTR(printInfo.m_pPD->GetDeviceName().GetBuffer()), &hPrinter, NULL))
{
bError = TRUE;
break;
}
DWORD cBytesNeeded;
if(!GetJob(hPrinter,printInfo.m_nJobNumber,1,NULL,0,&cBytesNeeded))
{
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
{
bError = TRUE;
break;
}
}
JOB_INFO_1 *pJobInfo;
if((pJobInfo = (JOB_INFO_1 *)malloc(cBytesNeeded))== NULL)
{
bError = TRUE;
break;
}
DWORD cBytesUsed;
BOOL bRet = GetJob(hPrinter,printInfo.m_nJobNumber,1,LPBYTE(pJobInfo),cBytesNeeded,&cBytesUsed);
DWORD dwJobStatus = pJobInfo->Status;
free(pJobInfo);
pJobInfo = NULL;
// if job status is restart, just continue
if(!bRet || !(dwJobStatus & JOB_STATUS_RESTART) )
{
bError = TRUE;
break;
}
}
if(!_AfxAbortProc(dcPrint.m_hDC, 0))
{
bError = TRUE;
break;
}
}
}
// cleanup document printing process
if (!printInfo.m_bDocObject)
{
if (!bError)
dcPrint.EndDoc();
else
dcPrint.AbortDoc();
}
hwndTemp->EnableWindow(); // enable main window
OnEndPrinting(&dcPrint, &printInfo); // clean up after printing
dlgPrintStatus.DestroyWindow();
dcPrint.Detach(); // will be cleaned up by CPrintInfo destructor
}
}

While creating private pool WinBioOpenSession() is failing and returning WINBIO_E_CONFIGURATION_FAILURE

I'm creating a bio metric project in visual studio 2008 using mfc application in VC++ I'm getting following difficulties. Please Help
I'm trying to create private pool using the WinBioOpenSession() method but the function returning WINBIO_E_CONFIGURATION_FAILURE what should I do?
BOOL CPrivatePoolBioDlg::EnrollFingerprint()
{
WINBIO_UNIT_SCHEMA *unitSchemaArray = NULL;
SIZE_T unitSchemaCount = 0;
WINBIO_UNIT_ID unitIdArray[1]={};
SIZE_T unitIdCount = ARRAYSIZE(unitIdArray);
WINBIO_SESSION_HANDLE sessionHandle;
HRESULT hr; // = S_OK;
//Enumarating devices...
hr = WinBioEnumBiometricUnits(WINBIO_TYPE_FINGERPRINT,&unitSchemaArray,&unitSchemaCount);
if(FAILED(hr))
{
CString m;
m.Format(_T("Unable to Enumarate Device 0x%08x"),hr);
AfxMessageBox(m);
return 0;
}
//Enumaration Success...
unitIdArray[0] = unitSchemaArray[0].UnitId;
//Opening the session...
hr = WinBioOpenSession(WINBIO_TYPE_FINGERPRINT,WINBIO_POOL_PRIVATE,WINBIO_FLAG_BASIC,
unitIdArray,unitIdCount,&PRIVATE_POOL_DATABASE_ID,&sessionHandle);
if(FAILED(hr))
{
///////////////////////HERE FUNCTION IS RETURNING WINBIO_E_CONFIGURATION_FAILURE////////////////////
CString m;
m.Format(_T("Unable to Start session 0x%08x, %d"),hr, GetLastError());
AfxMessageBox(m);
return 0;
}
//Session opened...
WinBioCloseSession(sessionHandle);
return 1;
}
Before Opening session you should configure GUID database into registry and to configure follow the steps on.
MSDN Private Pool Helper Function and MSDN Private Pool Setup. Before opening session call the methods OnInstall() to create configuration and OnAdd() to add sensor to private pool from PrivatePoolSetup.cpp.
You should have following files in your project.
PrivatePoolCommonDefs.h
PrivatePoolSetup.cpp
BioHelper.h
Config.cpp
Display.cpp

::CoResumeClassObect() fails on Windows Server 2012 R2 with HRESULT : 0x800706c6(The array bounds are invalid)

I have a COM Server , and I want to use it as a service. My application has a installer component which creates a user (CN_Service) in local system and install this COM server as a service using below command:
Connect.exe /service /noreinstall /user:CN_Service /password:somePassword /depends:lanmanworkstation
I have another component, which is responsible for starting this installed service. In its winmain(), I am using below code to register the COM server class objects (in SUSPENDED mode), it successfully registers the objects and returns HRESULT as S_OK which is as expected.
int CAppModule::WinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPTSTR /* lpCmdLine */, int nShowCmd)
{
::AfxSetResourceHandle(hInstance);
_strServiceName.LoadString(IDS_SRVL_SERVICENAME);
_strDisplayName.LoadString(IDS_SRVL_DISPLAYNAME);
VERIFY(gNTEventLog.SetSource(_strDisplayName));
// Copy parameters
m_hInstance = hInstance;
m_nCmdShow = nShowCmd;
_strCmdLine = ::GetCommandLine();
_qappmodel->InitCOMSupport(); //::CoInitializeEx(NULL, COINIT_MULTITHREADED);
// Process command line options
bool bContinue = true;
int nExitCode = 0;
if (ProcessCommandLine(_strCmdLine, &bContinue) && bContinue)
{
if (_patlmodule != NULL)
{
//_patlmodule is an interface pointer and private member of CAppModule
HRESULT hr = _patlmodule->RegisterClassObjects(CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER, REGCLS_MULTIPLEUSE | REGCLS_SUSPENDED);
if (FAILED(hr))
{
ASSERT_NOT_REACHED();
gNTEventLog.LogHR(_T("Failed to register the class objects"), hr);
return 2;
}
}
nExitCode = InternalWinMain();
if (_patlmodule != NULL)
{
_patlmodule->RevokeClassObjects();
}
}
_qappmodel->UninitCOMSupport();
// When we get here, the service has been stopped
return nExitCode;
}
But when I try to resume the registered class objects using ::CoResumeClassObjects(), it throws an error ‘Failed to resume class objects’ with HRESULT value:
800706c6 (The array bounds are invalid)
I am using below code to resume the class objects:
BOOL CAppModule::InitInstance()
{
// Increment usage count
if (_patlmodule != NULL)
{
_patlmodule->Lock();
HRESULT hr = ::CoResumeClassObjects(); //Fails here
if (FAILED(hr))
{
ASSERT_NOT_REACHED();
if (hr == CO_E_WRONG_SERVER_IDENTITY)
{
gNTEventLog.LogHR(_T("Failed to resume class objects (registered as a service?)"), hr);
}
else
{
gNTEventLog.LogHR(_T("Failed to resume class objects"), hr);
}
return FALSE;
}
}
return TRUE;
}
Problem Statement: The important thing is that, I want to run this code on Windows Server 2012 R2 machine, where the method ::CoResumeClassObjects() fails. This same piece of code runs fine on Windows Server 2008 machine.
Please suggest me whether server2012 box has anything to do with ::CoResumeClassObjects() method.
Also I am creating a separate local user(which is an app requirement) for registering the exe as service in code and responsible for starting/stopping service. Can It be a problem on win server 2012 ?
Any help would be appreciated…

Cross-thread operation not valid:

So i'm a bit new to C++(4-6 months so far + learning from books(not teachers)) and I understand this problem is most likely a result of my misunderstandings but I still can't figure it out after googling a lot of search terms...
I also tried stackoverflow and read:
Cross-thread operation not valid: Control 'Form1' accessed from a thread other than the thread it was created on
Cross-thread operation not valid: Control accessed from a thread other than the thread it was created on
Best Way to Invoke Any Cross-Threaded Code?
and I attempted to create a solution for this(which you can see below), but I failed to convert the code from c# to c++(I am not a C# user so...)
I can solve it with( from: Crossthread operation not valid... - VB.NET):
listView1->CheckForIllegalCrossThreadCalls = false;
but since it is not good practice, I am looking for an alternative.
when I attempt to call this clr code in my thread:
void CClient::add(){
lvhandle = (HWND)project1::Form1::ClrForm1->listView1->Handle.ToPointer();
/* as you can see here, I tried to figure out how to use MethodInvoker but failed...
if(project1::Form1::ClrForm1->listView1->InvokeRequired){
lvhandle = (HWND)project1::Form1::ClrForm1->listView1->Handle.ToPointer();
//project1::Form1::ClrForm1->listView1->Invoke(gcnew System::Windows::Forms::MethodInvoker(this, &annoyme));
}
else
{
lvhandle = (HWND)project1::Form1::ClrForm1->listView1->Handle.ToPointer();
}*/
item.pszText = LPSTR_TEXTCALLBACK; // Sends an LVN_GETDISPINFO message.
item.mask = LVIF_TEXT | LVIF_IMAGE |LVIF_STATE;
item.stateMask = 0;
item.iSubItem = 0;
item.state = 0;
item.pszText = L"test";
item.lParam = 0;
ListView_InsertItem(lvhandle, &item);
std::string lol = std::to_string(item.iItem);
String^ test;
test = marshal_as<String^>(lol);
project1::Form1::ClrForm1->Text = test;
}
it gives me an exception:
Cross-thread operation not valid: Control 'Form1' accessed from a thread other than the thread it was created on.
ClrForm1 is defined as:
public ref class Form1 : public System::Windows::Forms::Form
{
public:
static Form1^ ClrForm1;
which I create when the entry point is triggered.
int main(array<System::String ^> ^args)
{
// Enabling Windows XP visual effects before any controls are created
Application::EnableVisualStyles();
Application::SetCompatibleTextRenderingDefault(false);
// Create the main window and run it
Form1::ClrForm1 = gcnew Form1();
Application::Run(Form1::ClrForm1);
return 0;
}
I also confirmed the error by doing:
project1::Form1::ClrForm1->Text = "Test!0";
hopefully I detailed this enough to get a response >.<

Starting Doc/View application hidden

Using Visual studio 2010 and MFC Doc/View Applications I want my SDI application to start up completely hidden, and after sometime or with receiving some message from tray icon it shows the mainframe, view and so on. I change the line m_pMainWnd->ShowWindow(SW_NORMAL); to m_pMainWnd->ShowWindow(SW_HIDE); in BOOL CMyApp::InitInstance() but the main frame just flickers after executing the application and then goes hiiden what should I do inorder to avoid this problem and keep the showing capability of main frame when ever I want.
Here is the solution for SDI/MDI app: The new MFC (with VC2010) overrides the m_nCmdShow value with a setting stored in the system registry. To change this behaviour, simply override the LoadWindowPlacement virtual function in the application class.
BOOL CAdVisuoApp::LoadWindowPlacement(CRect& rectNormalPosition, int& nFflags, int& nShowCmd)
{
BOOL b = CWinAppEx::LoadWindowPlacement(rectNormalPosition, nFflags, nShowCmd);
nShowCmd = SW_HIDE;
return b;
}
Normally if you have VC2005 or earlier the following will do:
// Parse command line for standard shell commands, DDE, file open
CCommandLineInfo cmdInfo;
ParseCommandLine(cmdInfo);
m_nCmdShow = SW_HIDE;
// Dispatch commands specified on the command line. Will return FALSE if
// app was launched with /RegServer, /Register, /Unregserver or /Unregister.
if (!ProcessShellCommand(cmdInfo))
return FALSE;
// The one and only window has been initialized, so show and update it
m_pMainWnd->ShowWindow( m_nCmdShow);
m_pMainWnd->UpdateWindow();
Note that m_nCmdShow should be set to SW_HIDE before ProcessShallCommand for the flicker not to occur.
It looks like there might be a bug in VC2010 though. Since I have done this before it intrigued me and tried a fresh VC2010 project but it was not working. I noticed the problem was deep in the following MFC function.
BOOL CFrameWnd::LoadFrame(UINT nIDResource, DWORD dwDefaultStyle,
CWnd* pParentWnd, CCreateContext* pContext)
{
// only do this once
ASSERT_VALID_IDR(nIDResource);
ASSERT(m_nIDHelp == 0 || m_nIDHelp == nIDResource);
m_nIDHelp = nIDResource; // ID for help context (+HID_BASE_RESOURCE)
CString strFullString;
if (strFullString.LoadString(nIDResource))
AfxExtractSubString(m_strTitle, strFullString, 0); // first sub-string
VERIFY(AfxDeferRegisterClass(AFX_WNDFRAMEORVIEW_REG));
// attempt to create the window
LPCTSTR lpszClass = GetIconWndClass(dwDefaultStyle, nIDResource);
CString strTitle = m_strTitle;
if (!Create(lpszClass, strTitle, dwDefaultStyle, rectDefault,
pParentWnd, ATL_MAKEINTRESOURCE(nIDResource), 0L, pContext))
{
return FALSE; // will self destruct on failure normally
}
// save the default menu handle
ASSERT(m_hWnd != NULL);
m_hMenuDefault = m_dwMenuBarState == AFX_MBS_VISIBLE ? ::GetMenu(m_hWnd) : m_hMenu;
// load accelerator resource
LoadAccelTable(ATL_MAKEINTRESOURCE(nIDResource));
if (pContext == NULL) // send initial update
SendMessageToDescendants(WM_INITIALUPDATE, 0, 0, TRUE, TRUE);
return TRUE;
}
m_nCmdShow is still SW_HIDE when this function executes but it changes to SW_SHOWNORMAL when if (!Create(lpszClass... line executes. I don't know why this happens in VC2010 project only, sounds like a bug to me.
My sample project was SDI.
This comes from a dialog based application but you should be able to convert it to a Doc/View app as well. You need to handle the OnWindowPosChanging event. The key line is the the one inside the if statement. This allows my application to start completely hidden from view.
void CIPViewerDlg::OnWindowPosChanging( WINDOWPOS FAR* lpWindowPosition )
{
if( !m_bVisible )
{
lpWindowPosition->flags &= ~SWP_SHOWWINDOW;
}
CDialog::OnWindowPosChanging( lpWindowPosition );
}
Make sure that you are correctly turning off the WS_VISIBLE bit in CMainFrame::PreCreateWindow(CREATESTRUCT& cs). Something like this should worK:
cs.style &= ~WS_VISIBLE;
We had simply been negating the bit instead of turning it off, and we got away with it in VS 6.0 because this function was called only once. It is called twice in newer versions of Visual Studio, so in the second call we were flipping it right back on again. :-O
I tried all for Visual Studio 2010 and finished up with:
class CMainFrame : public CFrameWndEx
{
// ...
// Attributes
public:
BOOL m_bForceHidden;
// ...
// Overrides
public:
virtual void ActivateFrame(int nCmdShow = -1);
//...
};
CMainFrame::CMainFrame() : m_bForceHidden(TRUE)
{
// ...
}
void CMainFrame::ActivateFrame(int nCmdShow)
{
if(m_bForceHidden)
{
nCmdShow = SW_HIDE;
m_bForceHidden = FALSE;
}
CFrameWndEx::ActivateFrame(nCmdShow);
}
Other tricks did not work for me.
Found solution at:
http://forums.codeguru.com/showthread.php?478882-RESOLVED-Can-a-Doc-view-be-hidden-at-startup
I found in VS2017 (using BCGControlBar Pro which is what MFC Feature Pack was based on) that you have to handle things in two places:
BOOL CMainFrame::LoadFrame(UINT nIDResource, DWORD dwDefaultStyle, CWnd* pParentWnd, CCreateContext* pContext)
{
if (!__super::LoadFrame(nIDResource, dwDefaultStyle, pParentWnd, pContext))
{
return FALSE;
}
// undo what __super::LoadFrame() does where it will set it to SW_NORMAL if not SW_MAXIMIZED
AfxGetApp()->m_nCmdShow = SW_HIDE;
}
BOOL CTheApp::LoadWindowPlacement(CRect& rectNormalPosition, int& nFflags, int& nShowCmd)
{
BOOL b = __super::LoadWindowPlacement(rectNormalPosition, nFflags, nShowCmd);
nShowCmd = SW_HIDE;
return b;
}

Resources