How to refresh only one time in ReadDirectoryChange in WIN32 API? - winapi

I use ReadDirectoryChange in WIN32 API. After I copy 10 folder, my program is running refresh 10 times. However I only want it refresh once.
Can you help me? Here is my code:
bool FolderWatcher::Loop ()
{
// declare a variable and using it to return
int i = 0;
// convert from WCHAR to LPWSTR
LPWSTR ptr = _folder;
char buf[256 * (sizeof(FILE_NOTIFY_INFORMATION) + MAX_PATH * sizeof(WCHAR))] = {0};
DWORD bytesReturned = 0;
BOOL result = FALSE;
FILE_NOTIFY_INFORMATION *fni = NULL;
// using CreateFile to choose folder need to watch
HANDLE hDir = CreateFileW(
ptr,
FILE_LIST_DIRECTORY |
STANDARD_RIGHTS_READ,
//Enables subsequent open operations on a file or device to request read access.
FILE_SHARE_READ |
//Enables subsequent open operations on a file or device to request write access.
FILE_SHARE_WRITE |
//Enables subsequent open operations on a file or device to request delete access.
FILE_SHARE_DELETE,
NULL,
//Opens a file or device, only if it exists.
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS,
NULL);
// check if directory is not exists
if (!hDir || hDir == INVALID_HANDLE_VALUE)
{
i = 0;
}
else
{
for (;;)
{
// call ReadDirectoryChangeW to watch folder
result = ReadDirectoryChangesW(hDir,
buf,
sizeof(buf) / sizeof(*buf),
FALSE, /* monitor the entire subtree */
FILE_NOTIFY_CHANGE_FILE_NAME |
FILE_NOTIFY_CHANGE_DIR_NAME |
FILE_NOTIFY_CHANGE_ATTRIBUTES |
FILE_NOTIFY_CHANGE_SIZE |
/*FILE_NOTIFY_CHANGE_LAST_WRITE |
FILE_NOTIFY_CHANGE_LAST_ACCESS |*/
FILE_NOTIFY_CHANGE_CREATION |
FILE_NOTIFY_CHANGE_SECURITY,
&bytesReturned,
NULL,
NULL);
if (result && bytesReturned)
{
wchar_t filename[MAX_PATH];
wchar_t action[256];
for (fni = (FILE_NOTIFY_INFORMATION*)buf; fni; )
{
switch (fni->Action)
{
// excute if a folder/ text docu is added
case FILE_ACTION_ADDED:
{
i = 1;
PostMessage (_hwndNotifySink, WM_FOLDER_CHANGE, 0, (LPARAM) _folder);
}
break;
// excute if a folder/ text docu is removed
case FILE_ACTION_REMOVED:
{
i = 1;
PostMessage (_hwndNotifySink, WM_FOLDER_CHANGE, 0, (LPARAM) _folder);
}
break;
case FILE_ACTION_MODIFIED:
{
i = 1;
if(lstrcmp(fni->FileName, L"service.log") != 0)
PostMessage (_hwndNotifySink, WM_FOLDER_CHANGE, 0, (LPARAM) _folder);
break;
}
// excute if a folder/ text docu is renamed
case FILE_ACTION_RENAMED_OLD_NAME:
{
i = 1;
PostMessage (_hwndNotifySink, WM_FOLDER_CHANGE, 0, (LPARAM) _folder);
break;
}
// excute if a folder/ text docu is renamed new name
case FILE_ACTION_RENAMED_NEW_NAME:
{
i = 1;
PostMessage (_hwndNotifySink, WM_FOLDER_CHANGE, 0, (LPARAM) _folder);
}
break;
}
if (fni->NextEntryOffset)
{
char *p = (char*)fni;
fni = (FILE_NOTIFY_INFORMATION*)(p + fni->NextEntryOffset);
}
else
{
fni = NULL;
}
}
}
else
{
i = 0;
}
}
CloseHandle(hDir); // close handle
}
return i; // return value of i
}
In case WM_FOLDER_CHANGE, I call refresh function.

Related

How to get windows folder display order by C + +

