Search code examples
cwinapicreateprocess

How to write data into global variables from callback function?


According to windows API docs we can use global variable to pass data from creating thread to the new thread and I am assuming the opposite is also possible

Data can also be passed from the creating thread to the new thread using global variables.

Here is a data structure and a callback function, ptr is a pointer to heap allocated memory in main

typedef struct Output
{
    char *ptr;
    DWORD len;

}Output, *POutput;

Output out; // global variable 


DWORD grab_output(LPVOID args)
{ 
    DWORD dread;
    BOOL success = FALSE;
    while (1)
    {
        success = ReadFile(g_hChildStd_OUT_Rd,out.ptr, 1024, &dread, NULL);
        if (!success || dread == 0 ) break;
        out.ptr = realloc(out.ptr, out.len+1024);
        out.len += dread;
    }   
}


int run()
{
    BOOL res; 
    STARTUPINFO si;
    PROCESS_INFORMATION pi;
    SECURITY_ATTRIBUTES sa;
    DWORD   dwThreadIdArray[1];


    
    DWORD n_size; 
    memset(&si, 0 ,sizeof(si));
    memset(&pi, 0, sizeof(pi));
    memset(&sa, 0, sizeof(sa));
    sa.nLength = sizeof(SECURITY_ATTRIBUTES);
    sa.bInheritHandle = TRUE;
    sa.lpSecurityDescriptor = NULL;

    if (!CreatePipe(&g_hChildStd_OUT_Rd, &g_hChildStd_OUT_Wr, &sa, 0)) 
        return GetLastError();
    
    if (!SetHandleInformation(g_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0))
        return GetLastError();

    si.cb = sizeof(STARTUPINFOA);
    si.hStdError = g_hChildStd_OUT_Wr;
    si.hStdOutput = g_hChildStd_OUT_Wr; 
    si.dwFlags |= STARTF_USESTDHANDLES;

    if(!CreateProcess(NULL,
                        "C:\\Windows\\System32\\cmd.exe /c dir",
                        NULL,
                        NULL,               
                        TRUE,               
                        CREATE_NEW_CONSOLE,   
                        NULL,                
                        NULL,                                      
                        &si,                
                        &pi                 
                        ))
                        {
    }
    else
    {
        
        handle = CreateThread(0, 0, grab_output, NULL, 0, NULL);
    }
    return 0;
}


int main()
{
    out.ptr = malloc(1024);
    out.len = 0;
    run();
    printf("%s\n", out.ptr);

}

when running the code out.ptr returns garbage values

gcc example.c && ./a.exe 
└e╔┐═☺

for the sake of this question assume that I will be running a single thread at any given time


Solution

  • The reason this prints garbage values is you assumed for no clear reason that the thread finishes before you accessed the global variable.

    There's too many unchecked fault points. Right now, check every function that can error for an error return and produce output in that case, and also set a flag in another global variable. Really, you shouldn't have to, but better to much than not enough. Then close the process and thread handles you aren't using.

    Now we should be able to discuss synchronization.

    It looks like you want to grab all of the output at once. Thus WaitForSingleObject() on your own thread handle. To produce output incrementally, you need to track input highwater and output highwater and output only the characters in between with putc().

    Don't forget to null-terminate your string either, or printf() won't be happy.