Archive for November, 2007

Success Depends on Others Failing

I came across this article today. It’s somewhat interesting overall, but there are 2 things which particularly struck me, first, the following paragraph…

The researchers were especially interested in the set of outcomes where both players answered correctly. For any given prize value, the brain’s reward response was bigger if the other player earned less. Players on average were more pleased with a 60 euro prize when the other player got just 30 euros, for example, than they were if both players earned 60 euros, or if the other player got more.

I can only guess what my brain scan would show, but my gut feeling is that I’d likely feel empathy for the person being rewarded less and/or reduced satisfaction (or no satisfaction) due to the fact that my reward is inflated. However, I could definitely understand the negative reaction if I were the person being rewarded less and the satisfaction for being rewarded more for doing more.

Also, this seems really sad to me. It would indicate that humans are, in general, inherently selfish as we have no problem seeing others rewarded less for doing the same work.

(I hate that the article somewhat convolutes the issue, by casually making a segway to the “keeping up with the Joneses” concept; there’s a fundamental difference in keeping up and keeping up unfairly)

Win32 annoyances and tips when working with files and processes

1. ShellExecuteEx and lpFile

SHELLEXECUTEINFOW setupxInfo;
memset(&setupxInfo, 0,
sizeof(SHELLEXECUTEINFO));
setupxInfo.cbSize =
sizeof(SHELLEXECUTEINFO);
setupxInfo.fMask = SEE_MASK_FLAG_NO_UI |
SEE_MASK_NOCLOSEPROCESS;
setupxInfo.lpVerb = L
"open";
setupxInfo.lpFile = L
"setupx.exe"; // can't be full path
setupxInfo.nShow = SW_SHOWNORMAL;
setupxInfo.lpDirectory = L
"setupdir";
setupxInfo.lpParameters = NULL;

ShellExecuteExW(&setupxInfo);

The code above is correct and it works, however if the lpFile member of the SHELLEXECUTEINFO struct is the full path to the executable file the ShellExecuteEx call fails. It seem you must specify the working directory for the child process (lpDirectory) and the filename only for the lpFile member.

2. SHFileOperation and pFrom

SHFILEOPSTRUCTW SHFileOp;
ZeroMemory(&SHFileOp,
sizeof(SHFILEOPSTRUCT));
SHFileOp.hwnd = NULL;
SHFileOp.wFunc = FO_DELETE;
SHFileOp.pFrom = killFolder;
// double-null-terminated string, can't end with path separator
SHFileOp.pTo = NULL;
SHFileOp.fFlags = FOF_SILENT |
FOF_NOCONFIRMATION |
FOF_NOERRORUI |
FOF_NOCONFIRMMKDIR;
SHFileOp.fAnyOperationsAborted = FALSE;
SHFileOp.lpszProgressTitle = NULL;
SHFileOp.hNameMappings = NULL;
SHFileOperationW(&SHFileOp);

In the above code, SHFileOp.pFrom (killFolder variable) is a double-null-terminated string to a folder I want to delete (I want to also recursively delete everything inside the folder, that’s why I’m using SHFileOperation). However, aside from the peculiar double null-termination, the path can’t end with the path separator char or the SHFileOperation call fails.

3. WaitForSingleObject

After calling ShellExecuteEx or CreateProcess you can do the following to wait for the child process to terminate:

WaitForSingleObject( setupxInfo.hProcess, INFINITE );

4. fclose

Don’t forget to close your file handles. I spent a few hours today trying to figure out why I couldn’t delete an exe, thinking it was an issue with the ShellExecuteEx function. Turns out I opened the file and forgot to close it.

btw, Process Explorer is very helpful and a great tool for programmers; it’s wonderful for detecting things like unclosed file handles.

The pains of making an installer + uninstaller

I’ve been working on an installer/uninstaller for firesync 2. The installer is fairly straightforward, although it is quite a bit of work to set registry keys and make shortcuts, but overall it’s all fairly standard stuff. The one unique aspect of the firesync installer is that it is multi-part and actually consists of 2 executables. The first executable, the setup.exe file that will be distributed, is a native code binary + a zip archive. This program checks that the .NET Framework 2.0 is installed and extracts the zip archive to a folder in the user’s temporary directory. The zip archive contains the firesync executable and data files, but also contains another setup executable setupx.exe (a .NET executable). This executable is the real setup, as it shows/prompts the user for setup information (installation directory, whether or not to make a desktop icon, etc.), copies over the necessary files, makes program shortcuts, and writes registry entries so that firesync appears in the Add/Remove Programs list.

The reason for the multi-part installation is that it is much easier to design an interface using the WinForms designer in Visual C# compared to MFC, wxWidgets, etc. However, a .NET executable alone won’t suffice because users without the framework will just be given a cryptic error message (I think you get dialog about mscoree.dll not being found) and they’re not actually told that they need to install the framework.

(fyi, the native code executable is being done with wxDevC++)

Now making an uninstaller should be simple, your just deleting files and removing a couple of registry entries (in general, I avoid the registry and for firesync I’m only using it for the entry in Add/Remove Programs). Also, I think it’s rare that a user will uninstall the .NET Framework then try to uninstall firesync, so it’s pretty safe to make the uninstaller a .NET executable. However, there’s one big issue (and it’s a major pain in the ass) that pops up when it comes to making an uninstaller, how do you delete the uninstaller executable itself? I was lucky enough to stumble across this old Q&A from Microsoft Systems Journal. It’s a very inter… well to be honest it’s a very boring read (how interesting can deleting a file be?), but it’s important stuff. Ultimately, I went with the simplest method, and just used a batch file (although I haven’t played around with setting thread priorities as mentioned in the article; I’m not crazy about doing it and I’m not sure if it’s even worth it).

Finally, some important issues I ran across that was not mentioned in the article:

  • The directory your attempting to remove may be in use by the OS or another application. Another loop in the batch file should take care of this.
  • You can’t have the batch file in the directory your trying to delete (you’ll never be able to delete it as it’ll be in use by cmd.exe, you’ll have to manually kill cmd.exe to delete the folder and free the CPU). This is simple to solve, I just put the batch file in the user’s temp directory.