Unexpected RegNotifyChangeKeyValue() Behaviour - windows

RegNotifyChangeKeyValue()
function can provide alerts to changes in the security of a registry key.
I, possibly mistakenly, expected it to alert the caller if the permissions
of the user calling RegNotifyChangeKeyValue() were changed to deny the
user read permission.
From testing it does not inform the caller of this change, nor does it
inform the user of any subsequent changes to the key nor does it fail
in anyway: the caller is completely unaware that it is no longer being
informed of any change.
Code (stackc.c):
#include <windows.h>
#include <stdio.h>
int main()
{
HKEY h_key;
HANDLE h_event;
DWORD last_error = RegCreateKeyEx(HKEY_LOCAL_MACHINE,
"Software\\stackoverflow-testing-key",
0,
0,
REG_OPTION_NON_VOLATILE,
KEY_READ,
0,
&h_key,
0);
if (ERROR_SUCCESS != last_error)
{
fprintf(stderr, "Failed to create key: %d\n", last_error);
exit(1);
}
RegCloseKey(h_key);
last_error = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
"Software\\stackoverflow-testing-key",
0,
KEY_NOTIFY,
&h_key);
if (ERROR_SUCCESS != last_error)
{
fprintf(stderr, "Failed to open key: %d\n", last_error);
exit(1);
}
h_event = CreateEvent(0, FALSE, FALSE, 0);
if (h_event)
{
int change_count = 0;
while (change_count < 2)
{
DWORD wait_status;
last_error = RegNotifyChangeKeyValue(
h_key,
FALSE,
REG_NOTIFY_CHANGE_NAME |
REG_NOTIFY_CHANGE_ATTRIBUTES |
REG_NOTIFY_CHANGE_LAST_SET |
REG_NOTIFY_CHANGE_SECURITY,
h_event,
TRUE);
if (ERROR_SUCCESS != last_error)
{
fprintf(stderr, "Failed to notify: %d\n", last_error);
break;
}
wait_status = WaitForSingleObject(h_event, INFINITE);
if (WAIT_FAILED == wait_status)
{
fprintf(stderr, "Wait failed: %d\n", GetLastError());
break;
}
if (WAIT_OBJECT_0 == wait_status)
{
printf("Registry key changed!\n");
change_count++;
}
}
CloseHandle(h_event);
}
RegCloseKey(h_key);
RegDeleteKey(HKEY_LOCAL_MACHINE, "Software\\stackoverflow-testing-key");
return 0;
}
Build commands:
cl.exe -nologo -c -DWIN32 -Zi -MT -W4 -Ox stackc.c -Fo./stackc.obj
link.exe -NOLOGO -INCREMENTAL:NO -OUT:stackc.exe stackc.obj Kernel32.lib advapi32.lib
I am running Windows XP Service Pack3 x86.
To test I executed stackc.exe and ran the Registry editor
(Start->Run "regedit.exe"), browsed to
HKEY_LOCAL_MACHINE\Software\stackoverflow-testing-key
and right-clicked and selected Permissions, selected the user
which I was executing stackc.exe as and denied read permission.
I then added a value to the key and stackc.exe is never notified.
Can someone provide an explanation for this behaviour or, preferably,
point to an error in the posted code?

Related

use SetWinEventHook for logged-in user from a SYSTEM onwed process

