Problems with common dialog functions in a binary dll - c++

I did a simple test of using common dialog in a console application and everything worked properly. Then I tried to use the same code putting it in a binary dll. I called my function from Vb 6 and strange things have begun to happen.
I have already tried to call other functions from vb 6 contained in this dll without problems.
With the common dialog, on the first call, the dialog appears correctly. The next calls vb says it cannot find the dll (error 53) and I have to close and reopen the IDE of vb 6. It only happens using the common dialog functions. For every other type of code this problem does not occur.
Here is the code:
C++:
bool _stdcall FsDialog(HWND hwnd){
OPENFILENAME openFile;
wchar_t szFileName[MAX_PATH];
wchar_t szFileTitle[MAX_PATH];
int index = 0;
ZeroMemory( &openFile, sizeof(OPENFILENAME) );
openFile.lStructSize = sizeof(OPENFILENAME);
szFileTitle[0] = '\0';
szFileName[0] = '\0';
openFile.hwndOwner = hwnd;
openFile.lpstrFilter = L"Logs (*.log)\0*.log\0";
openFile.lpstrFile = szFileName;
openFile.nMaxFile = MAX_PATH;
openFile.lpstrFileTitle = szFileTitle;
openFile.nMaxFileTitle = sizeof(szFileTitle)/sizeof(*szFileTitle);
openFile.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
openFile.lpstrDefExt = L"log";
if (GetOpenFileName(&openFile)){
return(1);
}
}
VB6:
Private Declare Function FsDialog Lib "mydll.dll" (ByVal hWnd As Long) As Integer
Private Sub Form_Load()
Debug.Print FsDialog(Me.hWnd)
End Sub

Related

How can I read and write text files using the windows api

