Josh Posted August 1, 2010 Share Posted August 1, 2010 Has anyone set this function up to run asynchronously? I've got it working but there is no timeout value, so it pauses until a change occurs: http://msdn.microsoft.com/en-us/library/aa365465%28VS.85%29.aspx Quote My job is to make tools you love, with the features you want, and performance you can't live without. Link to comment Share on other sites More sharing options...
Rick Posted August 1, 2010 Share Posted August 1, 2010 So the function pauses? Like when you call it, it doesn't come back until a change happens? That doesn't sound very asynchronous to me. I would assume the call would return right away, and the function you provided as the callback gets called when something changes in the directory. Quote Link to comment Share on other sites More sharing options...
Rick Posted August 1, 2010 Share Posted August 1, 2010 This code works, & I got it from the last post at http://cboard.cprogramming.com/windows-programming/77061-readdirectorychangesw.html. He talks about a special message loop. I'm not sure if the message loop is hidden from the users in BMax so not sure if it can be used in BMax. #define _WIN32_WINNT 0x0400 #include <windows.h> #include <windowsx.h> #include <commctrl.h> #include <shlwapi.h> #if defined(_MSC_VER) #pragma comment(lib, "comctl32.lib") #pragma comment(lib, "user32.lib") #pragma comment(lib, "ole32.lib") #endif HINSTANCE g_hinst; typedef void (CALLBACK *FileChangeCallback)(LPTSTR, DWORD, LPARAM); typedef struct tagDIR_MONITOR { OVERLAPPED ol; HANDLE hDir; BYTE buffer[32 * 1024]; LPARAM lParam; DWORD notifyFilter; BOOL fStop; FileChangeCallback callback; } *HDIR_MONITOR; /* * Unpacks events and passes them to a user defined callback. */ VOID CALLBACK MonitorCallback(DWORD dwErrorCode, DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOverlapped) { TCHAR szFile[MAX_PATH]; PFILE_NOTIFY_INFORMATION pNotify; HDIR_MONITOR pMonitor = (HDIR_MONITOR) lpOverlapped; size_t offset = 0; BOOL RefreshMonitoring(HDIR_MONITOR pMonitor); if (dwErrorCode == ERROR_SUCCESS) { do { pNotify = (PFILE_NOTIFY_INFORMATION) &pMonitor->buffer[offset]; offset += pNotify->NextEntryOffset; # if defined(UNICODE) { lstrcpynW(szFile, pNotify->FileName, min(MAX_PATH, pNotify->FileNameLength / sizeof(WCHAR) + 1)); } # else { int count = WideCharToMultiByte(CP_ACP, 0, pNotify->FileName, pNotify->FileNameLength / sizeof(WCHAR), szFile, MAX_PATH - 1, NULL, NULL); szFile[count] = TEXT('\0'); } # endif pMonitor->callback(szFile, pNotify->Action, pMonitor->lParam); } while (pNotify->NextEntryOffset != 0); } if (!pMonitor->fStop) { RefreshMonitoring(pMonitor); } } /* * Refreshes the directory monitoring. */ BOOL RefreshMonitoring(HDIR_MONITOR pMonitor) { return ReadDirectoryChangesW(pMonitor->hDir, pMonitor->buffer, sizeof(pMonitor->buffer), FALSE, pMonitor->notifyFilter, NULL, &pMonitor->ol, MonitorCallback); } /* * Stops monitoring a directory. */ void StopMonitoring(HDIR_MONITOR pMonitor) { if (pMonitor) { pMonitor->fStop = TRUE; CancelIo(pMonitor->hDir); if (!HasOverlappedIoCompleted(&pMonitor->ol)) { SleepEx(5, TRUE); } CloseHandle(pMonitor->ol.hEvent); CloseHandle(pMonitor->hDir); HeapFree(GetProcessHeap(), 0, pMonitor); } } /* * Starts monitoring a directory. */ HDIR_MONITOR StartMonitoring(LPCTSTR szDirectory, DWORD notifyFilter, FileChangeCallback callback) { HDIR_MONITOR pMonitor = (HDIR_MONITOR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pMonitor)); pMonitor->hDir = CreateFile(szDirectory, FILE_LIST_DIRECTORY, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, NULL); if (pMonitor->hDir != INVALID_HANDLE_VALUE) { pMonitor->ol.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); pMonitor->notifyFilter = notifyFilter; pMonitor->callback = callback; if (RefreshMonitoring(pMonitor)) { return pMonitor; } else { CloseHandle(pMonitor->ol.hEvent); CloseHandle(pMonitor->hDir); } } HeapFree(GetProcessHeap(), 0, pMonitor); return NULL; } /* * Runs a message loop that allows APCs to be despatched. */ int RunAPCMessageLoop(void) { BOOL done = FALSE; MSG msg = { 0 }; while (!done) { /* Wait for either an APC or a message. */ while (WAIT_IO_COMPLETION == MsgWaitForMultipleObjectsEx(0, NULL, INFINITE, QS_ALLINPUT, MWMO_ALERTABLE)) /* Do nothing */; /* One or more messages have arrived. */ while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { if (msg.message == WM_QUIT) { done = TRUE; break; } TranslateMessage(&msg); DispatchMessage(&msg); } } return (int) msg.wParam; } void CALLBACK FileCallback(LPTSTR szFile, DWORD action, LPARAM lParam) { /* Shouldn't call MessageBox as it will block new notifications coming in. */ MessageBox(NULL, szFile, NULL, 0); } HDIR_MONITOR h; BOOL OnCreate(HWND hwnd, LPCREATESTRUCT lpcs) { h = StartMonitoring(TEXT("C:\\Documents and Settings\\Games\\My Documents"), FILE_NOTIFY_CHANGE_CREATION | FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_FILE_NAME, FileCallback); return TRUE; } void OnDestroy(HWND hwnd) { if (h) StopMonitoring(h); PostQuitMessage(0); } LRESULT CALLBACK WndProc(HWND hwnd, UINT uiMsg, WPARAM wParam, LPARAM lParam) { switch (uiMsg) { HANDLE_MSG(hwnd, WM_CREATE, OnCreate); HANDLE_MSG(hwnd, WM_DESTROY, OnDestroy); } return DefWindowProc(hwnd, uiMsg, wParam, lParam); } BOOL InitApp(void) { WNDCLASS wc = { 0 }; wc.style = 0; wc.lpfnWndProc = WndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = g_hinst; wc.hIcon = NULL; wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); wc.lpszMenuName = NULL; wc.lpszClassName = TEXT("Scratch"); if (!RegisterClass(&wc)) return FALSE; return TRUE; } int WINAPI WinMain(HINSTANCE hinst, HINSTANCE hinstPrev, LPSTR lpCmdLine, int nShowCmd) { HWND hwnd; int result; g_hinst = hinst; if (!InitApp()) return 0; hwnd = CreateWindow( TEXT("Scratch"), /* Class Name */ TEXT("Scratch"), /* Title */ WS_OVERLAPPEDWINDOW, /* Style */ CW_USEDEFAULT, CW_USEDEFAULT, /* Position */ CW_USEDEFAULT, CW_USEDEFAULT, /* Size */ NULL, /* Parent */ NULL, /* No menu */ hinst, /* Instance */ 0); /* No special parameters */ ShowWindow(hwnd, nShowCmd); result = RunAPCMessageLoop(); return result; } Quote Link to comment Share on other sites More sharing options...
Rick Posted August 1, 2010 Share Posted August 1, 2010 btw, I can't stand Win32 API programming. I need to shower now. In .NET this is all encapsulated in a class and it's very easy Quote Link to comment Share on other sites More sharing options...
Josh Posted August 1, 2010 Author Share Posted August 1, 2010 The docs say there are three ways of doing it, and the GetOverlappedResult() function seems like the least BS. However, it is still pausing when I call the function. Quote My job is to make tools you love, with the features you want, and performance you can't live without. Link to comment Share on other sites More sharing options...
Josh Posted August 1, 2010 Author Share Posted August 1, 2010 This is the OVERLAPPED structure: typedef struct _OVERLAPPED { ULONG_PTR Internal; ULONG_PTR InternalHigh; union { struct { DWORD Offset; DWORD OffsetHigh; } ; PVOID Pointer; } ; HANDLE hEvent; } OVERLAPPED, *LPOVERLAPPED; Is this BMX code the same thing?: Type OVERLAPPED Method Delete() CloseHandle(hEvent) EndMethod Field Internal:Int Field InternalHigh:Int Field Offset:Int Field OffsetHigh:Int Field Pointer:Byte Ptr Field hEvent:Int=CreateEventA(0,0,False,"MyEvent") EndType Quote My job is to make tools you love, with the features you want, and performance you can't live without. Link to comment Share on other sites More sharing options...
Canardia Posted August 1, 2010 Share Posted August 1, 2010 I wouldn't use Windows API calls. I've done a multithreaded directory reader with cross-platforms calls. I tested it by reading the whole directory of my harddrive, while running an LE app with a rotating cube. The cube didn't stutter or slow down at all. Quote ■ Ryzen 9 ■ RX 6800M ■ 16GB ■ XF8 ■ Windows 11 ■ ■ Ultra ■ LE 2.5 ■ 3DWS 5.6 ■ Reaper ■ C/C++ ■ C# ■ Fortran 2008 ■ Story ■ ■ Homepage: https://canardia.com ■ Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.