//EXAMPLES SOLVED//

//CREATE A THREAD//

#include <stdio.h>
#include <Windows.h>

void threadFunction(LPVOID param) {
    DWORD threadId = GetCurrentThreadId();
    int *realParam = (int *) param;

    printf("Secondary thread: %d\n", threadId);
    Sleep(2000);
    printf("Received value: %d\n", *realParam);
}

int main(int argc, char *argv[]) {
    DWORD threadId;
    HANDLE threadHandle;

    DWORD mainThreadId = GetCurrentThreadId();
    DWORD processId = GetCurrentProcessId();
    printf("PID: %d, primary thread: %d\n", processId, mainThreadId);

    int param = 1234;

    DWORD waitResult;

    threadHandle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) threadFunction, (LPVOID) &param, 0, (LPDWORD) &threadId);

    // Sleep(1000);
    waitResult = WaitForSingleObject(threadHandle, INFINITE);
    if (waitResult == WAIT_OBJECT_0) {
        printf("Thread signaled or finished\n");
    } else if (waitResult == WAIT_TIMEOUT) {
        printf("Timeout\n");
    } else {
        printf("Something else happened");
    }

    CloseHandle(threadHandle);

    return 0;
}


//CREATE A THREAD VERBOSE //

#include <stdio.h>
#include <Windows.h>

void threadFunction(LPVOID param) {
    DWORD currentProcessId = GetCurrentProcessId();
    DWORD currentThreadId = GetCurrentThreadId();
    int *realParam = (int *) param;  // We expect an integer pointer as parameter.

    printf("[SECONDARY THREAD] Process ID: %d\n", currentProcessId);
    printf("[SECONDARY THREAD] Thread ID: %d\n", currentThreadId);

    printf("[SECONDARY THREAD] Received value: %d\n", *realParam);
    (*realParam)++;
    printf("[SECONDARY THREAD] New value: %d\n", *realParam);

    printf("[SECONDARY THREAD] Waiting 2 seconds before finishing\n");
    Sleep(2000);
}

int main(int argc, char *argv[]) {
    DWORD currentProcessId = GetCurrentProcessId();
    DWORD currentThreadId = GetCurrentThreadId();

    HANDLE threadHandle;
    DWORD threadId;

    DWORD waitResult;

    int param;
    
    if (argc != 2) {
        printf("ERROR: Wrong number of parameters\n");
        return 1;
    }
    param = atoi(argv[1]);

    printf("[PRIMARY THREAD] Process ID: %d\n", currentProcessId);
    printf("[PRIMARY THREAD] Thread ID: %d\n", currentThreadId);

    threadHandle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) threadFunction, (LPVOID) &param, 0, (LPDWORD) &threadId);
    printf("[PRIMARY THREAD] Created a secondary thread with ID: %d\n", threadId);

    printf("[PRIMARY THREAD] Value of param: %d\n", param);
    printf("[PRIMARY THREAD] Waiting for secondary thread to finish\n");
    waitResult = WaitForSingleObject(threadHandle, INFINITE);
    if (waitResult == WAIT_OBJECT_0) {
        printf("[PRIMARY THREAD] Secondary thread signaled or finished\n");
    } else if (waitResult == WAIT_TIMEOUT) {
        printf("[PRIMARY THREAD] Wait operation timed out\n");
    } else {
        printf("[PRIMARY THREAD] Something else happened");
    }

    printf("[PRIMARY THREAD] Value of param: %d\n", param);

    CloseHandle(threadHandle);

    return 0;
}

//CREATE PROCESS//

#include <stdio.h>
#include <Windows.h>

int main(int argc, char *argv[]) {
    STARTUPINFO si;
    PROCESS_INFORMATION pi;
    char cmd[256] = ".\\ex1.exe";  // Command line with executable and parameters.

    DWORD currentProcessId = GetCurrentProcessId();
    DWORD currentThreadId = GetCurrentThreadId();

    DWORD waitResult;

    memset(&si, 0, sizeof(si));
    memset(&pi, 0, sizeof(pi));

    printf("[PRIMARY THREAD] Process ID: %d\n", currentProcessId);
    printf("[PRIMARY THREAD] Thread ID: %d\n", currentThreadId);

    if (!CreateProcess(NULL,
                       cmd,
                       NULL,
                       NULL,
                       FALSE,
                       0,
                       NULL,
                       NULL,
                       &si,
                       &pi)) {
        fprintf(stderr, "Process could not be created\n");
        return 1;
    }
    
    printf("[PRIMARY THREAD] Waiting for the other process to finish\n");
    waitResult = WaitForSingleObject(pi.hProcess, INFINITE);
    if (waitResult == WAIT_OBJECT_0) {
        printf("[PRIMARY THREAD] Secondary thread signaled or finished\n");
    } else if (waitResult == WAIT_TIMEOUT) {
        printf("[PRIMARY THREAD] Wait operation timed out\n");
    } else {
        printf("[PRIMARY THREAD] Something else happened");
    }

    CloseHandle(pi.hThread);
    CloseHandle(pi.hProcess);

    return 0;
}