|
Thank you for feedback, I will try what you said, but right now I haven't newer environment then VC6 ... Thank you.
|
|
|
|
|
Technically, he is with the initializer
NOTIFYICONDATA nid = {sizeof(NOTIFYICONDATA)}; but it only works because the .cbSize element is offset 0. This is bad programming practice. Doublly so since he responded to your suggestion with "I will try what you said", meaning that he didn't know he was initializing it, probably somebody else's code he's trying.
Best practices would the to explicitly initialize the structure like this
NOTIFYICONDATA tnid;
memset(&tnid, 0, sizeof(tnid));
tnid.cbSize = sizeof(NOTIFYICONDATA);
tnid.hWnd = GetSafeHwnd();
etc...
|
|
|
|
|
Chuck O'Toole wrote: Technically, he is with the initializer
Wow, learn something every day. I didn't realize that's what that code does.
The difficult we do right away...
...the impossible takes slightly longer.
|
|
|
|
|
Did you also ever create the notify icon by calling Shell_NotifyIcon with NIM_ADD.
See this MSDN page[^] for a technical description of the function.
|
|
|
|
|
Yes, of course, I have already icon in system tray. I just want to setup NIM_MODIFY parameter to show up a baloon notification.
|
|
|
|
|
Does the code work if you make the proposed modification of explicitly setting cbSize, along with the following: nid.uFlags = NIF_INFO; rather than |= which can (and I think in this case does) lead to errors?
|
|
|
|
|
This code works for me. You're probably missing some flag in your code.
void CMainFrame::PopupTrayBalloon(CString title, CString msg)
{
NOTIFYICONDATA tnid;
OSVERSIONINFO ver;
ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
if (!GetVersionEx(&ver)) return;
if ((ver.dwPlatformId == VER_PLATFORM_WIN32_NT) && (
((ver.dwMajorVersion == 5) && (ver.dwMinorVersion > 0)) ||
((ver.dwMajorVersion == 6) && (ver.dwMinorVersion >= 0)) ))
{
memset(&tnid, 0, sizeof(tnid));
tnid.cbSize = sizeof(NOTIFYICONDATA);
tnid.hWnd = GetSafeHwnd();
tnid.uFlags = NIF_MESSAGE | NIF_ICON | NIF_INFO;
tnid.dwInfoFlags = NIIF_INFO;
tnid.uTimeout = 10000;
lstrcpyn(tnid.szInfoTitle, title, sizeof(tnid.szInfoTitle));
lstrcpyn(tnid.szInfo, msg, sizeof(tnid.szInfo));
tnid.hIcon = LoadIcon(GetMainInstance(), MAKEINTRESOURCE(IDR_MAINFRAME));
tnid.uCallbackMessage = MY_ICONNOTIFICATION;
Shell_NotifyIcon(NIM_MODIFY, ((NOTIFYICONDATA *)&tnid));
}
}
|
|
|
|
|
Thank you very much ! I will try this code.
|
|
|
|
|
Does the supplied code work? Please also check out my other post, as it might help you in the future (for instance, when testing on 64 bits).
|
|
|
|
|
Why are you using GetVersion in this way? If this code now attempts to run under a future OS it will fail, without any need. For instance, if Windows 8 (or later) gets a major version of 7 then this code will artificially stop running. You should really use better version checks of Windows, as this can lead to real problems in the future.
A little further note on compatibility, rather than using lstrcpyn use StringCchCopy as advised by MSDN. Also, sizeof(tnid.szInfoTitle) returns the amount of char's, meaning it's twice as big as it should be under Unicode, which effectively removes the security layer add by using this particular function over a simple _tcscpy.
Ok, I'm sounding like a real nagger here. I don't mean to, I just want to avoid hard-to-solve bugs in the future.
|
|
|
|
|
The code was offered as a way of showing all the fields that need to be filled in to achieve a working solution, cut / paste at your own peril.
I can't predict what a future OS might look like, nor can you. However, I do know that some old OS'es do not support the balloon so I do not attempt it there, the results are unpredictable.
Thanks for your comments
|
|
|
|
|
Finnaly I get the notify baloon with follow code :
BOOL CMainFrame::ShowNotifyBaloon(LPCTSTR lpszBalloonTitle, LPCTSTR lpszBalloonMsg, DWORD dwIcon, UINT nTimeOut)
{
ASSERT (dwIcon == NIIF_WARNING || dwIcon == NIIF_ERROR || dwIcon == NIIF_INFO || dwIcon == NIIF_NONE);
NOTIFYICONDATA nid;
memset(&nid,0,sizeof(nid));
nid.uID = 0;
nid.dwInfoFlags = dwIcon;
nid.hWnd = GetSafeHwnd();
nid.cbSize = sizeof(NOTIFYICONDATA);
nid.uFlags = NIF_MESSAGE | NIF_ICON | NIF_INFO;
nid.uTimeout = nTimeOut;
nid.uCallbackMessage = WMU_TRAYNOTIFYICON;
::strcpy(nid.szInfoTitle,lpszBalloonTitle);
::strcpy(nid.szInfo,lpszBalloonMsg);
return ::Shell_NotifyIcon(NIM_MODIFY,&nid);
}
but still has a problem : when baloon show up, the systemtray icon dissapear !? Why ? I compile code with VC6 + SDK, and I try it on Win7.
|
|
|
|
|
I realize you had to make changes to my code but I don't think the .dwInfoFlags field is where you stick the dwIcon. And you don't fill in the .hIcon field in the structure so I'm not surprised that the icon disappears. Go back and check the code I posted
|
|
|
|
|
Lookup the definition of the flag NFI_ICON, it says:
NIF_ICON (0x00000002)
0x00000002. The hIcon member is valid.
but you didn't fill in the .hIcon field (well, memset() zeroed it).
Either give it an Icon handle in .hIcon or remove the NFI_ICON flag.
|
|
|
|
|
You are right, and it is good to avoid calling the function on OSes that are too old to support it. But we can reasonably assume that the code will work on future OSes, as has most always been the case with Windows (high level of backwards compatibility, via extended (FuncXyzEx) functions), so I was suggesting only setting a minimum.
When changing the compatibility setting for an executable to an older version of windows, the GetVersion API changes along to display the 'emulated' setting. The reason is does this is to 'fix' code that does version checks 'the wrong way' (restricting it from above. Such as applications for XP that stop working on Windows 7 because they only checked if major version was 5).
While searching for an article I once saw, I found this: VerifyVersionInfo Function[^] which does what we want for us.
|
|
|
|
|
Finally goes fine ... here is the code :
BOOL CMainFrame::ShowNotifyBaloon(LPCTSTR lpszBalloonTitle, LPCTSTR lpszBalloonMsg, DWORD dwIcon, UINT nTimeOut)
{
ASSERT(dwIcon == NIIF_WARNING || dwIcon == NIIF_ERROR || dwIcon == NIIF_INFO || dwIcon == NIIF_NONE);
NOTIFYICONDATA nid;
memset(&nid,0,sizeof(nid));
nid.uID = 0;
nid.dwInfoFlags = dwIcon;
nid.hWnd = GetSafeHwnd();
nid.cbSize = sizeof(NOTIFYICONDATA);
nid.uFlags = NIF_MESSAGE | NIF_ICON | NIF_INFO;
nid.uTimeout = nTimeOut;
nid.hIcon = theApp.LoadIcon(MAKEINTRESOURCE(IDR_MAINFRAME));
nid.uCallbackMessage = WMU_TRAYNOTIFYICON;
::strcpy(nid.szInfoTitle,lpszBalloonTitle);
::strcpy(nid.szInfo,lpszBalloonMsg);
return ::Shell_NotifyIcon(NIM_MODIFY,&nid);
}
Thank you very much, for your kindness and patience !
|
|
|
|
|
Anytime. PS, if you found some of the answer useful, give them a good rating.
|
|
|
|
|
I am trying to debug a program that is having a strange issue. When I first build and run the program it saves an image file, but after a series of saves the program will suddenly have a windows exception thrown. The error is happening at this point in the code:
void CDlg_ScanAcq::OnPlaceData()
CString title;
title.Format("%06d.stm",theInst->m_Flags.ScanNumber);
strcat(pDoc->m_Header.FileName, title);
pDoc->SetTitle(title);
pDoc->m_Ready = true;
pDoc->SetModifiedFlag(true);
pDoc->ShowAllViews();
CWinSTMApp *theApp = (CWinSTMApp*)AfxGetApp();
CString path;
path = theApp->m_Default.SaveDir + title;
pDoc->SetPathName(path);
This leads me to the exception being thrown here
void CRecentFileList::Add(LPCTSTR lpszPathName, LPCTSTR lpszAppID)
{
if (!afxGlobalData.bIsWindows7)
{
Add(lpszPathName);
return;
}
CString strAppID = lpszAppID == NULL ? _T("") : lpszAppID;
#if (WINVER >= 0x0601)
ASSERT(AfxIsValidString(lpszPathName));
Add(lpszPathName);
HRESULT hr = S_OK;
CComPtr<IShellItem> psi = NULL;
#ifdef UNICODE
hr = afxGlobalData.ShellCreateItemFromParsingName(lpszPathName, NULL, IID_IShellItem, reinterpret_cast<void**>(&psi));
#else
{
USES_CONVERSION;
LPOLESTR lpWPath = A2W(lpszPathName);
hr = afxGlobalData.ShellCreateItemFromParsingName(lpWPath, NULL, IID_IShellItem, (LPVOID*)&psi);
}
#endif
ENSURE(SUCCEEDED(hr));
If I manually save the data, which is an image, then everything is fine...but this very inconvenient and I would like to find the reason the bug suddenly pops up. I can try to provide more information if anyone has an idea as to why this is happening. Thanks!
|
|
|
|
|
Hi Andrew,
You can probably get around the exception if you change:
pDoc->SetPathName(path);
to
pDoc->SetPathName(path,FALSE);
I believe the CDocument::SetPathName[^] function causes the CRecentFileList to call ShellCreateItemFromParsingName which ends up checking for the existence of the file. If you are actually using the MRU list then you will need to ensure that the file exists before calling SetPathName.
-House of Blues
|
|
|
|
|
Our team has the task of maintaining and developing new features for a very old application. There is no budget (and no hope we can ever convince management) to rewrite it from scratch, so the only feasible way to keep this beast running is to gradually rewrite only parts of it, just as I have done before, occasionally.
It isn't quite that easy though, because, as I learned the hard way, even when I thought I completely understood a part of the program, errors kept creeping up. Often much, much later than when I initially wrote the replacement, making it much harder for me to understand my original thought process, and why it didn't work.
So I need tests, and the only valid method of testing under these circumstances that I can think of are Unit Tests. The problem is - I never worked with Unit Tests, I only know of them through articles that mention them, and therefore I only have a vague understanding of what they are and how they are supposed to be done.
Now I need some guidance where to start: I did search for articles and information on the web, but unfortunately didn't find anything useful that doesn't already require a thorough understanding of Unit Tests to start with. Somehow there don't seem to be any introductory articles - or I'm too stupid to find them. If anyone knows a link, could you please share?
As for books, I know there are literally thousands out there - but that is also my problem: which of them would be the right one? Could you advise some good picks to help out an old, experienced programmer, who for some reason never picked up the art of unit-testing?
|
|
|
|
|
The idea of unit tests is to test the functionality of units, as opposed to whole systems. (I assume you've read the relevant Wikipedia page.)
It's not as widely talked about in relation to C++ as some other languages (notably Java, but also C# and 'new' dynamic languages like Python, Ruby and that ilk) because
a) there isn't an established practically-standard unit testing framework, and
b) the language does not support reflection.
You can roll your own little framework, or grab one of the many free ones available. See Exploring the C++ Unit Testing Framework Jungle for a decent run-down. At my current workplace we use Boost.Test, but I've used CppUnit in the past. They both work, but are clunky when compared with, say, NUnit for C#.
Now, the idea is to test a unit, so you have a separate test application that links in the unit(s) you want to test, and work to their public interfaces. It's usual to have a setup-test-teardown structure, as you might need to create mock objects to pass in, or otherwise set up an environment to run the test.
So next time you need to make a change to this old legacy application, you start with identifying what units/modules/classes you need to change, and then sit down and make a series of tests that test them. For it to be any use, you need to have a comprehensive test suite - if you test only the behaviour on one sanitised input your test has poor coverage.
You want to be sure that you exercise the whole module, and all execution paths. This means testing for failures, to make sure that bad inputs or invalid environment setups generate appropriate failures (exceptions or error return codes). Test the edge cases, test "obviously" bad calls (for instance all functions that take int parameters that are assumed to be always positive - what happens when you pass in -1?) and test unlikely (but possible) combinations of inputs.
So you make your tests, and you check that they pass. If they don't pass, you need to figure out if the test is poorly written, or if there is a bug in the unit.
If you were fixing a bug in the unit, write a test that exercises that bug. In other words, write a test that will fail with the existing code. That way, you can verify that you've fixed the bug, since the test should pass after you're done.
Oh, and something that's often left out of the list advice - presumably because the adivsors see it as self-evident - is that you shouldn't remove tests. This means that for every bug you find and fix, the list of tests should grow, as you write a test to prove there's a bug, and then proves you've fixed the bug. Only remove a test if an interface has changed so the call doesn't compile any more. If that happens, write a new test to replace it.
Hope this helps a bit
|
|
|
|
|
Thanks a ton for your time. I was aware of most of what you said, but as I picked up each individual piece of information from all kinds of different sources it's a great help for me to see it all in one cohesive writeup!
I like the title of the article you linked to and will definitely try to get a look at it, but first I'll have to convince the admin to unblock the site
I've heard about the 'clunkiness' of CppUnit and other tools, and that is one of the reasons I posted here: I didn't want to invest a lot of time to learn working with a tool as long as I don't even know what to expect and what everything is about - that kind of would be like learning to use a hammer without knowing what a nail is
I've already set up a little project to get a feel for it: it has two cpp files for each header file, one as a mockup and one for the real thing. That part was easy, but I already wonder if I could somehow automate it. Also I'm asking myself how to set up a framework that calls tests for more than one unit: If I replace one cpp file in the mock project, then I can only test that one unit; I need to create a new project for each test! Is that right?
|
|
|
|
|
Mocking isn't always necessary - it depends on the units you are testing. If they conform to the classic design ideals - low coupling, small interface, high cohesion - the lion's share of their function should be testable with no mock objects. But seeing such designs in real life, especially in old production apps, is quite rare.
A mockup is only needed if the unit you want to test is dependent on something that is expensive or impossible to provide in a simple test.
For instance, a self-contained unit that calculates income tax probably wouldn't need any mock objects.
namespace taxCalc
{
double calcIncomeTax(double annualIncome);
double calcIncomeTax(double annualIncome, double pensionDeduction);
...
}
void test_taxCalc()
{
std::cout << "Testing taxCalc::calcIncomeTax" << std::endl;
int passed = 0;
int tests = 4;
if (15.3 == calcIncomeTax(60.0))
++passed;
if (0 == calcIncomeTax(5.0))
++passed;
if (0 == calcIncomeTax(0.0))
++passed;
if (14.6 == calcIncomeTax(60.0, 4.0))
++passed;
std::cout << passed << " out of " << tests << " passed" << std::endl;
if (passed != tests)
std::cout << "There were errors" << std::endl;
}
int main()
{
test_taxCalc();
return 0;
}
There you go, a very simple unit test. As you see, there can be multiple tests in one function.
If you had a second unit in the system, to calculate national insurance or something, you can test that in the same test file, though it makes sense to write a separate test function for it.
Now, it could be that for hysterical reasons a simple function is dependent on something hugely expensive, like access to a corporate database with lots of security and whatnot. That's when you make a mock. Not of what you're testing, but of what the tested unit is dependent on.
class DataBaseTableFromFortKnox
{
public:
DataBaseTableFromFortKnox();
...
double GetCentsPerDollar() const;
...
};
namespace taxCalc
{
double calcIncomeTax(double annualIncome);
double calcIncomeTax(double annualIncome, double pensionDeduction);
double calcIncomeTaxInCents(double annualIncome, const DataBaseTableFromFortKnox& dbTab);
...
}
class DataBaseTableFromFortKnox
{
public:
DataBaseTableFromFortKnox()
{}
...
double GetCentsPerDollar() const
{
return 100.0;
}
};
void test_taxCalc()
{
...
}
void test_taxCalcDB()
{
DataBaseTableFromFortKnox db;
std::cout << "Testing taxCalc::calcIncomeTax with mock DB connection" << std::endl;
int passed = 0;
int tests = 4;
if (1530.0 == calcIncomeTax(60.0, db))
++passed;
...
In this case, you must make sure that you link to the mock rather than the real thing.
In one of the projects I'm managing where I work, there's a DLL that's dependent on some libs from other departments. For that project, I have two unit test projects - one where I've replaced the other libs with stub libs, and one where it's built with the proper libs. The first tests the internal logic of the DLL, making sure that the correct libs are called for the various inputs. Only when that test project runs successfully do I need to run the other, which is calling into the other libs (which takes a few minutes to initialise and close down).
|
|
|
|
|
Cool Cow Orjan wrote: low coupling, small interface, high cohesion
You guessed it: yes, 95% of our application is everything but that. Much of it is 'objectified C', stuff like structs renamed to class, but with everything staying on the public interface because it's being referenced in thousands of places. And that, exactly is the problem: everyone references everything, or in other words, calling our 'interfaces' huge might be an understatement.
I know I will eventually have to face that, but before I do I wish to start small to get a hang of Unit Tests. What I'll start with is the libraries I wrote myself, beginning with one I've just started implementing. At least here I know exactly where it's referenced (nowhere so far), and what it is supposed to achieve.
I've just seen your followup post. Thanks for the tip, yes I will be in need of good documentation, so I might just as well look into boost.
|
|
|
|
|
Also: one purpose of unit test frameworks is to aid with reporting and result checking, keeping track of how may tests you have, trapping expected exceptions and so on.
I'd recommend Boost, if only because it's got the best documentation of the frameworks I've looked at. It's using lots of macros, which isn't to everybody's taste, but it's quite straightforward to use.
|
|
|
|
|