There are many similar questions, but mine is a bit different. Mine involves a Windows GUI. I am using an open file dialog or an "OPENFILENAME". I want to get the dialog result as OK when the user clicks the OK button and then open a text encoded file. I have done it in Java, but the UI looks weird. So I am not sure whether or not people would like it. I want to learn C++ as well, so I need some help. I have a text box called "hWndEdit" in the WM_COMMAND message inside my program. After opening, the text in the file is supposed to be displayed in the textBox I have specified. I have defined the function in a header file with the following code:
#include <iostream>
#include <fstream>
#include <windows.h>
using namespace std;
void OpenFile()
{
OPENFILENAME ofn; // common dialog box structure
HWND hwnd = nullptr; // owner window
HANDLE hf; // file handle
// Initialize OPENFILENAME
ZeroMemory(&ofn, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = hwnd;
// Set lpstrFile[0] to '\0' so that GetOpenFileName does not
// use the contents of szFile to initialize itself.
ofn.nMaxFile = sizeof(szFile);
ofn.lpstrFilter = L"NoteRecorder Notes\0(*.recnote)\0Text\0(*.txt)\0";
ofn.nFilterIndex = 1;
ofn.lpstrFileTitle = NULL;
ofn.nMaxFileTitle = 0;
ofn.lpstrInitialDir = NULL;
ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
// Display the Open dialog box.
if (GetOpenFileName(&ofn) == TRUE)
{
hf = CreateFile(ofn.lpstrFile,
GENERIC_READ,
0,
(LPSECURITY_ATTRIBUTES)NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
(HANDLE)NULL);
}
}
Then I call it from my WM_COMMAND message:
case WM_COMMAND:
switch (wParam)
{
case 12:
OpenFile();
break;
}
But when the user presses the OK button in the OPENFILENAME, it doesn't read any text from the file. How can I accomplish this?
And I want to write files with a save file dialog. Tell me how to do that as well.
The main purpose of the functions GetOpenFileName and GetSaveFileName is to provide you with the filename that the user selected. However, doing the actual File Input and Output is a different issue. You can use the standard C/C++ library for that or you can use the Windows API functions, such as CreateFile, ReadFile and WriteFile.
Since you seem to already be using the function CreateFile, it would make sense to call ReadFile after verifying that the function call to CreateFile succeeded (i.e. that it did not return INVALID_HANDLE_VALUE). After reading the data, you can add a terminating null character to the data (you should make sure that the memory buffer is large enough) and then pass it to the SetDlgItemText function (if the text box is in a dialog box) or SetWindowText function.

Local html (RoboHelp) index online help file under MFC is not opened

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 ?

Showing a Windows Explorer Dialog from a C++ application

I have a windows application written in C++.
The application generates certain configuration files in a hidden directory.
I want to give user an option to open that directory from my application.
Clicking that option should open a windows explorer like dialog with an input directory location.
I spend time searching for a similar api, but end up with certain dialogs like "DlgDirListComboBoxW" or "GetOpenFileName" or "GetSaveFileName".
I am looking for an api to open normal Windows explorer like Dialog with an input directory location.
It would be really helpful if the api belongs to CommonDialogs section.
You can use the SHBrowseForFolder
It shows a dialog similar to this:
This is a example for how to use it:
BOOL GetFolder(LPCSTR folderpath,
LPCSTR szCaption,
HWND hOwner /*= NULL*/)
{
BOOL retVal = FALSE;
// The BROWSEINFO struct tells the shell
// how it should display the dialog.
BROWSEINFO bi;
memset(&bi, 0, sizeof(bi));
bi.ulFlags = BIF_USENEWUI;
bi.hwndOwner = hOwner;
bi.lpszTitle = szCaption;
// must call this if using BIF_USENEWUI
::OleInitialize(NULL);
// Show the dialog and get the itemIDList for the
// selected folder.
LPITEMIDLIST pIDL = ::SHBrowseForFolder(&bi);
if(pIDL != NULL)
{
// Create a buffer to store the path, then
// get the path.
char buffer[_MAX_PATH] = {'\0'};
if(::SHGetPathFromIDList(pIDL, buffer) != 0)
{
// Set the string value.
folderpath = buffer;
retVal = TRUE;
}
// free the item id list
CoTaskMemFree(pIDL);
}
::OleUninitialize();
return retVal;
}
How about:
HWND hWndOwner = NULL;
ShellExecute(
hWndOwner,
_T("explore"),
_T("c:\\some\\path"),
NULL,
NULL,
SW_SHOWNORMAL);
You can set hWndOwner to your main window handle if you're so inclined and can choose from a variety of other options.
For more information and usage details, check out the MSDN page on ShellExecute.

C++ program crashes after exit

I'm using the following function to open a dialog box, using the OPENFILENAME. Problem is, after opening the dialog box, and closing it, everything works fine, but when I exit my application then Windows says it crashed.
bool openDialog()
{
OPENFILENAME ofn; // common dialog box structure
char szFile[260]; // buffer for file name
HWND hwnd = NULL; // owner window
HANDLE hf; // file handle
// Initialize OPENFILENAME
ZeroMemory(&ofn, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = hwnd;
ofn.lpstrFile = szFile;
//
// Set lpstrFile[0] to '\0' so that GetOpenFileName does not
// use the contents of szFile to initialize itself.
//
ofn.lpstrFile[0] = '\0';
ofn.nMaxFile = sizeof(szFile);
ofn.lpstrTitle = "Open File";
ofn.lpstrFilter = "Custom File\0*.Cus\0";
ofn.nFilterIndex = 1;
ofn.lpstrFileTitle = NULL;
ofn.nMaxFileTitle = 0;
ofn.lpstrInitialDir = NULL;
ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
// Display the Open dialog box.
if (GetOpenFileName(&ofn) == true)
{
path = ofn.lpstrFile;
return true;
}
else
{
return false;
}
}
I noticed it was the dialog box because the crash only happens if I use it at runtime, meaning that when I close the application without opening the dialog box at some point, it exits successfully.
Anyways, as far as I researched, it is probably caused my a 'heap corruption' or something similar that I don't have much knowledge of, so when my application tries to close, it doesn't release memory as it should (?). If anyone could figure out a solution it'd be greatly appreciated.
Most likely the problem is to do with path if this is simply a const char * or char * declared outside the function.
When the openDialog function returns, both the ofn structure of type OPENFILENAME and character array szFile go out of scope (along with all the other local, stack-allocated variables) and are no longer valid. As a result, the character array that ofn.lpstrFile and consequently path point to is no longer valid.
You should allocate space for the file name outside the function and perform a copy with strcpy, strncpy or equivalent before returning from it. Another approach would be to move the szFile character array out of the function and into the containing class as a member variable. Either way, the scope of the character array containing the file name returned needs to extend beyond the lifetime of the execution of the openDialog function.

Problems using IFileDialog on Windows 7

I'm facing some weird (at least for me) behavior on using the Common Item Dialogs in my MFC Windows application running on Windows 7 or Vista.
According to the MSDN http://msdn.microsoft.com/en-us/library/windows/desktop/bb776913(v=vs.85).aspx I'm using the new interfaces to display file open and save dialogs:
bool OpenFileDialog(CString& strFile, CString strTitle, CStringArray& astrFilter, CStringArray& astrFilterExtension, ULONG nFlags, HWND hParentWnd)
{
USES_CONVERSION;
INT_PTR nResult = 0;
INT_PTR nFilterCount = astrFilter.GetCount();
IFileDialog* pfod = 0;
HRESULT hr = ::CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pfod));
if(SUCCEEDED(hr))
{
// New dialog starting with Vista/Windows 7
COMDLG_FILTERSPEC* pOpenTypes = 0;
if((nFilterCount > 0) && (nFilterCount == astrFilterExtension.GetCount()))
{
pOpenTypes = new COMDLG_FILTERSPEC[nFilterCount];
for(int nIdx = 0; nIdx < nFilterCount; nIdx++)
{
pOpenTypes[nIdx].pszName = astrFilter[nIdx].GetBuffer();
pOpenTypes[nIdx].pszSpec = astrFilterExtension[nIdx].GetBuffer();
}
}
// Set the file types to display.
if(pOpenTypes)
{
hr = pfod->SetFileTypes(nFilterCount, pOpenTypes);
if(SUCCEEDED(hr))
hr = pfod->SetFileTypeIndex(0);
}
if(!strFile.IsEmpty())
pfod->SetFileName(strFile);
if(!strTitle.IsEmpty())
pfod->SetTitle(strTitle);
if(SUCCEEDED(hr))
{
// Ensure the dialog only returns file system paths.
DWORD dwFlags;
hr = pfod->GetOptions(&dwFlags);
if(SUCCEEDED(hr))
{
dwFlags |= FOS_FORCEFILESYSTEM;
if(nFlags & OFN_FILEMUSTEXIST)
dwFlags |= FOS_FILEMUSTEXIST;
if(nFlags & OFN_PATHMUSTEXIST)
dwFlags |= FOS_PATHMUSTEXIST;
hr = pfod->SetOptions(dwFlags);
if(SUCCEEDED(hr))
{
// Create an event handling object, and hook it up to the dialog.
IFileDialogEvents* pfde = NULL;
DWORD dwCookie;
// Actually only added for debugging purposes
/*hr = CDialogEventHandler_CreateInstance(IID_PPV_ARGS(&pfde));
if(SUCCEEDED(hr))
{
// Hook up the event handler.
hr = pfod->Advise(pfde, &dwCookie);
if(!SUCCEEDED(hr))
{
pfde->Release();
pfde = 0;
}
}*/
// Now show the dialog. Usually called with hParent == 0
if(hParentWnd)
hr = pfod->Show(::GetWindow(hParentWnd, GW_OWNER));
else
hr = pfod->Show(0);
// do something with the path when the dialog was closed...
So the dialog appears and works fine if I want to select a file from a normal drive. I can navigate through the folders and select any file I want. On leaving the dialog I also get the correct file information.
But it doesn't work for one of the Libraries in the navigation pane on the left side. Whenever I try to select a Library like Documents, Videos or Pictures the dialog doesn't update the right pane which shows the folder/library content.
What I noticed is that on clicking a Library in the file open/save dialog the OnFolderChanging() event of the IFileDialogEvents interface is fired but the OnFolderChange() and OnSelectionChange() are not. Those events are fired if I click and navigate on a "normal" drive like C.
I also tried to call the dialogs early in my InitInstance method to avoid possible side-effects with my other code but this didn't help either.
Is there someone who had the same behavior and was able to resolve this?
Thanks a lot!
So I finally found the answer to this issue. Creating the new MFC project for the application was the actual hint to solve this. The reason was that the "Stack reserve size" was too big. The settings in the old VS6.0 project had the stack size increased to more than 100MB. Apparently the IFileDialog based dialogs do not work properly when the reserved stack size is simply too large (other thing might don't work also as expected). So I had to set it back to 15MB in my case.