首页 > 解决方案 > 如何在 C 中执行 DLL 中的线程

问题描述

我创建了一个运行 3 个工作线程的 DLL,主线程处于循环中等待线程完成。线程被创建,但没有执行线程。

我尝试在使用 CreateThread() 创建的函数内设置 MessageBox 函数,但该框没有出现。我也尝试过调试,并且 CreateThread() 的返回值是有效的,所以线程被创建了。

BOOL WINAPI DllMain() {
   main();
   return 1;
}

int main() {
    HANDLE h1, h2, h3;

    h1 = CreateThread(first)...
    h2 = CreateThread(second)...
    h3 = CreateThread(third)...

   WaitForSingleObject(h3, INFINITE);
   return 1;
}

first() {
    MessageBoxA("print some stuff");
    return;
}

我已经包含了一些关于我的布局的伪代码。由于它的敏感性,我无法提供真实的代码。然而,这就是正在发生的事情。我在另一个加载此 .DLL 的项目中使用 LoadLibrary。DLL 被加载并执行 DllMain。然后它调用我的 main 函数来创建 3 个线程。每个线程都被创建。但是线程内部的内容不会执行。

编辑:

// dllmain.cpp : Defines the entry point for the DLL application.
#include <Windows.h>

void mb() {
    MessageBoxW(0, L"AAAAAAAAAAAAAAAAAAAAAAAAA", L"AAAAAAAAAAAAAAAAAAAAAAa", 1);
}

void create() {
    HANDLE han;
    DWORD threadId;
    han = CreateThread(NULL, 0, mb, NULL, 0, &threadId);
    han = CreateThread(NULL, 0, mb, NULL, 0, &threadId);
    han = CreateThread(NULL, 0, mb, NULL, 0, &threadId);

}

BOOL APIENTRY DllMain() {
    create();
    return 1;
}

标签: cwindowsdll

解决方案


因为在一般情况下 DLL 可以被卸载,需要添加对 DLL 的引用 - 因为它不会被卸载,直到线程使用它执行代码。这可以通过调用来完成GetModuleHandleEx-除非指定,否则会增加模块的引用计数。GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT当线程退出时——我们通过调用取消引用 DLL 代码FreeLibraryAndExitThread。在大多数情况下不需要等待所有线程退出。所以代码,里面的dll可以是下一个

ULONG WINAPI DemoThread(void*)
{
    MessageBoxW(0, L"text", L"caption", MB_OK);
    // dereference dlll and exit thread
    FreeLibraryAndExitThread((HMODULE)&__ImageBase, 0);
}

void someFnInDll()
{
    HMODULE hmod;
    // add reference to dll, because thread will be use it
    if (GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (PCWSTR)&__ImageBase, &hmod))
    {
        if (HANDLE hThread = CreateThread(0, 0, DemoThread, 0, 0, 0))
        {
            CloseHandle(hThread);
        }
        else
        {
            // dereference dll if thread create fail
            FreeLibrary(hmod);
        }
    }
}

wait inside dll 入口点是错误的,因为我们在这里持有进程范围的临界区。如果我们等待线程退出——这个等待总是死锁——线程在退出(并开始)之前尝试进入这个临界区,但不能因为我们在这里等他。所以我们持有临界区并等待线程,但是当我们退出这个临界区时线程会等待。僵局


推荐阅读