I'm working on an application that runs with SYSTEM level privileges and is created by the SYSTEM user. I need to track foreground activities for the currently logged-in user.
I'm using SetWinEventHook for the same. It works fine when I run the application from my current user. But if I started the application with the SYSTEM user, it was unable to receive events.
Is there any workaround to trigger this with user context?
Edit:
g_hook = SetWinEventHook(EVENT_SYSTEM_FOREGROUND, EVENT_SYSTEM_FOREGROUND, NULL, focusChangeCallbackHandle, 0, 0, WINEVENT_OUTOFCONTEXT);
focusChangeCallbackHandle is a in same namespace as the caller function
Edit 2:
Adding my boilerplate code here:
I'm using pstools to run the binary with the SYSTEM user. Also not sure why but after running any of the getter/setters of ThreadDesktop and WindowStation my application stop printing on the console.
void ForegroundCheck() {
printf("In thread \n");
HWINSTA orgWS = GetProcessWindowStation();
printf("Done GetProcessWindowStation \n");
if (orgWS) {
printf("In GetProcessWindowStation \n");
HWINSTA itrWS = OpenWindowStation(TEXT("WinSta0"), true, GENERIC_ALL);
if (itrWS) {
printf("In OpenWindowStation \n");
if (SetProcessWindowStation(itrWS)) {
printf("In SetProcessWindowStation \n");
HDESK iD = OpenInputDesktop(DF_ALLOWOTHERACCOUNTHOOK, true, GENERIC_ALL);
if (iD) {
if (!SetThreadDesktop(iD)) {
printf("SetThreadDesktop failed: %lu \n", GetLastError());
} else {
printf("setting hoook");
// SetWinEventHook sets the hook for the mentioned event.
// In current case EVENT_SYSTEM_FOREGROUND. When ever EVENT_SYSTEM_FOREGROUND is triggerd HandleWinEvent will be called
g_hook = SetWinEventHook(
EVENT_SYSTEM_FOREGROUND, EVENT_SYSTEM_FOREGROUND, // Range of events (4 to 5).
NULL, // Handle to DLL.
HandleWinEvent, // The callback.
0, 0, // Process and thread IDs of interest (0 = all)
WINEVENT_OUTOFCONTEXT);
MSG msg;
//GetMessage(&msg, NULL, 0, 0);
while (WaitMessage() && set) {
PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
}
}
} else {
printf("OpenInputDesktop failed: %lu \n", GetLastError());
}
SetProcessWindowStation(orgWS);
} else {
printf("SetProcessWindowStation failed: %lu \n", GetLastError());
}
CloseWindowStation(itrWS);
} else {
printf("OpenWindowStation failed: %lu \n", GetLastError());
}
} else {
printf("GetProcessWindowStation failed: %lu \n", GetLastError());
}
}
int main() {
bool retVal = false;
printf("In Main \n");
CoInitialize(NULL);
std::thread t(ForegroundCheck);
printf("In thread started \n");
std::cin.get();
// Deinit
UnhookWinEvent(g_hook);
set = false;
t.join();
CoUninitialize();
return 0;
}
Thanks
Each logged on user has separate desktop. So if you want to track foreground activities, your process need to run as Users group. You can create another process as user with CreateProcessAsUser.

Find out which process is locking a file or folder in Windows [duplicate]

