因此,使用Visual Studio 2008为Windows CE 6.0平台开发本地c++代码。考虑以下多线程应用程序:
#include "stdafx.h"
void IncrementCounter(int& counter)
{
if (++counter >= 1000)
{
counter = 0;
}
}
unsigned long ThreadFunction(void* arguments)
{
int threadCounter = 0;
while (true)
{
Sleep(20);
IncrementCounter(threadCounter);
}
return 0;
}
int _tmain(int argc, _TCHAR* argv[])
{
CreateThread(
NULL,
0,
(LPTHREAD_START_ROUTINE)ThreadFunction,
NULL,
0,
NULL
);
int mainCounter = 0;
while (true)
{
Sleep(20);
IncrementCounter(mainCounter);
}
return 0;
}
当我在我的Windows 7 dev. machine上构建它并从Visual Studio运行一个调试会话时,在counter = 0;
语句上有一个断点,执行最终会中断,两个线程将在"threads"调试窗口中显示。我可以使用双击或右键单击->"switch to Thread"在两个线程之间来回切换,并查看两个线程的调用堆栈和浏览源代码并检查符号(用于应用程序代码中的调用堆栈帧)。然而,当我做同样的Windows CE连接通过。ActiveSync/WMDC(已经尝试了我们的自定义CE 6.0硬件与内部操作系统和SDK,以及一个旧的Windows mobile 5.0 PDA与股票MS SDK)我可以看到一个调用堆栈和浏览源代码的线程,其中中断已经发生(当前执行点是在我的应用程序代码),但是我没有得到任何有用的其他线程,这是目前被阻塞在内核空间等待它的睡眠超时。
有谁知道是否有可能在Windows CE上更好地工作?我猜这可能与调试器不知道在哪里找到WinCE内核元素的.pdb符号文件有关,或者我是否需要运行调试操作系统?
Windows CE 6远程调试。当暂停程序描述相同的问题时,没有调用堆栈,但没有真正提供解决方案
感谢理查德可能是因为coredll.dll缺少pdb文件。如果您正在为您的设备创建映像,则可以访问此文件,否则恐怕它取决于平台。
你可以在这里发现这个问题被认为是由VS2005设计的,所以也许VS2008也是如此:
http://connect.microsoft.com/VisualStudio/feedback/details/190785/unable-to-debug-windows-mobile-application-that-is-in-a-system-call在下面的链接中,你可以找到一些使用平台构建器为"未运行的线程"查找调用堆栈的说明
https://distrinet.cs.kuleuven.be/projects/SEESCOA/internal/workpackages/workpackage6/Task6dot2/ESCE/classes/331.pdf由于我只使用vs2005,我无法确认它是否有任何帮助。
如果日志记录是不够的(正如你提供的SO链接中建议的那样),要找到一个线程的调用堆栈,就像你的例子一样,我建议使用GetThreadCallStack
函数。下面是一步一步的步骤:
1 -添加以下代码到您的项目:
typedef struct _CallSnapshotEx {
DWORD dwReturnAddr;
DWORD dwFramePtr;
DWORD dwCurProc;
DWORD dwParams[4];
} CallSnapshotEx;
#define STACKSNAP_EXTENDED_INFO 2
DWORD dwGUIThread;
void DumpGUIThreadCallStack() {
HINSTANCE hCore = LoadLibrary(_T("coredll.dll"));
typedef ULONG (*GETTHREADCALLSTACK)(HANDLE hThrd, ULONG dwMaxFrames, LPVOID lpFrames[], DWORD dwFlags,DWORD dwSkip);
GETTHREADCALLSTACK pGetThreadCallStack = (GETTHREADCALLSTACK)GetProcAddress(hCore, _T("GetThreadCallStack"));
if ( !pGetThreadCallStack )
return;
#define MAX_FRAMES 40
CallSnapshotEx lpFrames[MAX_FRAMES];
DWORD dwCnt = pGetThreadCallStack((HANDLE)dwGUIThread, MAX_FRAMES, (void**)lpFrames, STACKSNAP_EXTENDED_INFO, 0);
TCHAR szBuff[64];
for ( DWORD i = 0; i < dwCnt; ++i ) {
wsprintf(szBuff, L"[%d] %pn", i, lpFrames[i].dwReturnAddr);
OutputDebugString(szBuff);
}
}
它将在输出窗口调用帧返回地址中转储(示例输出在第3点)。
在WinMain中初始化dwGUIThread:
dwGUIThread = GetCurrentThreadId();
3 -在ThreadFunction
内部实际断点之前执行DumpGUIThreadCallStack();
。它将向输出窗口写入类似于这样的文本:
[0] 8C04D2C4
[1] 8C04D34C
[2] 40026D48
[3] 000111F4 <--- 1
[4] 00011BAC <--- 2
[5] 4003C2DC
1和2是您感兴趣的返回地址,您希望找到最接近它们的符号。
4 -在调试器内部切换到拆卸模式(右键单击源文件并选择"Go to disassembly")。在这种模式下,在窗口的顶部,你会看到Address:
线。您应该从输出窗口复制粘贴到它的地址,在我的情况下,000111F4将引导我到以下行:
while (true)
{
Sleep(20);
000111F0 mov r0, #0x14
000111F4 bl 0001193C // <--- 1
IncrementCounter(mainCounter);
给出你的GUI线程实际在做什么。
Visual Studio Debugger允许从直接窗口执行函数,但我无法调用DumpGUIThreadCallStack
,我总是得到'错误:不支持函数求值'。
为了找到最接近的帧返回地址符号,你也可以使用。map文件和。cod文件(/FAcs编译的源代码),在谷歌上有一些很好的教程。
上面的例子是在WCE6.0(最终用户)设备上使用VS 2005和标准SDK 5.0进行测试的。