Hi there finally I have it working, first of all there were several errors in my code the event objects were using the same name (In my working code example only one event object was necessary). also I had to make several other changes as well.
#include <Windows.h>
#include <stdio.h>
#include <stdlib.h> // For malloc, realloc, free
#include <string.h>
#include <wchar.h> // For wcslen and wcscpy
HANDLE g_NewFileItemEvent;
HANDLE g_NoMoreWorkEvent;
WCHAR* filePath;
WIN32_FIND_DATAW fd;
WCHAR subPath[MAX_PATH];
const WCHAR* rootPath = L"D:\\search";
CRITICAL_SECTION g_queueCS;
typedef struct {
WCHAR** data; // Pointer to an array of string pointers
int size; // Current number of strings in the array
int capacity; // Allocated capacity of the array
} StringDynamicArray;
StringDynamicArray myFolders;
StringDynamicArray myFiles;
void initStringDynamicArray(StringDynamicArray* arr, int initialCapacity) {
arr->data = (WCHAR**)malloc(sizeof(WCHAR*) * initialCapacity);
if (arr->data == NULL) {
perror("Failed to allocate initial memory for string array");
exit(EXIT_FAILURE);
}
arr->size = 0;
arr->capacity = initialCapacity;
}
void pushString(StringDynamicArray* arr, const WCHAR* str) {
if (arr->size == arr->capacity) {
arr->capacity *= 2;
arr->data = (WCHAR**)realloc(arr->data, sizeof(WCHAR*) * arr->capacity);
if (arr->data == NULL) {
perror("Failed to reallocate memory for string array");
exit(EXIT_FAILURE);
}
}
size_t strLen = wcslen(str);
arr->data[arr->size] = (WCHAR*)malloc((strLen + 1) * sizeof(wchar_t)); // +1 for null terminator
if (arr->data[arr->size] == NULL) {
perror("Failed to allocate memory for string");
exit(EXIT_FAILURE);
}
// Use wcscpy_s with the correct buffer size (strLen + 1)
errno_t err = wcscpy_s(arr->data[arr->size], strLen + 1, str);
if (err == 0) {
//wprintf(L"Successfully copied: %ls\n", arr->data[arr->size]);
arr->size++;
}
else {
wprintf(L"Error copying string. Error code: %d\n", err);
}
}
WCHAR* popString(StringDynamicArray* arr) {
if (arr->size == 0) {
fprintf(stderr, "Error: Cannot pop from an empty array.\n");
return NULL;
}
arr->size--;
WCHAR* poppedStr = arr->data[arr->size];
return poppedStr; // Caller is responsible for freeing this memory
}
void freeStringDynamicArray(StringDynamicArray* arr) {
for (int i = 0; i < arr->size; i++) {
free(arr->data[i]); // Free individual strings
}
free(arr->data); // Free the array of pointers
arr->data = NULL;
arr->size = 0;
arr->capacity = 0;
}
void searchDirectories(const WCHAR* path) {
WIN32_FIND_DATAW findData;
HANDLE hFind = INVALID_HANDLE_VALUE;
WCHAR searchPath[MAX_PATH];
WCHAR subPath[MAX_PATH];
//::EnterCriticalSection(&g_queueCS);
//pushString(&myFolders, (LPCWSTR)path);
// Construct the search pattern (e.g., "D:\\search\\*")
swprintf_s(searchPath, MAX_PATH, L"%s\\*", path);
// Start the search with FindFirstFileW
hFind = FindFirstFileW(searchPath, &findData);
if (hFind == INVALID_HANDLE_VALUE) {
wprintf(L"Error opening directory %s: %d\n", path, GetLastError());
return;
}
// Iterate through all files and directories
do {
// Skip the current (".") and parent ("..") directories
if (wcscmp(findData.cFileName, L".") == 0 || wcscmp(findData.cFileName, L"..") == 0) {
continue;
}
// Construct the full path of the current file or directory
swprintf_s(subPath, MAX_PATH, L"%s\\%s", path, findData.cFileName);
// Print the full path
//wprintf(L"%s\n", subPath);
// If it's a directory, recursively search it
if (findData.dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY) {
wprintf(L"[DIR]: %ws\n", subPath);
pushString(&myFolders, (LPCWSTR)subPath);
searchDirectories(subPath);
}
} while (FindNextFileW(hFind, &findData) != 0);
//::LeaveCriticalSection(&g_queueCS);
// Check if the loop ended due to an error
DWORD error = GetLastError();
if (error != ERROR_NO_MORE_FILES) {
wprintf(L"Error during directory search: %d\n", error);
}
// Close the search handle
FindClose(hFind);
}
//IN each directory provided as an argument search for all files in it
void searchFiles(const WCHAR* path) {
WIN32_FIND_DATAW findData;
HANDLE hFind = INVALID_HANDLE_VALUE;
WCHAR searchPath[MAX_PATH];
WCHAR subPath[MAX_PATH];
swprintf_s(searchPath, MAX_PATH, L"%s\\*", path);
// Start the search with FindFirstFileW
hFind = FindFirstFileW(searchPath, &findData);
if (hFind == INVALID_HANDLE_VALUE) {
wprintf(L"Error opening directory %s: %d\n", path, GetLastError());
return;
}
// Iterate through all files and directories
while (FindNextFileW(hFind, &findData) != 0) {
// Skip the current (".") and parent ("..") directories
if (wcscmp(findData.cFileName, L".") == 0 || wcscmp(findData.cFileName, L"..") == 0) {
continue;
}
// Construct the full path of the current file or directory
swprintf_s(subPath, MAX_PATH, L"%s\\%s", path, findData.cFileName);
// Print the full path
//wprintf(L"%s\n", subPath);
// If it's NOT a directory, write it to the myFiles Struct
if (findData.dwFileAttributes != FILE_ATTRIBUTE_DIRECTORY) {
//wprintf(L"[FILE]: %s\n", subPath);
::EnterCriticalSection(&g_queueCS);
//printf("Size: %d\n", myFiles.size);
pushString(&myFiles, (LPCWSTR)subPath);
::LeaveCriticalSection(&g_queueCS);
}
}
printf("File thread: Finished producing items.\n");
// Check if the loop ended due to an error
DWORD error = GetLastError();
if (error != ERROR_NO_MORE_FILES) {
wprintf(L"Error during directory search: %d\n", error);
}
// Close the search handle
FindClose(hFind);
}
BOOL FileMatchesSearch(WCHAR fullPath[], WCHAR targetString[]) {
size_t fullPathLen = wcslen(fullPath);
size_t targetStringLen = wcslen(targetString);
// Check if the full path is long enough to contain the target string
if (fullPathLen >= targetStringLen) {
// Get a pointer to the potential start of the target string in fullPath
WCHAR* endOfPath = fullPath + (fullPathLen - targetStringLen);
// Compare the substring with the target string
if (wcscmp(endOfPath, targetString) == 0) {
//printf("'%ws' exists at the end of the path.\n", targetString);
printf("File path found: %ws\n", fullPath);
return TRUE;
}
else {
printf("'%ws' does NOT exist at the end of the path.\n", targetString);
return FALSE;
}
}
else {
printf("The path is too short to contain '%ws'.\n", targetString);
return FALSE;
}
}
DWORD WINAPI FolderThread(PVOID) {
searchDirectories(rootPath);
::Sleep(20000);
::SetEvent(g_NewFileItemEvent);
return 42;
}
DWORD WINAPI FileThread(LPVOID lpParam) {
printf("File thread: waiting for Start signal.\n");
::WaitForSingleObject(g_NewFileItemEvent, INFINITE);
const WCHAR* folderPath = (WCHAR*)lpParam;
wprintf(L"Processing string: %s\n", folderPath);
printf("File thread: Starting.\n");
searchFiles(folderPath);
printf("File thread: Exiting.\n");
return 42;
}
DWORD WINAPI SearchThread(PVOID) {
printf("Search thread started. Waiting for manual reset event...\n");
// Wait for the manual reset event
WaitForSingleObject(g_NewFileItemEvent, INFINITE);
printf("Search thread: Event received! Starting to consume items...\n");
while (myFiles.size !=0) {
::EnterCriticalSection(&g_queueCS);
WCHAR* filePath = NULL;
if (myFiles.size != 0)
{
filePath = popString(&myFiles);
WCHAR searchPattern[] = L"My_search_item.txt";
// Allocate a WCHAR array on the stack, including space for the null terminator
const int MAX_LENGTH = 256; // Or a suitable maximum length
WCHAR destinationArray[MAX_LENGTH];
// Copy the string
wcscpy_s(destinationArray, MAX_LENGTH, filePath);
if (FileMatchesSearch(destinationArray, searchPattern)) {
printf("File Found...!!!\n");
}
}
::LeaveCriticalSection(&g_queueCS);
}
printf("Search thread: Thread exiting.\n");
return 42;
}
int main(){
::InitializeCriticalSection(&g_queueCS);
initStringDynamicArray(&myFolders, 5);
initStringDynamicArray(&myFiles, 5);
pushString(&myFolders, rootPath);//Without this Line it won't search in the current folder
// Create a manual-reset event in a non-signaled state
g_NewFileItemEvent = ::CreateEvent(
NULL, // Default security attributes
TRUE, // Manual-reset event
FALSE, // Initial state is non-signaled
L"NewFileItemEvent" // Name of the event (optional)
);
//************************Folder thread
HANDLE hThreadFolder = ::CreateThread(NULL,0, FolderThread, NULL, 0 ,NULL);
::WaitForSingleObject(hThreadFolder, INFINITE);
// Array to store thread handles
HANDLE* threads = (HANDLE*)malloc(myFolders.size * sizeof(HANDLE));
if (!threads) {
wprintf(L"Failed to allocate memory for thread handles\n");
return 1;
}
//**************MULtiple threads to look for files in each folder discovered (One thread per folder)
// Loop through the data array and create a thread for each index
for (int i = 0; i < myFolders.size; i++) {
threads[i] = CreateThread(
NULL, // Default security attributes
0, // Default stack size
FileThread, // Thread function
myFolders.data[i], // Pass the string at index i
0, // Default creation flags
NULL // No thread ID needed
);
if (threads[i] == NULL) {
wprintf(L"Failed to create thread for index %d\n", i);
// Handle error (e.g., clean up and exit)
}
}
// Wait for all threads to complete
WaitForMultipleObjects(myFolders.size, threads, TRUE, INFINITE);
// ****************************Singe thread to Search for the File by file name
HANDLE hThreadSearch = ::CreateThread(NULL, 0, SearchThread, NULL, 0, NULL);
::WaitForSingleObject(hThreadSearch, INFINITE);
// Clean up thread handles
for (int i = 0; i < myFolders.size; i++) {
if (threads[i]) {
CloseHandle(threads[i]);
}
}
free(threads); // Free thread handles array
::CloseHandle(hThreadFolder);
::CloseHandle(hThreadSearch);
::DeleteCriticalSection(&g_queueCS);
freeStringDynamicArray(&myFolders);
freeStringDynamicArray(&myFiles);
return 0;
}