I need to get the pictures in the windows folder and sort them according to the order in which they are displayed. Now there is a method to traverse the entire folder display items through the handle by getting the folder window handle. However, this method has a drawback: it can't get the order of the unopened folder, because there is no open file and no window handle.
Qt is used.
Please forgive my grammatical mistakes.
//Find out the current folder window according to the mouse click position
HWND findOpenFileWindow(const QString& path)
{
Sleep(3 * 1000);
POINT pNow = { 0, 0 };
if (!GetCursorPos(&pNow))
return NULL;
TCHAR szClass[255] = {0};
HWND pMouseChooseHandle = WindowFromPoint(pNow);
HWND pParent = ::GetParent(pMouseChooseHandle);
GetClassName(pParent, szClass, 255);
if (_tcscmp(szClass, L"SHELLDLL_DefView") == 0 || _tcscmp(szClass, L"NSEViewClass") == 0 )
{
bool bQingDisk = _tcscmp(szClass, L"NSEViewClass") == 0;
pParent = ::GetParent(pParent);
GetClassName(pParent, szClass, 255);
if (_tcscmp(szClass, L"WorkerW"))
{
pParent = pMouseChooseHandle;
for (int i = 0; i < 6; i++)
{
if(pParent != NULL)
pParent = ::GetParent(pParent);
}
HWND pChild = ::GetWindow(pParent, GW_CHILD);
GetClassName(pChild, szClass, 255);
while (pChild != NULL)
{
GetClassName(pChild, szClass, 255);
if (_tcscmp(szClass, TEXT("ShellTabWindowClass")) == 0)
{
pParent = pChild;
break;
}
pChild = ::GetNextWindow(pChild, GW_HWNDNEXT);
}
TCHAR exploreWndName[MAX_PATH] = {0};
::GetWindowText(pParent, exploreWndName, MAX_PATH);
if(QFileInfo(path).fileName() == QString().fromWCharArray(exploreWndName))
return pParent;
}
}
return NULL;
}
//Traverse window display items, get them
QStringList listNormalFolderFile( const QString& path, const QStringList& filter )
{
HWND folderWnd = findOpenFileWindow(path);
HWND hwnd;
IDispatch *pDispatch;
CComPtr<IShellWindows> pShellWindows;
CoInitialize(NULL);
HRESULT hr = CoCreateInstance(CLSID_ShellWindows, NULL, CLSCTX_ALL, IID_PPV_ARGS(&pShellWindows));
if (FAILED(hr))
{
CoUninitialize();
return QStringList();
}
LONG lCount = 0;
pShellWindows->get_Count(&lCount);
QStringList fileList;
for (LONG i = 0; i < lCount; i++)
{
CComPtr<IShellBrowser> pShellBrowser;
VARIANT var;
var.vt = VT_I4;
var.lVal = i;
if(SUCCEEDED(pShellWindows->Item(var, &pDispatch)))
{
if(SUCCEEDED(IUnknown_QueryService(pDispatch, SID_STopLevelBrowser, IID_PPV_ARGS(&pShellBrowser))))
{
if (SUCCEEDED(IUnknown_GetWindow(pShellBrowser, &hwnd)))
{
TCHAR szBuf[256];
GetWindowText(hwnd, szBuf, sizeof(szBuf) / sizeof(TCHAR));
if(QFileInfo(path).fileName() != QString().fromWCharArray(szBuf))
continue;
CComPtr<IShellView> pShellView;
if(FAILED(pShellBrowser->QueryActiveShellView(&pShellView)))
continue;
CComPtr<IFolderView> pFv = NULL;
/*
do something here
*/
CComPtr<IPersistFolder2 > pFolder;
if( FAILED(pFv->GetFolder(IID_IPersistFolder2, (void**) &pFolder)))
continue;
LPITEMIDLIST pidl = nullptr;
if( SUCCEEDED(pFolder->GetCurFolder(&pidl)))
{
wchar_t cPath[32767];
if( ::SHGetPathFromIDList(pidl, cPath))
{
QString filePath;
QFileInfo fileInfo(filePath.fromWCharArray(cPath));
if(fileInfo.absoluteFilePath() == QFileInfo(path).absoluteFilePath())
{
if(folderWnd == NULL || folderWnd == hwnd)
{
fileList = listFileInBrowser(pShellBrowser, filter);
break;
}
}
}
}
}
}
}
}
CoUninitialize();
return fileList;

How to eject USB drive on Windows 10 (IOCTL_STORAGE_EJECT_MEDIA no longer enough)

Convention wisdom to eject a USB drive on Windows is the following sequence:
CreateFile (drive letter, with read/write rights, file share read and write)
DeviceIoControl(FSCTL_LOCK_VOLUME)
DeviceIoControl(FSCTL_DISMOUNT_VOLUME)
DeviceIoControl(IOCTL_STORAGE_MEDIA_REMOVAL) PreventMediaRemoval = FALSE
DeviceIoControl(IOCTL_STORAGE_EJECT_MEDIA)
This worked fine until a recent change in Windows 10 (not sure when). Now the drive is still properly ejected, but then Windows immediately remounts the drive.
What needs to be done to eject the drive until the user removes it and puts it in again?
Using CM_Request_Device_EjectW API works for me. You can have a try.
The following is the complete code I tested and it from "How to Prepare a USB Drive for Safe Removal" at codeproject.
(Here the "F" is my USB drive letter. Replace it using your own one.)
#include <stdio.h>
#include <windows.h>
#include <Setupapi.h>
#include <winioctl.h>
#include <winioctl.h>
#include <cfgmgr32.h>
//-------------------------------------------------
DEVINST GetDrivesDevInstByDeviceNumber(long DeviceNumber, UINT DriveType, char* szDosDeviceName);
//-------------------------------------------------
//-------------------------------------------------
int main()
{
char DriveLetter = 'F';
DriveLetter &= ~0x20; // uppercase
if (DriveLetter < 'A' || DriveLetter > 'Z') {
return 1;
}
char szRootPath[] = "F:\\"; // "X:\" -> for GetDriveType
szRootPath[0] = DriveLetter;
char szDevicePath[] = "F:"; // "X:" -> for QueryDosDevice
szDevicePath[0] = DriveLetter;
char szVolumeAccessPath[] = "\\\\.\\F:"; // "\\.\X:" -> to open the volume
szVolumeAccessPath[4] = DriveLetter;
long DeviceNumber = -1;
// open the storage volume
HANDLE hVolume = CreateFile(szVolumeAccessPath, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, NULL, NULL);
if (hVolume == INVALID_HANDLE_VALUE) {
return 1;
}
// get the volume's device number
STORAGE_DEVICE_NUMBER sdn;
DWORD dwBytesReturned = 0;
long res = DeviceIoControl(hVolume, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL, 0, &sdn, sizeof(sdn), &dwBytesReturned, NULL);
if (res) {
DeviceNumber = sdn.DeviceNumber;
}
CloseHandle(hVolume);
if (DeviceNumber == -1) {
return 1;
}
// get the drive type which is required to match the device numbers correctely
UINT DriveType = GetDriveType(szRootPath);
// get the dos device name (like \device\floppy0) to decide if it's a floppy or not - who knows a better way?
char szDosDeviceName[MAX_PATH];
res = QueryDosDevice(szDevicePath, szDosDeviceName, MAX_PATH);
if (!res) {
return 1;
}
// get the device instance handle of the storage volume by means of a SetupDi enum and matching the device number
DEVINST DevInst = GetDrivesDevInstByDeviceNumber(DeviceNumber, DriveType, szDosDeviceName);
if (DevInst == 0) {
return 1;
}
PNP_VETO_TYPE VetoType = PNP_VetoTypeUnknown;
WCHAR VetoNameW[MAX_PATH];
VetoNameW[0] = 0;
bool bSuccess = false;
// get drives's parent, e.g. the USB bridge, the SATA port, an IDE channel with two drives!
DEVINST DevInstParent = 0;
res = CM_Get_Parent(&DevInstParent, DevInst, 0);
for (long tries = 1; tries <= 3; tries++) { // sometimes we need some tries...
VetoNameW[0] = 0;
// CM_Query_And_Remove_SubTree doesn't work for restricted users
//res = CM_Query_And_Remove_SubTreeW(DevInstParent, &VetoType, VetoNameW, MAX_PATH, CM_REMOVE_NO_RESTART); // CM_Query_And_Remove_SubTreeA is not implemented under W2K!
//res = CM_Query_And_Remove_SubTreeW(DevInstParent, NULL, NULL, 0, CM_REMOVE_NO_RESTART); // with messagebox (W2K, Vista) or balloon (XP)
res = CM_Request_Device_EjectW(DevInstParent, &VetoType, VetoNameW, MAX_PATH, 0);
//res = CM_Request_Device_EjectW(DevInstParent, NULL, NULL, 0, 0); // with messagebox (W2K, Vista) or balloon (XP)
bSuccess = (res == CR_SUCCESS && VetoType == PNP_VetoTypeUnknown);
if (bSuccess) {
break;
}
Sleep(500); // required to give the next tries a chance!
}
if (bSuccess) {
printf("Success\n\n");
return 0;
}
printf("failed\n");
printf("Result=0x%2X\n", res);
if (VetoNameW[0]) {
printf("VetoName=%ws)\n\n", VetoNameW);
}
return 1;
}
//-----------------------------------------------------------
//----------------------------------------------------------------------
// returns the device instance handle of a storage volume or 0 on error
//----------------------------------------------------------------------
DEVINST GetDrivesDevInstByDeviceNumber(long DeviceNumber, UINT DriveType, char* szDosDeviceName)
{
bool IsFloppy = (strstr(szDosDeviceName, "\\Floppy") != NULL); // who knows a better way?
GUID* guid;
switch (DriveType) {
case DRIVE_REMOVABLE:
if (IsFloppy) {
guid = (GUID*)&GUID_DEVINTERFACE_FLOPPY;
}
else {
guid = (GUID*)&GUID_DEVINTERFACE_DISK;
}
break;
case DRIVE_FIXED:
guid = (GUID*)&GUID_DEVINTERFACE_DISK;
break;
case DRIVE_CDROM:
guid = (GUID*)&GUID_DEVINTERFACE_CDROM;
break;
default:
return 0;
}
// Get device interface info set handle for all devices attached to system
HDEVINFO hDevInfo = SetupDiGetClassDevs(guid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
if (hDevInfo == INVALID_HANDLE_VALUE) {
return 0;
}
// Retrieve a context structure for a device interface of a device information set
DWORD dwIndex = 0;
long res;
BYTE Buf[1024];
PSP_DEVICE_INTERFACE_DETAIL_DATA pspdidd = (PSP_DEVICE_INTERFACE_DETAIL_DATA)Buf;
SP_DEVICE_INTERFACE_DATA spdid;
SP_DEVINFO_DATA spdd;
DWORD dwSize;
spdid.cbSize = sizeof(spdid);
while (true) {
res = SetupDiEnumDeviceInterfaces(hDevInfo, NULL, guid, dwIndex, &spdid);
if (!res) {
break;
}
dwSize = 0;
SetupDiGetDeviceInterfaceDetail(hDevInfo, &spdid, NULL, 0, &dwSize, NULL); // check the buffer size
if (dwSize != 0 && dwSize <= sizeof(Buf)) {
pspdidd->cbSize = sizeof(*pspdidd); // 5 Bytes!
ZeroMemory(&spdd, sizeof(spdd));
spdd.cbSize = sizeof(spdd);
long res = SetupDiGetDeviceInterfaceDetail(hDevInfo, &spdid, pspdidd, dwSize, &dwSize, &spdd);
if (res) {
// in case you are interested in the USB serial number:
// the device id string contains the serial number if the device has one,
// otherwise a generated id that contains the '&' char...
/*
DEVINST DevInstParent = 0;
CM_Get_Parent(&DevInstParent, spdd.DevInst, 0);
char szDeviceIdString[MAX_PATH];
CM_Get_Device_ID(DevInstParent, szDeviceIdString, MAX_PATH, 0);
printf("DeviceId=%s\n", szDeviceIdString);
*/
// open the disk or cdrom or floppy
HANDLE hDrive = CreateFile(pspdidd->DevicePath, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
if (hDrive != INVALID_HANDLE_VALUE) {
// get its device number
STORAGE_DEVICE_NUMBER sdn;
DWORD dwBytesReturned = 0;
res = DeviceIoControl(hDrive, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL, 0, &sdn, sizeof(sdn), &dwBytesReturned, NULL);
if (res) {
if (DeviceNumber == (long)sdn.DeviceNumber) { // match the given device number with the one of the current device
CloseHandle(hDrive);
SetupDiDestroyDeviceInfoList(hDevInfo);
return spdd.DevInst;
}
}
CloseHandle(hDrive);
}
}
}
dwIndex++;
}
SetupDiDestroyDeviceInfoList(hDevInfo);
return 0;
}

Asynchronous ReadDirectoryChangesW fails with ERROR_INVALID_PARAMETER

I've managed to use ReadDirectoryChangesW synchronously, but when I attempt to use completion ports, ReadDirectoryChangesW always returns ERROR_INVALID_PARAMETER. I guess there should be some obvious error in my code, but I cannot figure it.
My code is based on How to use ReadDirectoryChangesW() method with completion routine?
const wchar_t *directory = L"X:\\X";
HANDLE h = CreateFile(
directory,
FILE_LIST_DIRECTORY,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL, OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS|FILE_FLAG_OVERLAPPED, NULL);
if (h==INVALID_HANDLE_VALUE) return;
HANDLE p = CreateIoCompletionPort(h,0,0,1);
if (p==NULL) {CloseHandle(h); return;}
DWORD *buffer =new DWORD[4096];
DWORD bytesReturned;
DWORD notifyFilter = FILE_NOTIFY_CHANGE_FILE_NAME
| FILE_NOTIFY_CHANGE_DIR_NAME
| FILE_NOTIFY_CHANGE_SIZE
| FILE_NOTIFY_CHANGE_LAST_WRITE;
while (true) {
OVERLAPPED overlapped;
memset(&overlapped,0,sizeof(overlapped));
BOOL success = ReadDirectoryChangesW(h,
&buffer[0],
4096*sizeof(DWORD),
FALSE, notifyFilter,
NULL, //&bytesReturned,
&overlapped,myFileIOCompletionRoutine);
if (!success) {
//always ERROR_INVALID_PARAMETER
CloseHandle(h);
CloseHandle(p);
return;
}
}
As Hans Passant kindly reminds, the documentation already says that a completion routine must not be used if the directory is associated to a completion port. In this case I solved the problem by waiting on the completion port, i.e. ReadDirectoryChangesW(...,&overlapped,0);
Complete code is below.
while (true) {
OVERLAPPED overlapped;
memset(&overlapped,0,sizeof(overlapped));
BOOL success = ReadDirectoryChangesW(h,
&buffer[0],
4096*sizeof(DWORD),
FALSE, notifyFilter, 0, &overlapped,0);
if (!success) {
if (GetLastError()==ERROR_INVALID_HANDLE) {
//asynchronously closed by cancel
CloseHandle(p); //close completion port
return 0;
} else {
CloseHandle(h); //close directory handle
CloseHandle(p); //close completion port
return 1;
}
}
DWORD di;
LPOVERLAPPED lpOverlapped;
if (!GetQueuedCompletionStatus(p,&bytesReturned,&di,&lpOverlapped,1000)) {
int ret;
if (GetLastError()==WAIT_TIMEOUT) {
if (GetFileAttributes(directory)!=INVALID_FILE_ATTRIBUTES) {
continue; //timeout
} else {
//directory has been deleted or renamed
ret=0;
}
} else {
//other failure
ret=1;
}
CloseHandle(h); //close directory handle
CloseHandle(p); //close completion port
return ret;
}
char* ptr = (char*)&buffer[0];
char* end = ptr+bytesReturned;
while (ptr<end) {
FILE_NOTIFY_INFORMATION *info = (FILE_NOTIFY_INFORMATION*) ptr;
//process FILE_NOTIFY_INFORMATION
ptr+=info->NextEntryOffset;
if (!info->NextEntryOffset) break;
}
}

How can I get the Primary access token in windows 8?

I want to get the primary token so that I can get the access of OpenInputDesktop() and do my necessary things.
I browsed all over the sites for help and found the conclusive code as below but I got an error on calling DuplicateTokenEx() is 998 which means invalid access to memory location.
HANDLE GetCurrentUserToken()
{
HANDLE currentToken = 0;
PHANDLE primaryToken = 0;
unsigned int winlogonPid = 0;
int dwSessionId = 0;
PHANDLE hUserToken = 0;
PHANDLE hTokenDup = 0;
PWTS_SESSION_INFO pSessionInfo = 0;
DWORD dwCount = 0;
WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1,
&pSessionInfo, &dwCount);
//TestLog("Error on WTSEnumerateSessions(): %d",GetLastError());
int dataSize = sizeof(WTS_SESSION_INFO);
for (DWORD i = 0; i < dwCount; ++i)
{
WTS_SESSION_INFO si = pSessionInfo[i];
if (WTSActive == si.State)
{
dwSessionId = si.SessionId;
break;
}
}
WTSFreeMemory(pSessionInfo);
array<Process^>^localByName = Process::GetProcessesByName( "winlogon" );
for (int i=0;i<localByName->Length;i++)
{
Process ^ p1 = (Process^)(localByName->GetValue(i));
if ((unsigned int)p1->SessionId == dwSessionId)
{
winlogonPid = (unsigned int)p1->Id;
}
}
// obtain a handle to the winlogon process
HANDLE hProcess = OpenProcess(MAXIMUM_ALLOWED, false, winlogonPid);
TestLog("Error on OpenProcess():",GetLastError());
// obtain a handle to the access token of the winlogon process
if (!OpenProcessToken(hProcess, TOKEN_DUPLICATE, &currentToken))
{
TestLog("Error on OpenProcessToken():",GetLastError());
CloseHandle(hProcess);
return false;
}
BOOL bRet ;
// bRet = DuplicateTokenEx(currentToken,
// MAXIMUM_ALLOWED /*TOKEN_ASSIGN_PRIMARY | TOKEN_ALL_ACCESS*/,
// NULL/*0*/,
// SecurityImpersonation, TokenImpersonation, primaryToken);
bRet = DuplicateTokenEx(currentToken,
TOKEN_ASSIGN_PRIMARY | TOKEN_ALL_ACCESS,
NULL, SecurityImpersonation,
TokenPrimary, primaryToken);
TestLog("Error on DuplicateTokenEx():",GetLastError());
TestLog("return value of DuplicateTokenEx()",bRet);
int errorcode = GetLastError();
if (bRet == false)
{
return 0;
}
return primaryToken;
}
int main(array<System::String ^> ^args)
{
Console::WriteLine(L"Hello World");
TestLog("**Start TestLaunchExeOneTime**",0);
HANDLE hTokenNew = NULL, hTokenDup = NULL;
HMODULE hmod = LoadLibrary(L"kernel32.dll");
hTokenDup = GetCurrentUserToken();
STARTUPINFO si;
PROCESS_INFORMATION pi;
memset(&si,0,sizeof(STARTUPINFO));
si.cb = sizeof( STARTUPINFO );
si.lpDesktop = L"winsta0\\default";
LPVOID pEnv = NULL;
DWORD dwCreationFlag = NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE;
HMODULE hModule = LoadLibrary(L"Userenv.dll");
if(hModule )
{
if(CreateEnvironmentBlock(&pEnv,hTokenDup,FALSE))
{
//WriteToLog("CreateEnvironmentBlock Ok");
dwCreationFlag |= CREATE_UNICODE_ENVIRONMENT;
}
else
{
TestLog("Error on CreateEnvironmentBlock():",GetLastError());
pEnv = NULL;
}
}
//
if ( !CreateProcessAsUser( hTokenDup,
NULL,
L"C:\\temp\\DesktopDuplicationmilliseconds.exe",
NULL,
NULL,
FALSE,
dwCreationFlag,
pEnv,
NULL,
&si,
&pi
))
{
}
else
{
TestLog("Error on CreateProcessAsUser():",GetLastError());
// printf("error : %d",GetLastError());
}
return 0;
}
You haven't allocated any memory for the primary token. The primaryToken variable is a pointer to a handle, but you haven't actually pointed it to anything. (You've also declared GetCurrentUserToken as a function that returns a handle, but are actually returning a pointer to a handle.)
You need to either explicitly allocate the memory for the handle:
primaryToken = malloc(sizeof(HANDLE));
[...]
return *primaryToken;
or, more sensibly, define primaryToken as a HANDLE rather than a pointer and pass a reference to it in the appropriate place:
HANDLE primaryToken;
[...]
bRet = DuplicateTokenEx(currentToken,
TOKEN_ASSIGN_PRIMARY | TOKEN_ALL_ACCESS,
NULL, SecurityImpersonation,
TokenPrimary, &primaryToken);

Using GetRawInputBuffer correctly

I'm attempting to use the Win32 Raw Input API to collect raw mouse data with higher precision, but I can't seem to make sense of the documentation and samples at all for GetRawInputBuffer.
While my mouse is hovering over the window, nothing seems to happen. I only seem to get buffered data when I click or release on the title bar of the window and even then I mostly get 0 movement values and never receive mouse button changes. I've followed samples as closely as possible and have had little luck searching online.
Below is the the Window Procedure and Main for a heavily simplified example bearing the issue.
LRESULT CALLBACK MessageHandler(HWND WindowHandle, UINT Message, WPARAM wParameter, LPARAM lParameter)
{
switch(Message)
{
case WM_DESTROY:
{
PostQuitMessage(0);
return 0;
}
break;
case WM_CLOSE:
{
DestroyWindow(WindowHandle);
return 0;
}
break;
case WM_INPUT:
{
UINT RawInputSize;
UINT Result;
Result = GetRawInputBuffer(NULL, &(RawInputSize), sizeof(RAWINPUTHEADER));
if(Result == -1)
{
DWORD ErrorCode = GetLastError();
std::cout << "GetRawInputBuffer returned error code" << ErrorCode << std::endl;
}
else if(Result == 0 && RawInputSize != 0)
{
UINT AllocatedBufferByteCount = RawInputSize * 16;
RAWINPUT* RawInputBuffer = reinterpret_cast<RAWINPUT*>(malloc(AllocatedBufferByteCount));
UINT AllocatedBufferByteCountTwo = AllocatedBufferByteCount;
Result = GetRawInputBuffer(RawInputBuffer, &(AllocatedBufferByteCountTwo), sizeof(RAWINPUTHEADER));
if(Result == -1)
{
DWORD ErrorCode = GetLastError();
std::cout << "GetRawInputBuffer returned error code" << ErrorCode << std::endl;
}
else if(Result != 0)
{
UINT RawInputCount = Result;
DWORD MouseDeltaX = 0;
DWORD MouseDeltaY = 0;
bool ButtonsPressed[2] = {false, false};
RAWINPUT* RawInput = RawInputBuffer;
for(unsigned int i = 0; i < RawInputCount; ++i)
{
switch(RawInput->header.dwType)
{
// Raw mouse movement data for high-resolution mice.
case RIM_TYPEMOUSE:
{
MouseDeltaX += RawInput->data.mouse.lLastX;
MouseDeltaY += RawInput->data.mouse.lLastY;
ButtonsPressed[0] = ((RawInput->data.mouse.usButtonFlags & RI_MOUSE_LEFT_BUTTON_DOWN) == RI_MOUSE_LEFT_BUTTON_DOWN);
ButtonsPressed[1] = ((RawInput->data.mouse.usButtonFlags & RI_MOUSE_RIGHT_BUTTON_DOWN) == RI_MOUSE_RIGHT_BUTTON_DOWN);
}
break;
}
RawInput = NEXTRAWINPUTBLOCK(RawInput);
}
DefRawInputProc(&(RawInputBuffer), RawInputCount, sizeof(RAWINPUTHEADER));
std::cout << "Mouse moved (" << MouseDeltaX << ", " << MouseDeltaY << ")." << std::endl;
if(ButtonsPressed[0])
{
std::cout << "LMB pressed." << std::endl;
}
if(ButtonsPressed[1])
{
std::cout << "RMB pressed." << std::endl;
}
}
free(RawInputBuffer);
}
return 0;
}
break;
default:
{
return DefWindowProc(WindowHandle, Message, wParameter, lParameter);
}
break;
}
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
// Initialize window strings.
wchar_t WindowClassName[] = L"DominionWindowClass";
wchar_t WindowCaption[] = L"Test Window";
// Create the window class.
WNDCLASSEX WindowClass;
WindowClass.cbSize = sizeof(WindowClass);
WindowClass.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
WindowClass.lpfnWndProc = &(MessageHandler);
WindowClass.cbClsExtra = 0;
WindowClass.cbWndExtra = 0;
WindowClass.hInstance = hInstance;
WindowClass.hIcon = LoadIcon(hInstance, IDI_APPLICATION);
WindowClass.hIconSm = LoadIcon(hInstance, IDI_APPLICATION);
WindowClass.hCursor = LoadCursor(NULL, IDC_ARROW);
WindowClass.hbrBackground = NULL;
WindowClass.lpszMenuName = NULL;
WindowClass.lpszClassName = WindowClassName;
// Register window class.
RegisterClassEx(&WindowClass);
// Setup window style flags.
DWORD WindowStyles = WS_VISIBLE | WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU;
DWORD ExWindowStyles = WS_EX_APPWINDOW;
// Setup window rectangle area.
RECT WindowArea;
WindowArea.left = 0;
WindowArea.top = 0;
WindowArea.right = 1024;
WindowArea.bottom = 768;
AdjustWindowRectEx(&(WindowArea), WindowStyles, false, ExWindowStyles);
// Window creation.
HWND WindowHandle = CreateWindowEx(ExWindowStyles, WindowClass.lpszClassName, WindowCaption, WindowStyles, CW_USEDEFAULT, CW_USEDEFAULT, (WindowArea.right - WindowArea.left), (WindowArea.bottom - WindowArea.top), NULL, NULL, hInstance, NULL);
// Display the window.
ShowWindow(WindowHandle, SW_SHOWDEFAULT);
UpdateWindow(WindowHandle);
// Register devices for raw input.
const unsigned int RawInputDeviceCount = 1;
RAWINPUTDEVICE RawInputDevices[RawInputDeviceCount];
memset(RawInputDevices, 0, RawInputDeviceCount * sizeof(RAWINPUTDEVICE));
RAWINPUTDEVICE* MouseRawInputDevice;
MouseRawInputDevice = RawInputDevices;
MouseRawInputDevice->usUsagePage = 1;
MouseRawInputDevice->usUsage = 2;
MouseRawInputDevice->hwndTarget = WindowHandle;
BOOL SuccessfullyRegisteredInput = RegisterRawInputDevices(RawInputDevices, RawInputDeviceCount, sizeof(RAWINPUTDEVICE));
// Core loop.
MSG Message;
for(;;)
{
while(PeekMessage(&Message, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&Message);
DispatchMessage(&Message);
if(Message.message == WM_QUIT)
{
break;
}
}
if(Message.message == WM_QUIT)
{
break;
}
}
// Unregister devices for raw input.
memset(RawInputDevices, 0, RawInputDeviceCount * sizeof(RAWINPUTDEVICE));
MouseRawInputDevice = RawInputDevices;
MouseRawInputDevice->usUsagePage = 1;
MouseRawInputDevice->usUsage = 2;
MouseRawInputDevice->dwFlags = RIDEV_REMOVE;
MouseRawInputDevice->hwndTarget = NULL;
BOOL SuccessfullyUnregisteredInput = RegisterRawInputDevices(RawInputDevices, RawInputDeviceCount, sizeof(RAWINPUTDEVICE));
return Message.wParam;
}
I can't think of a simpler way to experiment with the Raw Input API. Thoughts?
Long late answer, but GetRawInputBuffer seems to be used for polling outside of the message processing loop. Use GetRawInputData within WM_INPUT handling or use GetRawInputBuffer outside the message processing loop.
I guess with GetRawInputBuffer() you can only read HID data. That means only the hid structure in the data part of the RAWINPUT structure is filled with input data. I was able to read input from my keyboard using the bRawData member of RAWHID but i think thats useless because that values vary from keyboard to keyboard. So I switched back to GetRawInputData....

Resources