DllMain 内无中断的开关/外壳

Posted

技术标签:

【中文标题】DllMain 内无中断的开关/外壳【英文标题】:Switch/case without break inside DllMain 【发布时间】:2010-03-08 19:50:27 【问题描述】:

我有一个 Dllmain,当线程附加到此 DLL 时,它会分配线程本地存储。代码如下:

BOOL APIENTRY DllMain(HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved)

    LPVOID lpvData; 
    BOOL fIgnore; 

    switch (ul_reason_for_call)
    
    case DLL_PROCESS_ATTACH:
        onProcessAttachDLL();
        // Allocate a TLS index.
        if ((dwTlsIndex = TlsAlloc()) == TLS_OUT_OF_INDEXES) 
            return FALSE; 
        // how can it jump to next case???
    case DLL_THREAD_ATTACH:
        // Initialize the TLS index for this thread.
        lpvData = (LPVOID) LocalAlloc(LPTR, MAX_BUFFER_SIZE); 
        if (lpvData != NULL) 
            fIgnore = TlsSetValue(dwTlsIndex, lpvData);  
        break; 
    ...

我知道根据 Microsoft 文档,对于主线程,没有输入 DLL_THREAD_ATTACH。但是,上面的代码有效。我正在使用VC2005。当我进入调试器时,我看到它进入 DLL_THREAD_ATTACH 后,当 ul_reason_for_call = 1!怎么会这样?如果我在 DLL_PROCESS_ATTACH 块的末尾添加“break”,则 DLL 无法工作。

怎么会这样?

【问题讨论】:

【参考方案1】:

如果我理解正确,您想知道为什么在进入 DLL_PROCESS_ATTACH 案例后,在 DLL_THREAD_ATTACH 案例上继续执行,而不是在 switch 结束后继续执行。

这种行为称为“失败”,它是标准 C。如果没有显式的 break 语句,将继续执行下一个 case

当然,对于第一次看到它的程序员来说,它是相当违反直觉的,因此它经常会引起误解甚至是错误(您可能并不总是知道break 是故意遗漏的,还是被错误遗漏的) .因此,在使用此构造时,用注释明确地标记它被认为是一种很好的做法,例如:

switch (ul_reason_for_call)

case DLL_PROCESS_ATTACH:
    onProcessAttachDLL();
    // Allocate a TLS index.
    if ((dwTlsIndex = TlsAlloc()) == TLS_OUT_OF_INDEXES) 
        return FALSE; 
    // fall through
case DLL_THREAD_ATTACH:
    // Initialize the TLS index for this thread.
    lpvData = (LPVOID) LocalAlloc(LPTR, MAX_BUFFER_SIZE); 
    if (lpvData != NULL) 
        fIgnore = TlsSetValue(dwTlsIndex, lpvData);  
    break; 
...

【讨论】:

谢谢。尽管我有多年的 C/C++ 经验,但我从未编写过这样的结构。我总是在每个分支或多个案例中放置中断(共享相同的代码块)。一开始我觉得很奇怪。 @Sherwood Hu - 是的,乍一看很奇怪 :-) 我意识到我的措辞可能会让你觉得有辱人格,所以我改写了它。既然您的问题得到了令人满意的答案,我可以要求您按照 SO 约定接受它吗?谢谢。 一个更好的做法是将DLL_THREAD_ATTACH代码放在它自己的函数中,并从DLL_PROCESS_ATTACHDLL_THREAD_ATTACH调用它,同时添加“缺失”break跨度> 【参考方案2】:

您了解 switch 语句的工作原理吗?如果你没有在 case 的末尾放一个 break,那么代码就会继续到下一个 case:

switch (3)

case 3:
   cout << "3";
case 4:
   cout << "4";

打印 3 和 4。

【讨论】:

以上是关于DllMain 内无中断的开关/外壳的主要内容,如果未能解决你的问题,请参考以下文章

钢筋外壳 - 传递配置文件

智能除味器——外壳结构部分设计(3D打印)

用于打开外壳、在外壳中运行命令并保持外壳运行的 Bash 脚本

请问要用MOS制作一个H桥开关电源,要求能够输出8V的电压和2A的电流,为啥用下面电路只能得到2V电压

文件外壳是啥

作业感知外壳与作业不感知外壳执行程序