因此,使用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开发上运行时。使用counter = 0;
语句上的断点从Visual Studio运行并运行调试会话,执行最终会中断,并且“Threads”调试窗口中将显示两个线程。我可以使用双击或右键单击>“切换到线程”在两个线程之间来回切换,然后查看调用堆栈并浏览源代码并检查符号(对于我的应用程序代码中的调用堆栈帧)两个线程。但是,当我在Windows CE连接通过时也这样做。 ActiveSync / WMDC(已经尝试了我们的自定义CE 6.0硬件与内部操作系统和SDK,以及旧的Windows移动5.0 PDA与库存MS SDK)我可以看到一个调用堆栈和浏览源的线程,其中已经发生了中断(当前执行点在我的应用程序代码中),但是我没有对其他线程有任何用处,其他线程当前在内核空间中被阻塞,等待它的睡眠超时。
任何人都知道是否有可能在Windows CE上更好地工作?我猜这可能与调试器有关,不知道在哪里找到WinCE内核元素的.pdb符号文件,或者我是否需要运行调试操作系统?
Windows CE 6 remote debugging. No call stack when pause program描述了同样的问题,但并没有真正提供解决方案
感谢
理查德
答案 0 :(得分:0)
可能是因为缺少coredll.dll的pdb文件。如果您要为您的设备创建图像,您将可以访问此文件,否则我担心它的平台依赖。
你可以在这里找到这个问题在VS2005中被认为是设计的,所以对于VS2008可能是相同的:
在以下链接中,您可以找到一些使用平台构建器查找调用堆栈的说明"未运行的线程"
由于我只使用VS 2005,我无法确认它是否有任何帮助。
如果日志记录不充分(如您提供的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] %p\n", i, lpFrames[i].dwReturnAddr);
OutputDebugString(szBuff);
}
}
它将在Output窗口中转储调用帧返回地址(示例输出在第3点)。
2 - 在WinMain中初始化dwGUIThread:
dwGUIThread = GetCurrentThreadId();
3 - 在DumpGUIThreadCallStack();
内执行断点之前执行ThreadFunction
。它将写入输出窗口文本,类似于:
[0] 8C04D2C4
[1] 8C04D34C
[2] 40026D48
[3] 000111F4 <--- 1
[4] 00011BAC <--- 2
[5] 4003C2DC
1和2是您感兴趣的返回地址,并且您希望找到最接近它们的符号。
4 - 在调试器内部切换到反汇编模式(右键单击源文件并选择&#39;转到反汇编&#39;)。在窗口顶部的此模式下,您将看到Address:
行。你应该从输出窗口复制粘贴到它的地址,在我的情况下,000111F4将引导我到以下行:
while (true)
{
Sleep(20);
000111F0 mov r0, #0x14
000111F4 bl 0001193C // <--- 1
IncrementCounter(mainCounter);
它为您提供了GUI线程实际执行的操作。
Visual Studio Debugger允许从即时窗口执行功能,但我无法调用DumpGUIThreadCallStack
,我总是得到错误:不支持功能评估&#39;。
要查找帧返回地址的最近符号,您还可以将.map文件与.cod文件(/ FAcs编译源)一起使用,谷歌上有一些很好的教程。
以上示例在WCE6.0(最终用户)设备上使用VS 2005和Standard SDK 5.0进行了测试。