【问题标题】:return two values out of a remote thread (C, windows)从远程线程(C,windows)返回两个值
【发布时间】:2009-08-28 15:18:48
【问题描述】:

我目前有一个使用 CreateRemoteThread() 创建的线程。一切都很好。 完成后(或完成前的错误),线程返回我们定义的五个返回代码之一。

我遇到了问题,我还需要返回 GetLastError() 的结果。有没有办法返回两个值?

我使用 WaitForSingleObject() 然后 GetExitCodeThread() 来获取线程的退出值。

我需要两个值(而不是只返回 GetLastError)的原因是因为我需要知道错误发生在远程线程的哪个位置,并且由第一个值返回。

代码表示赞赏。

谢谢

【问题讨论】:

    标签: c multithreading window


    【解决方案1】:

    在启动线程之前,在堆上分配一个结构,为错误返回参数留出空间。通过 CreateThread 的 lpParameter 参数将其传递给线程。在终止之前,请在此处留下您的错误代码。

    然后只需记住结构在等待该线程的任何线程中的位置,并从中读取结果。

    例如:

    struct threadinfo {
        void *someArgument;
        DWORD error_code;
        int error_flag;
    };
    
    DWORD WINAPI threadproc(LPVOID arg) {
        struct threadinfo *ti = (struct threadinfo *)arg;
        // do things using ti->someArgument
        ti->error_code = GetLastError();
        ti->error_flag = 42;
        return 0; // return code ignored
    }
    
    void start_and_wait() {
        struct threadinfo *ti = (struct threadinfo *)malloc(sizeof(*ti));
        ti->someArgument = &something;
    
        HANDLE hThread = CreateThread(NULL, 0, threadproc, (LPVOID)ti, 0, NULL);
        WaitForSingleObject(hThread, INFINITE);
        CloseHandle(hThread);
    
        printf("Exit code %08x, flag %d\n", ti->error_code, ti->error_flag);
        free((void*)ti);
    }
    

    如果您正在与远程线程通信,一种选择可能是将句柄作为 lpParameter 传递给共享内存段。您可以通过DuplicateHandle 将句柄注入远程进程,然后启动线程。然后,线程可以在返回之前映射共享内存段(如果尚未映射),将其结果放入共享内存段,然后取消映射并关闭句柄。

    例如在远程进程中:

    DWORD WINAPI threadproc(LPVOID arg) {
        LPVOID shmem = MapViewOfFile((HANDLE)arg, FILE_MAP_ALL_ACCESS, 0, 0, 4096);
        struct threadinfo *ti = (struct threadinfo *)shmem;
    
        // do stuff
        ti->error_code = GetLastError();
        ti->error_flag = 42;
    
        UnmapViewOfFile(shmem);
        CloseHandle((HANDLE)arg);
        return 0;
    }
    

    而在调用过程中:

    HANDLE mapping = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 4096, NULL);
    LPVOID shmem = MapViewOfFile(mapping, FILE_MAP_ALL_ACCESS, 0, 0, 4096);
    struct threadinfo *ti = (struct threadinfo *)shmem;
    ti->someArgument = ...;
    
    HANDLE remote_handle;
    DuplicateHandle(GetCurrentProcess(), mapping, hRemoteProcess, &remote_handle, 0, FALSE, DUPLICATE_SAME_ACCESS);
    HANDLE hRemoteThread = CreateRemoteThread(hRemoteProcess, NULL, 0, startAddress, remote_handle, 0, NULL);
    
    WaitForSingleObject(hRemoteThread);
    printf("err %08x flag %d\n", ti->error_code, ti->error_flag);
    UnmapViewOfFile(shmem);
    CloseHandle(mapping);
    

    【讨论】:

    • 哦,我明白了。问题是我使用的是 CreateRemoteThread() 而不是 CreateThread。线程在另一个进程的上下文中运行,所以我认为我不能发送指向结构的指针
    • 啊,抱歉 - 没看到。该技术仍然可以使用共享内存 - 请参阅我更新的帖子了解详细信息。
    【解决方案2】:

    返回指向包含您需要的字段的结构的指针。

    【讨论】:

    • 这不适用于 64 位 - 线程返回码是 DWORD,而 DWORD 只有 32 位宽,所以它太小而无法容纳 64 位指针。
    • 啊。在这种情况下,请使用 bdonlan 的建议。
    【解决方案3】:

    一次返回两个值的经典且非常丑陋的方法是将 or 转换为更大的类型。

    例如,要返回两个 int,您可以将其中一个上移一个 int 中的位数,然后将 or 与另一个值一起移动。

    然后,您的调用代码必须将各个部分分开。

    当然,这仅用于紧急情况。

    【讨论】:

    • 这里没有紧急情况 - 如果错误代码使用 DWORD 的所有 32 位会发生什么?
    • 那你倒霉了。这是一个可怕的解决方案。我一生中遇到过几次紧急情况,但如果您居住的地方没有紧急情况,那么请务必不要使用它。 :-)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-06
    • 2012-02-27
    相关资源
    最近更新 更多