I am using the following code to check if a file is being used by another application:
HANDLE fh = CreateFile("D:\\1.txt", GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
if (fh == INVALID_HANDLE_VALUE)
{
MessageBox(NULL, "The file is in use", "Error", 0);
}
If the file is being used by another application, the message box is displayed. However, the message box is also displayed if the file does not exists!
So what should I do to solve this problem, should I also check if the file exists (using another function), or can the parameters of CreateFile() be changed to only return INVALID_HANDLE_VALUE if the file is in use and does exists?
If you wish to find out, which process has a file open, use the Restart Manager. The procedure consists of the following steps (as outlined in Raymond Chen's blog entry How do I find out which process has a file open?):
Create a Restart Manager session (RmStartSession).
Add a file resource to the session (RmRegisterResource).
Ask for a list of all processes affected by that resource (RmGetList).
Close the session (RmEndSession).
Sample code:
#include <Windows.h>
#include <RestartManager.h>
#pragma comment(lib, "Rstrtmgr.lib")
bool IsFileLocked( const wchar_t* PathName ) {
bool isFileLocked = false;
DWORD dwSession = 0x0;
wchar_t szSessionKey[CCH_RM_SESSION_KEY + 1] = { 0 };
if ( RmStartSession( &dwSession, 0x0, szSessionKey ) == ERROR_SUCCESS ) {
if ( RmRegisterResources( dwSession, 1, &PathName,
0, NULL, 0, NULL ) == ERROR_SUCCESS ) {
DWORD dwReason = 0x0;
UINT nProcInfoNeeded = 0;
UINT nProcInfo = 0;
if ( RmGetList( dwSession, &nProcInfoNeeded,
&nProcInfo, NULL, &dwReason ) == ERROR_MORE_DATA ) {
isFileLocked = ( nProcInfoNeeded != 0 );
}
}
RmEndSession( dwSession );
}
return isFileLocked;
}
You need to use GetLastError() to know why CreateFile() failed, eg:
// this is requesting exclusive access to the file, so it will
// fail if the file is already open for any reason. That condition
// is detected by a sharing violation error due to conflicting
// sharing rights...
HANDLE fh = CreateFile("D:\\1.txt", GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
if (fh == INVALID_HANDLE_VALUE)
{
switch (GetLastError())
{
case ERROR_PATH_NOT_FOUND:
case ERROR_FILE_NOT_FOUND:
MessageBox(NULL, "The file does not exist", "Error", 0);
break;
case ERROR_SHARING_VIOLATION:
MessageBox(NULL, "The file is in use", "Error", 0);
break;
//...
default:
MessageBox(NULL, "Error opening the file", "Error", 0);
break;
}
}
else
{
// the file exists and was not in use.
// don't forget to close the handle...
CloseHandle(fh);
}

CreateProcessAsUser issue on Windows

I'm trying to get user token via LogonUser() WinAPI call and execute process via that user on windows by CreateProcessAsUser () call. The problem is that I get 1314 'A required privilege is not held by the client' error. I'm currently logged in via 'Pearl' and as you see I'm using my own credentials there. This used is in Administrators group, I also checked the Local Security Policy and this user has all necessary permissions (Act as part of operating system, Create token object and Log on as batch job. My code is:
#include <windows.h>
#include <stdio.h>
#include <userenv.h>
int enable_priv(HANDLE hToken, const char* name)
{
TOKEN_PRIVILEGES tp;
memset(&tp, 0, sizeof(tp));
if (LookupPrivilegeValue(NULL, name, &tp.Privileges[0].Luid) == 0)
{
fprintf(stderr, "Error: %ld\n", GetLastError());
return 0;
}
tp.PrivilegeCount = 1;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
if (AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), NULL, 0) == 0)
{
fprintf(stderr, "Error: %ld.\n", GetLastError());
return 0;
}
return 1;
}
int main(int argc, char **argv)
{
HANDLE hToken1 = NULL;
HANDLE dup = NULL;
STARTUPINFO si = {0};
PROCESS_INFORMATION pi = {0};
si.cb = sizeof(STARTUPINFO);
DWORD flags = CREATE_NO_WINDOW;
fprintf(stderr, "testlog starting...\n");
if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, &hToken1) == 0)
{
fprintf(stderr, "token failed code '%lu'.\n", GetLastError());
return -1;
}
enable_priv(hToken1, SE_TCB_NAME);
enable_priv(hToken1, SE_ASSIGNPRIMARYTOKEN_NAME);
enable_priv(hToken1, SE_INCREASE_QUOTA_NAME);
if (LogonUser("Pearl", NULL, "pass",
LOGON32_LOGON_INTERACTIVE,
LOGON32_PROVIDER_DEFAULT, &hToken1) == 0)
{
fprintf(stderr, " Interactive logon failed.\n");
return 0;
}
if (DuplicateTokenEx(hToken1, MAXIMUM_ALLOWED, NULL, SecurityDelegation,
TokenPrimary, &dup) == 0)
{
fprintf(stderr, "ERROR is '%lu'.\n", GetLastError());
return 0;
}
fprintf(stderr, "testlog executing...\n");
fflush(stderr);
fflush(stdout);
if (CreateProcessAsUser(dup, NULL, "C:\\Program Files (x86)\\folder1\\tazo.exe", NULL, NULL, TRUE,
flags, NULL, NULL, &si, &pi) == 0)
{
fprintf(stderr, "testlog Error is '%lu'\n", GetLastError());
}
}
Can anyone please help?

Is there any way to pair Bluetooth device in Windows programmatically

