PDA

View Full Version : SHChangeNotifyRegister



Coises
25th December 2009, 04:45
I realize this is more a MinGW/GCC question than a Qt question, but at this point MinGW/GCC is pretty much a black box to me, and I couldn’t find anything helpful by searching for SHChangeNotifyRegister and MinGW.

How do I access a Windows function the definition of which is missing from the MinGW header files?

SHChangeNotifyRegister (http://msdn.microsoft.com/en-us/library/bb762120(VS.85).aspx) belongs in shlobj.h — it’s there in the Windows Platform SDK (been there since Windows 2000), but it’s nowhere in the MinGW version. It’s nowhere in any file under my Qt 4.6 installation. I can copy the definition from the Platform SDK to get my code to compile, but (unsurprisingly) the link step fails.

Of course, it has to be there in the actual Windows run-time libraries — how do I tell the linker how to find it?

squidge
25th December 2009, 12:35
Normally you would add the import library to your .pro file, but I'm not sure what library you would use for this function, or whether MinGW actually has such a library. It's one of the reasons I use MSVC++ for my projects rather than QtCreator.

If your only interested in SHChangeNotifyRegister however, how about an alternative? The Qt class QFileSystemWatcher might do what you want. It uses FindFirstChangeNotification and friends in a seperate thread under Windows, and of course is more portable to other platforms.

Coises
25th December 2009, 18:48
Normally you would add the import library to your .pro file, but I'm not sure what library you would use for this function

It should be in the shell32.lib equivalent, but other functions from that library, such as SHGetSpecialFolderLocation, are linking properly. I notice SHChangeNotifyRegister requires shell32.dll version 5.0, but I think all the others I’m using require at most version 4.72; is it possible that MinGW has never been updated to Windows 2000 / Windows ME (which included shell32.dll version 5 (http://msdn.microsoft.com/en-us/library/bb776779(VS.85).aspx#numbers))?


If your only interested in SHChangeNotifyRegister however, how about an alternative? The Qt class QFileSystemWatcher might do what you want. It uses FindFirstChangeNotification and friends in a seperate thread under Windows, and of course is more portable to other platforms.

Thank you for the heads-up on FindFirstChangeNotification.

As a sub-part of a larger project (in which I do want to maintain portability, though I don’t expect to be the one to port it), I’m trying to write a replacement for QFileSystemModel that yields a tree view of the Windows shell namespace (with the desktop at the root and including virtual folders with file system descendants, like My Computer and Network Neighborhood), just as a Windows user is used to seeing it in the left-hand pane of Windows Explorer. QFileSystemModel is, in my opinion, virtually useless on Windows, because Windows users don’t look at the file system that way. Portability is an issue only in that I’ll want QFileSystemModel to work in the same context on other platforms. (I have no idea whether it’s flawed in similar ways on Macintosh or Linux, since I know nothing about them.)

Unless I’m missing something, QFileSystemWatcher can only watch the immediate contents of a directory, not the entire sub-tree beneath it. Since I’ll need to watch the entire shell namespace (or, at least, as much of it as has been populated, which could be many, many folders over the lifetime of the model), that strikes me as the wrong way to go if there’s a more direct alternative.

I had been simultaneously trying to figure out the code in QFileSystemWatcher and searching the Windows Platform SDK for how to do change notification. I stared right at FindFirstChangeNotification in qfilesystemwatcher_win.cpp and didn’t recognize it as a Windows system call. Eventually I found SHChangeNotifyRegister in the Windows Platform SDK.

Were it supported, SHChangeNotifyRegister would be best, because it can watch the entire shell namespace by registering to watch the desktop and all its descendants. If I can’t get that under MinGW, though, I can probably apply FindFirstChangeNotification with the “watch subtree” flag to each drive, keeping track of special folders like Desktop and My Documents that reflect directories located elsewhere in the tree. This would still miss some things, though, such as plugging in a thumb drive, adding or removing a folder from the new Windows 7 libraries, or just about anything happening in Network Neighborhood.

Edit: It turns out FindFirstChangeNotification (http://msdn.microsoft.com/en-us/library/aa364417.aspx) isn’t very helpful with directory recursion, as it merely enables a wait, but doesn’t return any information about what changed; it would be necessary to rescan the entire logical drive, or else set a separate notification without the “watch subtree” flag on each directory that had been populated. Next stop, ReadDirectoryChangesW (http://msdn.microsoft.com/en-us/library/aa365465.aspx)... or start learning more about MinGW to figure out if there’s any way to update it to work with shell32.dll version 5.0, if that is the reason SHChangeNotifyRegister (http://msdn.microsoft.com/en-us/library/bb762120.aspx) won’t work.

Coises
26th December 2009, 07:02
How do I access a Windows function the definition of which is missing from the MinGW header files?

I think I have answered my own question; for anyone who might have the same question and find this thread in a search, here is what appears to work:



typedef struct {
LPCITEMIDLIST pidl;
BOOL fRecursive;
} SHChangeNotifyEntry;

#define SHELL_ENTRY(returnType, functionName, parameters) \
static returnType __stdcall (*functionName) parameters \
= (returnType __stdcall (*) parameters) \
QLibrary::resolve("shell32", #functionName)

SHELL_ENTRY(ULONG, SHChangeNotifyRegister,
(HWND hwnd, int fSources, LONG fEvents, UINT wMsg, int cEntries, SHChangeNotifyEntry *pshcne));
SHELL_ENTRY(BOOL, SHChangeNotifyDeregister, (unsigned long ulID));
SHELL_ENTRY(HANDLE, SHChangeNotification_Lock,
(HANDLE hChangeNotification, DWORD dwProcessId, LPITEMIDLIST **pppidl, LONG *plEvent));
SHELL_ENTRY(BOOL, SHChangeNotification_Unlock, (HANDLE hLock));
SHELL_ENTRY(HRESULT, SHGetRealIDL,
(IShellFolder *psf, LPCITEMIDLIST pidlSimple, LPITEMIDLIST * ppidlReal));


The details for the SHChangeNotifyEntry (http://msdn.microsoft.com/en-us/library/bb773405.aspx) structure and the function declarations are copied from the Windows Platform SDK version of shlobj.h. The macro uses the static form of QLibrary::resolve to load shell32.dll dynamically and find the required entry point, then assigns it to a static variable.

Oddly, Qt Creator underlines the SHELL_ENTRY declaration for SHChangeNotifyRegister (http://msdn.microsoft.com/en-us/library/bb762120.aspx) in red, but the compiler accepts it without complaint, and the function is called successfully using that pointer in subsequent code.

I would have declared the pointers-to-function const instead of static; but removing the static keyword and adding const between the asterisk and functionName results in “internal compiler error: in start_decl, at cp/decl.c:4220” from g++.

Coises
26th December 2009, 16:21
Sorry to keep posting replies to myself, but apparently there is a time limit on edits in this forum.


#define SHELL_ENTRY(returnType, functionName, parameters) \
typedef returnType __stdcall (*functionName##_type) parameters; \
const functionName##_type functionName \
= (functionName##_type) QLibrary::resolve("shell32", #functionName)

avoids the Qt Creator and g++ problems described in the last two paragraphs of my previous post (http://www.qtcentre.org/forum/f-qt-programming-2/t-shchangenotifyregister-26821.html#post127508).

squidge
26th December 2009, 21:40
I don't think people will mind your useful posts about how to access features of Windows that you normally can't access under MinGW.

As for QFileSystemModel, I completely agree with you. It's fine for the basic functionality of browsing drives, but it's just not flexible enough for most serious uses and completely useless for browsing any virtual folders that a lot of people expect. I think the reason for this is the portability - the Windows directory structure under XP and above is completely different to the likes of Linux. There is a legacy system for accessing files on most devices (typically, those with drive letters), but its completely incapable of accessing others.

I'm desiging my own version of QFileSystemModel, which uses PIDLs instead of ascii paths, so hopefully I'll be able to browse the entire name space.

Coises
26th December 2009, 22:14
I'm desiging my own version of QFileSystemModel, which uses PIDLs instead of ascii paths, so hopefully I'll be able to browse the entire name space.

It sounds like we’re working on the same problem. Here’s what I have so far, in case it’s any help to you.