GetOpenFileName() does not refresh when changing filter - c++

I use GetOpenFilename() to let the user select a file. Here is the code:
wchar_t buffer[MAX_PATH] = { 0 };
OPENFILENAMEW open_filename = { sizeof (OPENFILENAMEW) };
open_filename.hwndOwner = handle_;
open_filename.lpstrFilter = L"Video Files\0*.avi;*.mpg;*.wmv;*.asf\0"
L"All Files\0*.*\0";
open_filename.lpstrFile = buffer;
open_filename.nMaxFile = MAX_PATH;
open_filename.lpstrTitle = L"Open media file...";
open_filename.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
::GetOpenFileNameW(&open_filename);
The file dialog shows up, but when I
change the Filter or
click on "My Computer"
the file list turns empty. Pressing [F5] does not help, but if I switch to the parent folder and return to the original folder (in the case of the Filter change) the filtering works fine and files show up in the list.
EDIT: My system is Windows XP (SP3) 32-bit - nothing special. It happens on other machines - with the same config - as well.

One thing you haven't done that might be causing problems is fully initialize the OPENFILENAMEW structure, especially the lStructSize element. I've seen this causing strange effects before. I'd suggest having something like
OPENFILENAMEW open_filename = { sizeof (OPENFILENAMEW) };
ZeroMemory(&open_filename, sizeof (OPENFILENAMEW));
open_filename.lStructSize = sizeof (OPENFILENAMEW);

Okay, I have figured out the problem, or at least, I have a solution that is working for me.
Earlier in the code, I had the following call to initialize COM...
::CoInitializeEx(NULL, COINIT_MULTITHREADED);
Well, changing this to...
::CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
...solves the problem for me! Now the file dialog is filtering again.
I searched the web for this and it seems that a very few people faces the same problem, but no one published the aforementioned solution. Can anyone verify my findings?

Thank you, beef2k. It works.
But my problem has a little difference.
Everything worked fine until I added the SHBrowseForFolder call. I had got the same effect since that moment. But adding CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); solved the problem.

Related

force SHBrowseForFolder() to show desired directory

I've been searching online and fighting this thing for over an hour and still can't seem to get it to work. Most people seem to be satisfied when they get it this far on forums etc. but mine still doesn't work.
I'm trying to force the SHBrowseForFolder() function to start in a folder of my choosing.
char current[MAX_PATH];
strcpy(current,"C:\\Users");
char outbuf[MAX_PATH];
BROWSEINFO bis;
bis.hwndOwner = NULL;
bis.pidlRoot = NULL;
bis.pszDisplayName = outbuf;
bis.lpszTitle = (LPCSTR)"HERE";
bis.ulFlags = BIF_NEWDIALOGSTYLE|BIF_RETURNONLYFSDIRS;
bis.lpfn = NULL;
bis.lParam = (LPARAM)current;
SHBrowseForFolder(
&bis
);
It seems like this should be a relatively simple task. :/
At the moment, the above code is still showing the default: the Desktop folder.
Beyond starting in a specific folder, if possible, I'd also like it to ONLY show that folder and below, with no access to parent directories.
What am I missing here?
You can also send a BFFM_SETSELECTION message from your BrowseCallbackProc, like:
int FAR PASCAL BrowseNotify(HWND hWnd, UINT iMessage, long wParam, LPARAM lParam)
{ if (iMessage == BFFM_INITIALIZED)
{ SendMessage(hWnd, BFFM_SETSELECTION, 1, (LPARAM) szInitialPathName); // Set initial folder
return 1;
}
return 0;
}
Set the BFFCALLBACK (lpfn) to a BrowseCallbackProc. From there you can call SendMessage with BFFM_SETEXPANDED to specify the path of a folder to expand in the Browse dialog box.
See:
http://msdn.microsoft.com/en-us/library/windows/desktop/bb773205(v=vs.85).aspx and
http://msdn.microsoft.com/en-us/library/windows/desktop/bb762598(v=vs.85).aspx
From my experience, that folder dialog is a bit flaky - it often scrolls the desired directory out of view and looks suboptimal. Just one of the joys of Windows...
Also, there is no way I have discovered to get it to show only that directory and its subs. The parent directories always seem to be there.
Set BIF.PidlRoot to the PIDL you don't want the user to browse below, select and expand the folder you want initially focused and selected - do as above - and it should work.
Jens. :)

What could prevent TBPF_INDETERMINATE progress bar from being displayed in taskbar?