there's a question:
Is there any way to pair Bluetooth device in Windows programmatically? (c++, c#)
thanks for replies
Yes, the reference documentation is available on MSDN.
32feet.NET is a C# wrapper, available here. Information on pairing is here.
Python is a tempting and overall easy solution, but PyBlueZ does not expose the windows Bluetooth authentication APIs here: https://msdn.microsoft.com/en-us/library/windows/desktop/cc766819(v=vs.85).aspx
One way to get around this is to create a command line tool and use this through Python. To create command line tools for Windows, use Visual Studio and add the necessary libraries to your project linker properties: Bthprops.lib and ws2_32.lib
Below is the code for a project to make a command line tool with 1 parameter, the MAC address, that pairs the specified device using "Just Works" pairing. See commented code for using passkey pairing.
#include "stdafx.h"
#include <initguid.h>
#include <winsock2.h>
#include <BluetoothAPIs.h>
#include <ws2bth.h>
BOOL WINAPI BluetoothAuthCallback(LPVOID pvParam, PBLUETOOTH_AUTHENTICATION_CALLBACK_PARAMS pAuthCallbackParams);
int _tmain(int argc, _TCHAR* argv[])
{
SOCKADDR_BTH sa = { 0 };
int sa_len = sizeof(sa);
DWORD dwRet;
BLUETOOTH_DEVICE_INFO btdi = { 0 };
HBLUETOOTH_AUTHENTICATION_REGISTRATION hRegHandle = 0;
// initialize windows sockets
WORD wVersionRequested;
WSADATA wsaData;
wVersionRequested = MAKEWORD(2, 0);
if (WSAStartup(wVersionRequested, &wsaData) != 0) {
ExitProcess(2);
}
// parse the specified Bluetooth address
if (argc < 2) {
fprintf(stderr, "usage: csbtpair <addr>\n"
"\n addr must be in the form (XX:XX:XX:XX:XX:XX)");
ExitProcess(2);
}
if (SOCKET_ERROR == WSAStringToAddress(argv[1], AF_BTH,
NULL, (LPSOCKADDR)&sa, &sa_len)) {
ExitProcess(2);
}
// setup device info
btdi.dwSize = sizeof(BLUETOOTH_DEVICE_INFO);
btdi.Address.ullLong = sa.btAddr;
btdi.ulClassofDevice = 0;
btdi.fConnected = false;
btdi.fRemembered = false;
btdi.fAuthenticated = false;
// register authentication callback. this prevents UI from showing up.
dwRet = BluetoothRegisterForAuthenticationEx(&btdi, &hRegHandle, &BluetoothAuthCallback, NULL);
if (dwRet != ERROR_SUCCESS)
{
fprintf(stderr, "BluetoothRegisterForAuthenticationEx ret %d\n", dwRet);
ExitProcess(2);
}
// authenticate device (will call authentication callback)
AUTHENTICATION_REQUIREMENTS authreqs = MITMProtectionNotRequired;
fprintf(stderr, "BluetoothAuthReqs = %d\n", authreqs);
dwRet = BluetoothAuthenticateDeviceEx(NULL, NULL, &btdi, NULL, authreqs);
if (dwRet != ERROR_SUCCESS)
{
fprintf(stderr, "BluetoothAuthenticateDevice ret %d\n", dwRet);
if (dwRet == ERROR_CANCELLED)
{
fprintf(stderr, "Cancelled");
}
else if (dwRet == ERROR_INVALID_PARAMETER)
{
fprintf(stderr, "Invalid Parameter");
}
else if (dwRet == ERROR_NO_MORE_ITEMS)
{
fprintf(stderr, "Already paired!");
}
}
fprintf(stderr, "pairing finish\n");
ExitProcess(0);
return 0;
}
// Authentication callback
BOOL WINAPI BluetoothAuthCallback(LPVOID pvParam, PBLUETOOTH_AUTHENTICATION_CALLBACK_PARAMS pAuthCallbackParams)
{
DWORD dwRet;
fprintf(stderr, "BluetoothAuthCallback 0x%x\n", pAuthCallbackParams->deviceInfo.Address.ullLong);
BLUETOOTH_AUTHENTICATE_RESPONSE AuthRes;
AuthRes.authMethod = pAuthCallbackParams->authenticationMethod;
fprintf(stderr, "Authmethod %d\n", AuthRes.authMethod);
// Check to make sure we are using numeric comparison (Just Works)
if (AuthRes.authMethod == BLUETOOTH_AUTHENTICATION_METHOD_NUMERIC_COMPARISON)
{
fprintf(stderr, "Numeric Comparison supported\n");
}
AuthRes.bthAddressRemote = pAuthCallbackParams->deviceInfo.Address;
AuthRes.negativeResponse = FALSE;
// Commented out code is used for pairing using the BLUETOOTH_AUTHENTICATION_METHOD_PASSKEY method
//memcpy_s(AuthRes.pinInfo.pin, sizeof(AuthRes.pinInfo.pin), L"1234", 0);
//AuthRes.pinInfo.pinLength = 0;
// Respond with numerical value for Just Works pairing
AuthRes.numericCompInfo.NumericValue = 1;
// Send authentication response to authenticate device
dwRet = BluetoothSendAuthenticationResponseEx(NULL, &AuthRes);
if (dwRet != ERROR_SUCCESS)
{
fprintf(stderr, "BluetoothSendAuthenticationResponseEx ret %d\n", dwRet);
if (dwRet == ERROR_CANCELLED)
{
fprintf(stderr, "Bluetooth device denied passkey response or communicatino problem.\n");
}
else if (dwRet == E_FAIL)
{
fprintf(stderr, "Device returned a failure code during authentication.\n");
}
else if (dwRet == 1244)
{
fprintf(stderr, "Not authenticated\n");
}
}
else
{
fprintf(stderr, "BluetoothAuthCallback finish\n");
}
return 1; // This value is ignored
}
In lieu of creating this yourself, you may want to try this pre-made solution:
http://bluetoothinstaller.com/bluetooth-command-line-tools/
It did not work for my particular solution.
Then, you will need to run your downloaded or custom command line tool from python as an administrator. To do this reliably, I recommend the stackoverflow question:
How to run python script with elevated privilege on windows
I meet the same problem,and I have resolved the problem, Maybe you can try it:
make a windows tool named pairtool.exe, it help you to pairing with command line. the key api is BluetoothAuthenticateDevice, please refering the functions document
dwRet = BluetoothAuthenticateDevice(NULL, NULL, &btdi, L"1234", 4);
if(dwRet != ERROR_SUCCESS)
{
fprintf(stderr, "BluetoothAuthenticateDevice ret %d\n", dwRet);
ExitProcess(2);
}
python code:
def connect2Btdev(devName):
#found the device addr
addr = inquiry(devName)
if addr == None:
return None
#pairing with pairtool.exe
cmd=r'%s %s' % ('pairtool.exe',addr)
ret = os.system(cmd)
if ret <> 0:
return None
here is all the code of pairtool.exe:
#include "stdafx.h"
#include <initguid.h>
#include <winsock2.h>
#include <BluetoothAPIs.h>
#include <ws2bth.h>
bool BluetoothAuthCallback(LPVOID pvParam, PBLUETOOTH_AUTHENTICATION_CALLBACK_PARAMS pAuthCallbackParams)
{
DWORD dwRet;
fprintf(stderr, "BluetoothAuthCallback 0x%x\n", pAuthCallbackParams->deviceInfo.Address.ullLong);
dwRet = BluetoothSendAuthenticationResponse(NULL, &(pAuthCallbackParams->deviceInfo), L"1234");
if(dwRet != ERROR_SUCCESS)
{
fprintf(stderr, "BluetoothSendAuthenticationResponse ret %d\n", dwRet);
ExitProcess(2);
return 1;
}
fprintf(stderr, "BluetoothAuthCallback finish\n");
ExitProcess(0);
return 1;
}
int _tmain(int argc, _TCHAR* argv[])
{
SOCKADDR_BTH sa = { 0 };
int sa_len = sizeof(sa);
DWORD dwRet;
BLUETOOTH_DEVICE_INFO btdi = {0};
HBLUETOOTH_AUTHENTICATION_REGISTRATION hRegHandle = 0;
// initialize windows sockets
WORD wVersionRequested;
WSADATA wsaData;
wVersionRequested = MAKEWORD( 2, 0 );
if( WSAStartup( wVersionRequested, &wsaData ) != 0 ) {
ExitProcess(2);
}
// parse the specified Bluetooth address
if( argc < 2 ) {
fprintf(stderr, "usage: rfcomm-client <addr>\n"
"\n addr must be in the form (XX:XX:XX:XX:XX:XX)");
ExitProcess(2);
}
if( SOCKET_ERROR == WSAStringToAddress( argv[1], AF_BTH,
NULL, (LPSOCKADDR) &sa, &sa_len ) ) {
ExitProcess(2);
}
//注册回调函数
btdi.dwSize = sizeof(BLUETOOTH_DEVICE_INFO);
btdi.Address.ullLong = sa.btAddr;
btdi.ulClassofDevice = 0;
btdi.fConnected = false;
btdi.fRemembered = false;
btdi.fAuthenticated = false;
dwRet = BluetoothRegisterForAuthenticationEx(&btdi, &hRegHandle, &BluetoothAuthCallback, NULL);
if(dwRet != ERROR_SUCCESS)
{
fprintf(stderr, "BluetoothRegisterForAuthenticationEx ret %d\n", dwRet);
ExitProcess(2);
}
dwRet = BluetoothAuthenticateDevice(NULL, NULL, &btdi, L"1234", 4);
if(dwRet != ERROR_SUCCESS)
{
fprintf(stderr, "BluetoothAuthenticateDevice ret %d\n", dwRet);
ExitProcess(2);
}
Sleep(1000);
fprintf(stderr, "pairing finish\n");
ExitProcess(0);
return 0;
}
Microsoft has introduced Windows.Devices.Enumeration API available for UWP and traditional applications, which makes pairing of bluetooth devices very easy (for details look at the official C# and C++ example). As far as I understand it is the API which is used by built-in "Bluetooth & other devices" UI dialog. As of an example of what console utility you can write using this API you can take a look at my console BluetoothDevicePairing utility.
You can do so by using the functions documented under MSDN Bluetooth Functions.
These enable searching and pairing of bluetooth devices programmatically.

How can I get around UAC when using ReadDirectoryChanges?

I have an application that needs to monitor the primary drive for file changes via ReadDirectoryChangesW. However, when UAC is enabled, it doesn't work.
All of the Windows API calls succeed, but I'm not notified of any changes.
I can work around this by individually monitoring each directory in the root, but this is a problem, because it can potentially cause a blue screen if there are too many directories.
Is there an acceptable way to get around UAC and receive file change notifications on the entire primary drive?
The relevant CreateFile and ReadDirectoryChangesW is below. In the case where it doesn't work, directory is C:\. If I monitor any secondary drive (i.e. E:\, F:\, G:\) it works as expected. None of the calls return errors.
HANDLE fileHandle = CreateFileW(directory.c_str(), FILE_LIST_DIRECTORY,
FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, NULL);
BOOL success = ReadDirectoryChangesW(fileHandle, watched.buffer.data(),
watched.buffer.size(), TRUE,
FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_LAST_WRITE,
NULL, &watched.overlapped, NULL);
Interestingly, the .NET System.IO.FileSystemWatcher does work correctly, and it uses the exact same functions and parameters as I'm using, but it behaves correctly.
First it is best for applications that use the ReadDirectoryChangesW API to run elevated make a manifest file for you app and set requireAdministrator as the requestedExecutionLevel level. Check here for reference.
Try removing FILE_SHARE_WRITE from the CreateFile call if you are using it.
Another option is to make your program run as a service, im not sure how applicable this is to your needs. You could post some code as to how you are getting the file handle and what are you passing to ReadDirectoryChangesW
Here's some working test code, for future reference.
#include <Windows.h>
#include <stdio.h>
int main(int argc, char ** argv)
{
HANDLE filehandle;
BYTE buffer[65536];
DWORD dw;
FILE_NOTIFY_INFORMATION * fni;
OVERLAPPED overlapped = {0};
overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (overlapped.hEvent == NULL)
{
printf("CreateEvent: %u\n", GetLastError());
return 1;
}
filehandle = CreateFile(L"C:\\",
FILE_LIST_DIRECTORY,
FILE_SHARE_READ | FILE_SHARE_DELETE,
NULL,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED,
NULL);
if (filehandle == INVALID_HANDLE_VALUE)
{
printf("CreateFile: %u\n", GetLastError());
return 1;
}
for (;;)
{
if (!ReadDirectoryChangesW(filehandle, buffer, sizeof(buffer),
TRUE,
FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_LAST_WRITE,
NULL, &overlapped, NULL))
{
printf("ReadDirectoryChangesW: %u\n", GetLastError());
return 1;
}
printf("Queued OK.\n");
if (!GetOverlappedResult(filehandle, &overlapped, &dw, TRUE))
{
printf("GetOverlappedResult: %u\n", GetLastError());
return 1;
}
printf("%u bytes read.\n", dw);
fni = (FILE_NOTIFY_INFORMATION *)buffer;
for (;;)
{
printf("Next entry offset = %u\n", fni->NextEntryOffset);
printf("Action = %u\n", fni->Action);
printf("File name = %.*ws\n",
fni->FileNameLength / 2,
fni->FileName);
if (fni->NextEntryOffset == 0) break;
fni = (FILE_NOTIFY_INFORMATION *)
(((BYTE *)fni) + fni->NextEntryOffset);
}
}
printf("All done\n");
return 0;
}
You can adjust the privileges of your process yourself like this:
// enable the required privileges for this process
LPCTSTR arPrivelegeNames[] = { SE_BACKUP_NAME,
SE_RESTORE_NAME,
SE_CHANGE_NOTIFY_NAME
};
for (int i=0; i<(sizeof(arPrivelegeNames)/sizeof(LPCTSTR)); ++i)
{
CAutoGeneralHandle hToken;
if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, hToken.GetPointer()))
{
TOKEN_PRIVILEGES tp = { 1 };
if (LookupPrivilegeValue(NULL, arPrivelegeNames[i], &tp.Privileges[0].Luid))
{
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), NULL, NULL);
}
}
}
This works also for non-privileged processes (a.k.a. normal user processes).

Resources