I'm having an issue with some MFC printing code lately. To describe the issue at a high level, we're getting problems when we try to print the same document twice. (Really, it doesn't have to be the SAME document. It seems that it happens when two documents are printed and the child window isn't destroyed and created between them.) The first time, the document prints fine. The second time, the program crashes with an uncaught exception.
This also only started happening after a recent upgrade. This is code that I've literally never touched. It worked fine in version 5 when we were using VS2005 and MFC8. But then, when we upgraded to VS2008 and MFC9, this started happening.
Here's the problem code:
void CReportWnd::OnPrint()
{
CDC dc;
CPrintDialog dlg (FALSE);
CPrintDialog defaults(FALSE);
DEVMODE *ldev_printinfo;
int li_first = 0;
int li_last;
int ret = defaults.GetDefaults();
ldev_printinfo = defaults.GetDevMode();
//ldev_printinfo->dmOrientation = DMORIENT_LANDSCAPE;
dc.Attach (defaults.GetPrinterDC ());
dc.ResetDC(ldev_printinfo);
PROPrint(1, NULL, &dc, NULL, &li_last, true);
dlg.m_pd.hDevMode = ldev_printinfo;
dlg.m_pd.Flags &= ~PD_NOPAGENUMS;
dlg.m_pd.nMinPage = 1;
dlg.m_pd.nFromPage = 1;
dlg.m_pd.nMaxPage = li_last;
dlg.m_pd.nToPage = li_last;
if (dlg.DoModal () == IDOK) {
dc.DeleteDC();
dc.Detach();
dc.Attach (dlg.GetPrinterDC ());
} else {
return;
}
//Set up document info (need to set the name)
DOCINFO di;
::ZeroMemory (&di, sizeof (DOCINFO));
di.cbSize = sizeof (DOCINFO);
di.lpszDocName = "Report";
if(dc.StartDoc(&di) <= 0) {
return;
}
if(dlg.PrintRange()) {
li_first = dlg.m_pd.nFromPage - 1;
li_last = dlg.m_pd.nToPage - 1;
}
//Now do the actual print job to the printing device
PROPrint(1, NULL, &dc, &li_first, &li_last, false);
}
On the int ret = ... line near the top is where the exception is thrown. GetDefaults() throws an access violation exception. But again, only the second time that this function is called. It seems to me like it's some sort of resource issue. Like a resource isn't being freed and allocated properly. But I'm so inexperienced with printing that it could be anything.
If anybody could offer any kind of help, I would really appreciate it.
Also, yes, I know that I can just catch the exception. My issue is, how do I handle the exception and still print the document?
EDIT:
It seems as if our program is having this issue in multiple places, not just with this particular set of code. It makes me think that the issue might not be in this code specifically. I'm working on it now and I kind of have to get it fixed, so when I figure out the solution, I'll be sure to post back. Until then, I'm always open to suggestions.
Not sure, but could it be because the code is deleting the default device context associated with the default printer? Try removing the dc.DeleteDC() line to give you:
if (dlg.DoModal() == IDOK)
{
dc.Detach();
dc.Attach(dlg.GetPrinterDC());
}
else
return;
Related
I create an GtkFixed object and put it into GtkEventBox via gtk_container_add (with destroying previous child, of course). This way works fine on Windows, but on Mac it crashes.
Stack trace showed me that app crashed on gtk_get_parent. I've tried to user set_parent procedure, but it crashes too:
[debug][New Thread 0x1b0f of process 88699]
[debug]Program received signal SIGSEGV, Segmentation fault.
[debug]0x0000000100b3cf3d in gtk_widget_set_parent () from /usr/local/lib/libgtk-3.0.dylib
[debug]>>>>>>cb_gdb:
Program received signal SIGSEGV, Segmentation fault.
In gtk_widget_set_parent () (/usr/local/lib/libgtk-3.0.dylib)
[debug]> bt 30
[debug]#0 0x0000000100b3cf3d in gtk_widget_set_parent () from /usr/local/lib/libgtk-3.0.dylib
Code runned in main thread and in "realize" callback of Window. Same.
The code is:
void main_view_reset_list_view(GtkWidget* list_view, GtkWidget* new_item)
{
GtkEventBox* eb = GTK_EVENT_BOX(list_view);
GtkBin* bin = GTK_BIN(list_view);
GtkContainer* container = GTK_CONTAINER(list_view);
GtkWidget* subview;
subview = gtk_bin_get_child(bin);
if (subview)
{
gtk_container_remove(container, subview);
gtk_widget_unparent (subview);
gtk_widget_destroy(subview);
}
gtk_widget_set_parent(new_item, container); // crash
GtkWidget* parent = gtk_widget_get_parent(container);
GtkWidget* parent2 = gtk_widget_get_parent(new_item); // 0 on windows, crash on mac
if (new_item)
{
gtk_container_add(container, new_item);
gtk_widget_show(new_item);
}
gtk_widget_show(list_view);
}
UPD:
set_parent makes controls dissapeared somehow on windows
I've traced gtk and glib source code and figured that G_IS_OBJECT() fails, which is quite weird. This post have brought me to mind that this issue is pointer-related. I've debugged my code and saw that it is true.
GtkWidget* create_widget()
{
return gtk_fixed_new(); // result points to 0x1018bf830
}
void refresh_widgets()
{
GtkWidget* w = create_widget(); // w points to 0x18bf830
}
I've actually faced with this kind of issue before, so all code which return pointers has been changed:
char* generate_string();
to
void generate_string(char** out);
So in order to fix my problem I have to provide correct pointers in this way. Like:
void create_widget(GtkWidget** out);
UPD: I've noticed difference between pointers. Shortly say, somehow they are trimmed to 32 bit on 64 bit system on return.
UPD2: Finally, I've made all changes and it works that way.
Anybody got this problem, anyway I didn't find an answer. The code is simple:
void CbDlg::OnBnClickedOk()
{
for(int i=0; i<1000; i++)
{
HRSRC hRes = ::FindResource(NULL, MAKEINTRESOURCE(IDR_MAINFRAME), RT_GROUP_ICON);
HGLOBAL hResLoad = ::LoadResource(NULL, hRes);
BYTE* pIconBytes = (BYTE*)::LockResource(hResLoad);
int nId = ::LookupIconIdFromDirectory(pIconBytes, TRUE);
hRes = ::FindResource(NULL, MAKEINTRESOURCE(nId), RT_ICON);
DWORD read = ::SizeofResource(NULL ,hRes);
hResLoad = ::LoadResource(NULL, hRes);
pIconBytes = (BYTE*)::LockResource(hResLoad);
if(pIconBytes != NULL)
{
HICON hIcon = ::CreateIconFromResource(pIconBytes, read, TRUE, 0x00030000);
DWORD e = ::GetLastError();
if(hIcon != NULL)
{
::DestroyIcon(hIcon);
}
}
}
}
If I click the Ok button four times (On my computer), CreateIconFromResource start to return NULL (It worked fine before and I could even draw out the icon). As to the GetLastError, it's always return 6 whatever CreateIconFromResource return NULL or not.
When this problem happened, if I drag the title bar to move, UI crashed, see the pictrue.
Of course you can understand this piece of code is just a demo, my real business need to call CreateIconFromResource thousands of times just like this.
UPDATE:
According to Hans' suggestion, I keep tracking the Handles/USER Objects/GDI objects, and found that USER Objects grows 1000 and GDI objects grows 2000 against each clicking to OK button (handles didn't grow), and GDI objects is 9999 when problem happens. But how to release them correctly, when I finish to use? I didn't use that much at one time, but need to load, release, load again, release again... Just like this demo. As MSDN document, I called DestroyIcon for every HICON. What else do I need to do, to finally release the USER/GDI objects?
I found the answer. The success or failure is all due to MSDN.
It says:
"The CreateIconFromResource function calls CreateIconFromResourceEx passing LR_DEFAULTSIZE|LR_SHARED as flags" AND "Do not use this function(DestroyIcon) to destroy a shared icon"
But It also says:
"When you are finished using the icon, destroy it using the DestroyIcon function" in CreateIconFromResource's document.
Actually, the second statement is WRONG.
So, the solution is, using CreateIconFromResourceEx without LR_SHARED, and DestroyIcon every HICON after using.
I'm debugging Qt5.3.1 on Mac, because my program freezes sometimes (intermittent ). I discovered that it is because the QTimer can't work properly.
In Qt code, they use the following two lines to trigger function activateTimersSourceCallback
CFRunLoopSourceSignal(d->activateTimersSourceRef);
CFRunLoopWakeUp(mainRunLoop());
void QCocoaEventDispatcherPrivate::activateTimersSourceCallback(void *info)
{
static int counter = 0;
NSLog(#"finished activeteTimersSourceCallback %d", counter++);
}
but sometimes, these two lines doesn't work, activateTimersSourceCallback won't get called.
I googled, but I couldn't find any solution? is this a known OS bug?
the initialization details:
// keep our sources running when modal loops are running
CFRunLoopAddCommonMode(mainRunLoop(), (CFStringRef) NSModalPanelRunLoopMode);
CFRunLoopSourceContext context;
bzero(&context, sizeof(CFRunLoopSourceContext));
context.info = d;
context.equal = runLoopSourceEqualCallback;
// source used to activate timers
context.perform = QCocoaEventDispatcherPrivate::activateTimersSourceCallback;
d->activateTimersSourceRef = CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &context);
Q_ASSERT(d->activateTimersSourceRef);
CFRunLoopAddSource(mainRunLoop(), d->activateTimersSourceRef, kCFRunLoopCommonModes);
Such behavior very likely can occur when UI event loop is overloaded with events or some business logic takes too long time. You should to check your business logic and move it to separate thread or run asynchronous.
This error shows up when run the program and try to load an image:
A first chance exception of type 'System.ArgumentException' occurred in System.Drawing.dll
An unhandled exception of type 'System.ArgumentException' occurred in System.Drawing.dll
Additional information: The parameter is invalid.
Here is my code:
Basically, there is a numericUpDown, a button, an openFileDialog and a pictureBox. The user changes the numericUpDown's value, depending on which picture he wants to load (the user doesn't have to open the openFileDialog). For example, if the user chooses "3" as a value for the numericUpDown, the FileName of the openFileDialog will be:
Public:
void Set_FilePath()
{
int n = (int)numericUpDown1->Value;
switch (n)
{
case 1: openFileDialog1->FileName = "C:\Users\Public\Pictures\Sample Pictures\Chrysanthemum.jpg"; break;
case 2: openFileDialog1->FileName = "C:\Users\Public\Pictures\Sample Pictures\Desert.jpg"; break;
case 3: openFileDialog1->FileName = "C:\Users\Public\Pictures\Sample Pictures\Hydrangeas.jpg"; break;
case 4: openFileDialog1->FileName = "C:\Users\Public\Pictures\Sample Pictures\Jellyfish.jpg"; break;
case 5: openFileDialog1->FileName = "C:\Users\Public\Pictures\Sample Pictures\Koala.jpg"; break;
case 6: openFileDialog1->FileName = "C:\Users\Public\Pictures\Sample Pictures\Lighthouse.jpg"; break;
case 7: openFileDialog1->FileName = "C:\Users\Public\Pictures\Sample Pictures\Penguins.jpg"; break;
case 8: openFileDialog1->FileName = "C:\Users\Public\Pictures\Sample Pictures\Tulips.jpg"; break;
}
}
private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) {
Bitmap^ myImage;
Set_FilePath();
myImage = gcnew Bitmap( openFileDialog1->FileName );
pictureBox1->SizeMode = PictureBoxSizeMode::StretchImage;
pictureBox1->Image = dynamic_cast <Image^> (myImage);
}
My attempt to fix it:
I thought that i didn't copy the directions of the images correctly. So i changed the code to:
if(openFileDialog1->ShowDialog() == System::Windows::Forms::DialogResult::OK)
{
MessageBox::Show(openFileDialog1->FileName);
myImage = gcnew Bitmap( openFileDialog1->FileName );
pictureBox1->SizeMode = PictureBoxSizeMode::StretchImage;
pictureBox1->Image = dynamic_cast <Image^> (myImage);
}
This is working perfectly. Also, a messagebox that shows the filename of openFileDialog is appeared... The directions of the images that are correct... I don't know what is wrong with my program. The problem is that i don't want the openFiledialog to be appeared.
(I am using Visual Studio C++ 2010, the application is made in windows form), Any help would be appreciated.
Thanks..
Exceptions raised by the Image and Bitmap classes are not very informative. You can get an "The parameter is invalid" exception for several reasons. It could be an image file that's corrupted, not that likely in your case since you are using stock Windows image files. It can also be caused by an image that's too large to fit in the available virtual memory address space. You'd like an OutOfMemoryException but GDI+ is goofy about it.
That's the more likely cause, your program is pretty likely to bite the dust like that when you run it for a while. Images can require a lot of unmanaged virtual memory to store their pixel data. And that should be released when you no longer use the image. The garbage collector will do that for you, but it isn't all that quick about it. Certainly an issue with the Bitmap class, it uses very little GC heap so isn't terribly likely to trigger a garbage collection often enough to keep you out of trouble.
Which is why it implements the IDisposable interface. The Dispose() method gets that memory released early. You are not calling it.
You'll need to fix that in your code, like this:
delete picureBox1->Image;
try {
myImage = gcnew Bitmap( openFileDialog1->FileName );
pictureBox1->Image = myImage;
}
catch (Exception^ ex) {
pictureBox1->Image = nullptr;
MessageBox::Show(ex->Message);
}
Note the added delete operator call, that's the one that calls IDisposable::Dispose(). It gets rid of the old image, the one you don't need anymore because you are going to display another image. The try/catch ensures that your program keeps running when the chips are down, dealing with a bad image file or a monster one that just can't fit in available memory. The kind that you deal with by targeting x64 so you get a 64-bit program.
We need to alter the selected file type filter in an active Vista/Win7 Open File dialog from IFileDialogControlEvents::OnButtonClicked. IFileDialog::SetFileTypeIndex updates the text in the combo box, but the list of items is not refreshed, which means that the items no longer reflect what's in the "Files of Type" combo box.
We've tried various ways to refresh the view, without success. Does anyone have a technique to do this?
One possible clue: The view isn't refreshed even if you manually click the Refresh button, which leads us to believe that maybe an internal value in the common dialog isn't updated by IFileDialog::SetFileTypeIndex. Is there something else we need to do?
Update: It turns out that a subsequent call to IFileDialog::GetFileTypeIndex doesn't return the index that we just set using SetFileTypeIndex, even though the combo box is showing the correct filter. This makes me think even more that there is some internal value in IFileDialog that doesn't get updated by SetFileTypeIndex if the dialog is already open.
Update:
This is a Windows bug. See workaround code below.
Can you provide your CFD code? It works fine for me. Is this what you're trying to do?
int _tmain(int argc, _TCHAR* argv[])
{
IFileDialog *pfd = NULL;
HRESULT hr = CoInitialize(NULL);
if (SUCCEEDED(hr))
{
hr = CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pfd));
if (SUCCEEDED(hr))
{
COMDLG_FILTERSPEC rgSpec[] =
{
{L"Text Documents (*.txt)", L"*.txt"},
{L"All Files (*.*)", L"*.*"}
};
hr = pfd->SetFileTypes(ARRAYSIZE(rgSpec), rgSpec);
if (SUCCEEDED(hr))
{
UINT ix;
pfd->Show(NULL);
pfd->SetFileTypeIndex(2);
pfd->Show(NULL);
pfd->GetFileTypeIndex(&ix);
printf("%d\n", ix);
}
}
}
return 0;
}
Microsoft has confirmed this as a bug in Vista and Windows 7 RTM. Here is a workaround provided by MS. In our case, we want to set the file type filter to *.*. This code puts *.* in the file name edit, which resets the filter and refreshes the view. (I haven't investigated what happens if you try to set a different filter using *.doc or something similar.)
if (SUCCEEDED(pFileDialog->SetFileName(L""))
&& SUCCEEDED(pFileDialog->SetFileName(L"*.*")))
{
IOleWindow *pOleWindow;
if (SUCCEEDED(pFileDialog->QueryInterface(IID_PPV_ARGS(&pOleWindow))))
{
HWND hwnd;
if (SUCCEEDED(pOleWindow->GetWindow(&hwnd)))
{
PostMessage(hwnd, WM_COMMAND, IDOK, 0);
}
pOleWindow->Release();
}
}
(The code sets the filename twice to get around some optimization that the Windows code would perform if the filename edit already contains *.*.)