|
Hi,
when a program runs fine on one system and not on another, there may be a difference in the environment, such as a missing DLL, or a different version of DLL. However, it may also indicate a simple bug in the program: running fine on a system is no proof of correctness.
Here are some ideas, the list is not complete!
- regional settings may be different, causing a conversion to sometimes fail. Example: date formatting could be dd-MMM-yyyy or MM/dd/yyyy, a string gets parsed fine in the one situation and not in the other. Now if the program also lacks decent error detection and reporting, you will be completely in the dark.
- some data gets stored somewhere, in a file, in registry, whatever; it is different on different systems and some values (or absence thereof) is not handled well. Example: assume a recent file list is kept in registry, it does not exist on some system, and as a result m_pRecentFileList->m_arrNames[0] is null (or undefined) and can not reliably be dereferenced.
Advice:
- check your code for proper error detection, reporting and handling;
- check your code dealing with inputs (registry, files, network locations, ...) as that is the greatest area of variance;
- check your system configuration, such as amount of memory.
|
|
|
|
|
Those are good points about the environment. Something like this would explain how it could be something specific about his system that isn't fixed by booting into Safe mode or not running Startup programs. I don't think it's date-format-related or it would be crashing on the computer of the Australian guy who's been testing the program, too. He's tried it on multiple systems with no problems.
I check return codes for everything - I went over every line of the startup code again.
Isn't the recent file list always stored in the registry for XP and above? My program targets XP and above. Anyway, I know it is on his system because my crash dump report includes the registry settings. I use this statement to enable and load the MRU files:
LoadStdProfileSettings(4);
My program does do a lot with input and output, and the InitInstance function mainly figures out paths for input and output. The input path is wherever the executable is. If the path ends up more than 260 characters, the program will put up an error message and terminate. Output is a subdirectory of MyDocs, which is created if it's not found. I check every return code and terminate cleanly if something goes wrong. I've traced through all the filename/path stuff in the debugger and it's working correctly.
He sent me some system specs from a diagnostic program he runs. I should look at it more carefully.
|
|
|
|
|
I am not familiar with LoadStdProfileSettings(4); . What does it return when there aren't any MRU files (in registry or where ever they get stored)?
one more typical mistake: one cannot store a file in a folder that does not yet exist.
|
|
|
|
|
It has no return code. Here's what Microsoft says about it:
http://msdn.microsoft.com/en-us/library/xbkh2k4h.aspx[^]
CWinApp::LoadStdProfileSettings
Call this member function from within the InitInstance member function to enable and load the list of most recently used (MRU) files and last preview state.
void LoadStdProfileSettings(
UINT nMaxMRU = _AFX_MRU_COUNT
);
I definitely create the output folder before I store anything in it.
|
|
|
|
|
I believe it is related to Heap Corruption.
Most probable reason is Buffer overrun.
Check for memory copy, memory concatenation etc in our code in that flow.
Some where in the code, you are using more memory than allocated.
These errors are hard to detect and crash on those machines, where it wont get that memory location, which is overrun from the allocation, because it might have benn already reserved.Величие не Бога может быть недооценена.
|
|
|
|
|
Are you in a position to be able to setup a remote debugging connection?
This allows you to step through the code on the target computer using the debugger on your PC.
There are some hoops to jump through to set it up, but it may be invaluable in helping to track down the root cause of the issue.If you vote me down, my score will only get lower
|
|
|
|
|
I've never done this and don't know how. What do you have to do to set it up?
|
|
|
|
|
I would recommend you do a search on the microsoft site for remote debugging in relation to the development platform your using. (Actually a straight google search for "remote debugging" should turn up what you need)
As the implementation of this has varied slightly over the years, I cannot give any direct description on how to perform it for your environment.If you vote me down, my score will only get lower
|
|
|
|
|
When I'm having issues that I cannot reproduce, then I use remote desktop/remote assistance to take control of the customer computer and install Windows Debug Tools (WinDbg).
WinDbg allows you to debug applications:
1) To see call stack while debugging then you need to upload Program Database files (PDB) generated with the EXE/DLL files.
2) To see source code then you need to upload the source used to compile the application.
3) To see values of variables (and not just addresses), then you need to compile the application without optimization turned on.
P.S. I would add the following to the problem line you have shown:
# Check that m_pRecentFileList != NULL
# Change m_arrNames to a proper container and check the size of that instead of using m_nSize
|
|
|
|
|
Yes, yes, and yes - thanks. I can see this is the direction I need to go.
I have WinDbg installed, but my knowledge of how to use it is minimal. I've used it to view crash dumps, but never for remote debugging and I don't know how that works. I need to google remote debugging for more detailed instructions.
Snakefoot wrote: I would add the following to the problem line you have shown:
# Check that m_pRecentFileList != NULL
# Change m_arrNames to a proper container and check the size of that instead of using m_nSize
Yeah, it's becoming clear to me that I need to check this pointer before trying to use it. The reason I didn't is that I didn't think there was any way it could be invalid after I'd made the call to LoadStdProfileSettings(4); . Could you tell me under what circumstances this structure might not be populated properly after this call? There's no return value to check with LoadStdProfileSettings.
I don't know what you mean by "change m_arrNames to a proper container". What is a "proper container". Confession: I learned to program in the pre-Windows DOS world (I am old) and I'm more adept with procedural programming than object-oriented programming.
|
|
|
|
|
A proper container is one that keeps track of its allocation like std::vector or MFC::CSimpleArray.
But I see that you are using CRecentFileList(), and it seems to be without such features.
|
|
|
|
|
I made a small change to the program, and now it's crashing on my own development system - which is sort of bad, but also sort of good.
The problem is not the line I quoted. It's crashing when it tries to run the app. I think I must have a buffer overrun somewhere, though I have no idea where. I looked at Bounds Checker but it costs $1500. Is there a cheaper alternative?
Geez - I am losing it, or I need more sleep or something. I deleted something crucial, that is all. Back to the original problem...modified on Wednesday, March 17, 2010 6:02 PM
|
|
|
|
|
Snakefoot wrote: A proper container is one that keeps track of its allocation like std::vector or MFC::CSimpleArray.
But I see that you are using CRecentFileList(), and it seems to be without such features.
I put in a check that the list exists, and for some reason I cannot fathom, it is not created properly on this one guy's system, though it works fine for everyone else.
I can't imagine what he can be doing on his computer that would prevent this standard MFC call from working properly. Does anyone know? I'd rather not do it all manually if I don't have to. I'd rather detect systems that don't support it, but I don't know of any reason why a system would not support it.
Can anyone make a guess on this?
|
|
|
|
|
I fixed the problem. I still have no idea why the standard call wasn't working on his system. But I changed this:
LoadStdProfileSettings(4);
to
CString strSection = "Recent File List";
CString strEntryFormat = "File%d";
m_pRecentFileList = new CRecentFileList(1, strSection, strEntryFormat, 4);
m_pRecentFileList->ReadList();
And voila! No crashes - it's working fine.
I can't believe I spent a week and a half of my life on this. On the plus side, my startup code is vastly cleaner after 10 days of intense scrutiny.
|
|
|
|
|
Hi,
NOTIFYICONDATA nid;
ZeroMemory(&nid,sizeof(nid));
nid.cbSize = sizeof(NOTIFYICONDATA);
nid.hWnd = hWnd;
nid.uID = 0;
nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
nid.uCallbackMessage = WM_USER;
nid.hIcon = LoadIcon(NULL, IDI_APPLICATION);
(nid.szTip,"Double-Click To Maximize.");
I have successfully got my application to show in the system tray but I want to add menu items when the user right clicks on the icon in the system tray.
Thank you.Andrew McIntyre
|
|
|
|
|
MrMcIntyre wrote: I have successfully got my application to show in the system tray but I want to add menu items when the user right clicks on the icon in the system tray.
You have to display the menu yourself. The CTrayIcon class in this article[^] encapsulates the display of a tray icon, and displays a menu in the OnTrayNotify method.Java, Basic, who cares - it's all a bunch of tree-hugging hippy cr*p
CodeProject MVP for 2010 - who'd'a thunk it!
|
|
|
|
|
Hi Andrew,
I hope this code will help you out.
What i normally do is first setup the basic funtionality for the try icon, something like this:
this->notifyIcon1->BalloonTipIcon = System::Windows::Forms::ToolTipIcon::Info;
this->notifyIcon1->Icon = (cli::safe_cast<System::Drawing::Icon^ >resources->GetObject(L"notifyIcon1.Icon")));
this->notifyIcon1->Text = L"Helios Options";
this->notifyIcon1->Visible = true;
this->notifyIcon1->MouseDoubleClick += gcnew System::Windows::Forms::MouseEventHandler(this, &Form1::notifyIcon1_MouseDoubleClick)
<pre>
Then i create a funtion that takes a couple of arguments to write and display certain text:
<pre>private: System::Void DoNotify(System::String^ Titlex, System::String^ Message, int Timeout)
{
notifyIcon1->ShowBalloonTip(Timeout,Titlex,Message,System::Windows::Forms::ToolTipIcon::Info);
}
<pre>
I then use the funtion like this:
<pre>DoNotify("Helios Minimised","Helios is still running\r\nDouble click icon to maximise",5);
I then handle the form resize funtion, this will show and hide the main window
private: System::Void Form1_Resize(System::Object^ sender, System::EventArgs^ e)
{
if(FormWindowState::Minimized == this->;WindowState)
{
DoNotify("Helios Minimised","Helios is still running\r\nDouble click icon to maximise",5);
this->Hide();
}
else if(FormWindowState::Normal == this->WindowState)
{
}
}
Then finally i hadle the function we created a event handler for at the notifyicon:
private: System::Void notifyIcon1_MouseDoubleClick(System::Object^ sender, System::Windows::Forms::MouseEventArgs^ e)
{
this->Show();
this->WindowState = FormWindowState::Normal;
}
I hope this will help you a little more.
Let me know if there is anything else i can help with.
Louis
|
|
|
|
|
Is that C# code on the example or C++. Andrew McIntyre
|
|
|
|
|
|
NOTIFYICONDATA nid;
memset(&nid, 0, sizeof(NOTIFYICONDATA));
nid.cbSize = sizeof(NOTIFYICONDATA);
nid.hWnd = hWnd;
nid.uID = 1;
nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
nid.uCallbackMessage = WM_USER + 200;
nid.hIcon = LoadIcon(NULL, IDI_INFORMATION);
lstrcpy nid.szTip, ("Test Tip");
Shell_NotifyIcon(NIM_ADD, &nid);
Hi Louis,
Can you help me fix this code so it can display the notify icon Title set as "Test" and in the code allow me to create menu items.
Thank you.Andrew McIntyre
|
|
|
|
|
Hi Andrew,
I have not used the Notifyicon in normall C++ yet, though the implementation thereof would not differ
much from C++/Clr i think. I could code something up for you, though are you only using C++? Cause this is all very simple using Clr. You simply add a Context menu strip and edit it via the normal GUI editor, and associate it then with your NotifyIcon from the editor or from code.
Louis
|
|
|
|
|
Louis,
I need it to be in C++.Andrew McIntyre
|
|
|
|
|
|
MrMcIntyre wrote: ...but I want to add menu items when the user right clicks on the icon in the system tray.
See here."One man's wage rise is another man's price increase." - Harold Wilson
"Fireproof doesn't mean the fire will never come. It means when the fire comes that you will be able to withstand it." - Michael Simmons
"Man who follows car will be exhausted." - Confucius
|
|
|
|
|
NOTIFYICONDATA nid;
memset(&nid, 0, sizeof(NOTIFYICONDATA));
nid.cbSize = sizeof(NOTIFYICONDATA);
nid.hWnd = hWnd;
nid.uID = 1;
nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
nid.uCallbackMessage = WM_USER + 200;
nid.hIcon = LoadIcon(NULL, IDI_APPLICATION);
nid.uTimeout = 5000;
nid.szInfoTitle, "BalloonTitle";
nid.szInfo, "TrayTip";
nid.szTip, "TrayTip";
Shell_NotifyIcon(NIM_ADD,&nid);
When I run this code the icon on the system tray the title does not appear or any of the input I want it to display when I hover over the icon. Please help.Andrew McIntyre
|
|
|
|
|