I'm trying to implement the new Windows 7 taskbar progress bar. I managed to get it to work with TBPF_NORMAL state using the following code:
CoCreateInstance(CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&taskbarList));
HRESULT c = taskbarList->SetProgressState(hWnd, TBPF_NORMAL);
if (c != S_OK) MessageBox("ERROR");
taskbarList->SetProgressValue(hWnd, 5, 10);
However if I try the exact same code with TBPF_INDETERMINATE, it doesn't display anything and there's no error either:
CoCreateInstance(CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&taskbarList));
HRESULT c = taskbarList->SetProgressState(hWnd, TBPF_INDETERMINATE);
if (c != S_OK) MessageBox("ERROR");
Does anybody know what could be causing this problem?
Okay, it looks like it was a problem with the configuration of my system. I post the answer here because it's not obvious why one progress bar animation would work but not another.
In System Properties / Performance Options, I had "Animations in the taskbar and Start Menu" disabled. This option apparently disables the "indeterminate" animation but not the regular one. By re-enabling the option, the indeterminate animation works.
This happened to me too. In the code, I have a Form A that shows a Form B (which Form B in the OnLoad event calls SetProgressState) and after that Form A calls the method Close to itself, and when it was in Indeterminate mode it didn't show anything!
Surpringsly, if I close first Form A and then show Form B, the problem is solved!
I hope this can help somebody having a headache with this.

Maximized Window Restores to Full Screen

Using CWnd::ShowWindow(SW_SHOWMAXIMIZED) maximizes my app window as expected.
However, when clicking the restore button on the app (or double clicking the title-bar), the restored size is the same size as the maximized window, which is confusing for the user.
Using this alternative code has the same problem:
WINDOWPLACEMENT wndpl;
GetWindowPlacement(&wndpl);
wndpl.showCmd = SW_SHOWMAXIMIZED;
SetWindowPlacement(&wndpl);
How can I keep the default un-maximized size when restoring.
I've solved my problem, and the solution might solve yours too. My problem was that even though I called SetWindowPlacement(&wndpl) within CMainFrame::OnCreate the window was not properly restored if it was maximized. I added two lines of code before SetWindowPlacement, and now it works as expected.
CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
...
// Obtain wndpl, maybe from registry
AfxGetApp()->m_nCmdShow = wndpl.showCmd;
wndpl.showCmd = SW_SHOW;
SetWindowPlacement(&wndpl);
}
These two lines helps underlying code not to mess things up when calling ActivateFrame, which calls ShowWindow with parameter obtained from CWinApp::m_nCmdShow.
All information are in the file with extension .RC. I never used a Maximize/Restore procedures though you should look for a 'DIALOGEX' for the same window. You can change it using any editor (notepad, ultraedit etc.)

PDFCreator will print TIFF instead of PDF

