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_ATTACH
和DLL_THREAD_ATTACH
调用它,同时添加“缺失”break
跨度>
【参考方案2】:
您了解 switch 语句的工作原理吗?如果你没有在 case 的末尾放一个 break,那么代码就会继续到下一个 case:
switch (3)
case 3:
cout << "3";
case 4:
cout << "4";
打印 3 和 4。
【讨论】:
以上是关于DllMain 内无中断的开关/外壳的主要内容,如果未能解决你的问题,请参考以下文章
用于打开外壳、在外壳中运行命令并保持外壳运行的 Bash 脚本