【问题标题】:Switch/case without break inside DllMainDllMain 内无中断的开关/外壳
【发布时间】: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 无法工作。

怎么会这样?

【问题讨论】:

    标签: c dll winapi switch-statement


    【解决方案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。

    【讨论】:

      猜你喜欢
      • 2017-04-21
      • 1970-01-01
      • 2010-12-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多