I am trying to convert a RTF document to PDF. I have this code:
// TestCOMPDF.cpp : Defines the entry point for the console application.
//
#include <windows.h>
#include <tchar.h>
#include <objbase.h>
#include <atlbase.h>
#import "MSVBVM60.DLL" rename ( "EOF", "VBEOF" ), rename ( "RGB", "VBRGB" ) //if you don't use this you will be in BIG trouble
#import "PDFCreator.exe"
int _tmain(int argc, _TCHAR* argv[])
{
CoInitialize(NULL);
{
CComPtr<PDFCreator::_clsPDFCreator> pdfObject;
HRESULT hr = pdfObject.CoCreateInstance(L"PDFCreator.clsPDFCreator");
pdfObject->cStart("/NoProcessingAtStartup", 1);
PDFCreator::_clsPDFCreatorOptionsPtr opt = pdfObject->GetcOptions();
opt->UseAutosave = 1;
opt->UseAutosaveDirectory = 1;
opt->AutosaveDirectory = "c:\\temp\\";
opt->AutosaveFormat = 0; // for PDF
opt->AutosaveFilename = "gigi13";
pdfObject->PutRefcOptions(opt);
pdfObject->cClearCache();
_bstr_t DefaultPrinter = pdfObject->cDefaultPrinter;
pdfObject->cDefaultPrinter = "PDFCreator";
hr = pdfObject->cPrintFile("c:\\temp\\RTF\\garage.rtf");
pdfObject->cPrinterStop = false;
while(true)
{
printf("sleep\n");
Sleep(1000);
if(pdfObject->cCountOfPrintjobs == 0)
break;
}
printf("done\n");
pdfObject->cPrinterStop = true;
pdfObject->cDefaultPrinter = DefaultPrinter;
}
CoUninitialize();
return 0;
}
When running this code sample instead of creating directly the PDF it prompts me with a Save dialog offering me the option to the output only with the option of choosing a TIFF file (which is not wanted). Can someone point me into the right direction or offer some suggestions?
Thanks,
Iulian
This is only a guess... I had a similar problem -- not when using PDFCreator programmatically (this is beyond my capabilities), but when using it as my standard printer to print to PDFs.
First I used it for a couple of days without any problem. Not I had installed it, but my partner. As I said... it just worked, and created beautiful PDFs.
Then, somehow, someone on our home computer (we are 3 different persons using it) must have changed the setting (maybe inadvertedly) to make it output TIFF instead of PDFs. For me, my default printer was named "PDFcreator" and it confused the hell out of me why it suddenly wanted to create TIFFs.
Meanwhile I've poked a lot in the user interface of all its settings, and learned to know where to look if something goes wrong.
The newest version in its lefthand treeview panel lists an item named "Save". If you select it, you can configure default filename conventions as well as "Standard save format". In my case in the dropdown listview there was "TIFF" selected instead of "PDF".
Looking at your code, you are somehow calling PDFCreator.exe (I don't understand the details, but I can see this string in your code). My bet would go towards this: somehow, the user account which your code uses to run under has his Standard save format set to TIFF. It may be that you look at the printer settings (on my Windows XP, I just type control printers, and rightclick the PDFCreator printername to select Properties...) and find nothing suspicious.
However, PDFcreator stores its settings for each user into a different location, probably in %userprofile%\local settings\temp\pdfcreator\..., or even in the registry...

What is the "Shell Namespace" way to create a new folder?

Obviously this is trivial to do with win32 api - CreateDirectory(). But I'm trying to host an IShellView, and would like to do this the most shell-oriented way. I would have thought that there would be a createobject or createfolder or some such from an IShellFolder. But neither IShellView nor IShellFolder nor even IFolderView seem to have anything quite like this.
Is there a Shell-programming way to create a new folder? Or do I need to create a folder using a pathname, the old-fashioned way?
If I have to do it via CreateDirectory(), then my next question might be: any ideas as to how to get the IShellView / IFolderView to actually see this new object and display it to the user?
Motivation: Creating my own File Dialog replacement and I want to provide the "new folder" toolbar icon functionality of the standard XP-style file dialog.
EDIT: I went ahead and created something that basically works, using CreateDirectory. However, I'm still hoping that there's a better way to do this, but so that you can see how that works, and to offer better ideas as to solve this issue better:
PidlUtils::Pidl pidl(m_folder);
CFilename folderName(GetDisplayNameOf(pidl), "New Folder");
for (int i = 2; folderName.Exists(); ++i)
folderName.SetFullName(FString("New Folder (%d)", i));
if (!CPathname::Create(folderName, false))
throw CContextException("Unable to create a new folder here: ");
// get the PIDL for the newly created folder
PidlUtils::Pidl pidlNew;
#ifdef UNICODE
const wchar_t * wszName = folderName.c_str();
#else
wchar_t wszName[MAX_PATH];
MultiByteToWideChar(CP_ACP, 0, folderName.GetFullName(), -1, wszName, MAX_PATH);
#endif
m_hresult = m_folder->ParseDisplayName(NULL, NULL, wszName, NULL, pidlNew, NULL);
if (FAILED(m_hresult))
throw CLabeledException(FString("Unable to get the PIDL for the new folder: 0x%X", m_hresult));
// upgrade our interface so we can select & rename it
CComQIPtr<IShellView2> sv2(m_shell_view);
if (!sv2)
throw CLabeledException("Unable to obtain the IShellView2 we need to rename the newly created folder.");
// force it to see thew new folder
sv2->Refresh();
// select the new folder, and begin the rename process
m_hresult = sv2->SelectAndPositionItem(pidlNew, SVSI_EDIT|SVSI_DESELECTOTHERS|SVSI_ENSUREVISIBLE|SVSI_POSITIONITEM, NULL);
if (FAILED(m_hresult))
throw CLabeledException(FString("Unable to select and position the new folder item: 0x%X", m_hresult));
Yes, you can get IContextMenu and look for sub menus, but why bother, just call SHChangeNotify after you call CreateDirectory
Shell folders usually implement the IStorage interface, so this is pretty simple. For example, the following creates a folder named "abcd" on the desktop:
CComPtr<IShellFolder> pDesktop;
HRESULT hr = SHGetDesktopFolder(&pDesktop);
if (FAILED(hr)) return;
CComQIPtr<IStorage> pStorage(pDesktop);
if (!pStorage) return;
CComPtr<IStorage> dummy;
hr = pStorage->CreateStorage(L"abcd", STGM_FAILIFTHERE, 0, 0, &dummy);
The Win32 API function CreateDirectory seems to be the "correct way". At least, I can find nothing better - and the answers here don't really shed any light on a better way to do it.