RETAILMSG 的定义与实现&Windows CE 6.0下dpCurSettings编译出错及解决办法

 

 

今天在编译6410的镜像文件的时候,突然报错:

BUILD: [01:0000004569:ERRORE] iic_mdd.obj : error LNK2001: unresolved external symbol dpCurSettings
BUILD: [01:0000004570:ERRORE] D:/WINCE600/platform/SMDK6410/target/ARMV4I/debug/s3c6410_iic.dll : fatal error LNK1120: 1 unresolved externals
BUILD: [01:0000004571:INFO  ]     editbin /nxcompat D:/WINCE600/platform/SMDK6410/target/ARMV4I/debug/s3c6410_iic.dll

BUILD: [01:0000004572:INFO  ] Microsoft (R) COFF/PE Editor Version 8.00.50727.42
BUILD: [01:0000004573:INFO  ] Copyright (C) Microsoft Corporation.  All rights reserved.
BUILD: [01:0000004574:INFO  ] 
BUILD: [01:0000004575:INFO  ] EDITBIN : fatal error LNK1104: cannot open file 'D:/WINCE600/platform/SMDK6410/target/ARMV4I/debug/s3c6410_iic.dll' 

什么原因?难道我的BSP被我修改了太多次,或者无意中修改了什么文件?可是我没有动过IIC下的代码呀?最怕就是我修改了环境变量就惨了...抱着一颗尝试的心,我又换了之前备份的SMDK6410的BSP包,可是编译的结果一样!错误仍然在继续?怎么解决?

先按照 字面意思找到IIC下面的的所有代码,搜索dpCurSettings,但是居然没有这个变量,费解...还准备找到相应代码,external一下呢,看样子这个方法不靠谱了。

继续在整个WINCE600下面搜索,结果出现一堆,按照时间先后顺序排列一下,还是有几十个(这几十个只是涉及SMDK6410的,还有PUBLIC下面的许多未计算在内)... 看了两个,惰性来了,准备到CSDN论坛上发帖求助,刚打好了两个字,算了还是先GOOGLE吧,结果出现几个帖子,原来还是有朋友和我遇见类似的问题,按照hzdysymbol兄的帮忙,解决了这个问题。

原话是这样的:你编译的是Debug版的,换成Release就应该可以解决这个问题. 试试吧

很稳!感谢 hzdysymbol!这个问题已经解决!

探求 dpCurSettings到底是个啥子?

找到唐勉老师的博客:http://space.itpub.net/16912323/viewspace-509778,引用如下:

 

在WinCE的开发环境中支持Debug Zones功能,通常也被称为调试域,通过它可以控制打印信息。当某个调试域被打开以后, 在这个域中的打印信息就会被打印出来,如果某个调试域被关闭了,那么这个域中的打印信息就会被关闭。调试域是基于模块的,也就是说一个模块,可能是在一个 驱动或者一个应用中都可以定义一个调试域,用来调试该模块。一个调试域最多可以包括16个域,一般在每一个模块中都会有一个全局变量dpCurSettings,该变量用于描述调试域的相关信 息,它由一个模块名字,16个域的名字和一个掩码组成。下面具个 例子:

DBGPARAM dpCurSettings =

{
    TEXT("PCIBUS"), {
    TEXT("Errors"),TEXT("Warnings"),TEXT("Functions"),TEXT("Initialization"),
    TEXT("Enumeration"),TEXT("Load Order"),TEXT("Resource"),TEXT("Undefined"),
    TEXT("Undefined"),TEXT("Undefined"),TEXT("Undefined"),TEXT("Undefined"),
    TEXT("Undefined"),TEXT("Undefined"),TEXT("Undefined"),TEXT("Undefined") },
    0x20

};

先来解释一下DBGPARAM结构,该结构在Dbgapi.h中定义,所以在定义dpCurSettings的时候还需要包含这个头文件,该结 构定义如下:

typedef struct _DBGPARAM {

    WCHAR  lpszName[32];                    //模块的名字

    WCHAR  rglpszZones[16][32];            //调试域的名字

    ULONG  ulZoneMask;                        //调试域的掩码

}DBGPARAM, *LPDBGPARAM;

 

在上面的例子中可以看到,第一个是模 块的名字,叫PCIBUS。而后定义了16个域的名字,其中只用到了7个域,剩下的都定义为Undefined了。最后一个数字为域的掩码,表示当前哪个域是被激活的,0x20表示只有第6个域是被激活的。从上面的例子还可以 看出,前7个域是有意义的,而且按照顺序分别对 应1到7。下面针对这些域需要定义相应Debug调试的宏定义:

#define DBGZONE_ERROR                           1

#define DBGZONE_WARNING                     2

#define DBGZONE_FUNCTION                    3

#define DBGZONE_INIT                                4

#define DBGZONE_ENUM                            5

#define DBGZONE_LOADORDER                6

#define DBGZONE_RESOURCE                    7

 

上述宏定义对应在dpCurSettings中的7个域,然后就可以在打印信息的时候,通过这些宏定义来对应相应的调试域了。例如:

  1. while(1)
  2. {
  3.     if (dwFlag)
  4.     {
  5.          DEBUGMSG(DBGZONE_ERROR, (L"Error found: %d/r/n", NumDevKeys));
  6.          break;
  7.      }
  8.      else
  9.      {
  10.          DEBUGMSG(DBGZONE_WARNING, (L"Warning found/r/n"));
  11.      }
  12.      DEBUGMSG(DBGZONE_LOADORDER, (L"load in a while loop/r/n"));
  13.      Sleep(100);
  14. }
  15.  

从这段代码可以看出,如果dpCurSettings中的掩码定义为0x20,那么在DEBUGMSG的打印中,只有条件为DBGZONE_LOADORDER才会被打印,循环中的前两个打印信息 是不会被打印的。如果想让上面的代码中的所有DEBUGMSG都能打印必须设置掩码如下:

dpCurSettings.ulZoneMask = DBGZONE_ERROR | DBGZONE_WARNING | DBGZONE_LOADORDER;

 

 

在一个模块中定义了调试域,如果想 在系统中去使用还必须注册该调试域,需要用到的函数叫DEBUGREGISTER(..),其中要把该调试模块的句柄作为参 数传给它。例如:

DllMain(..)

{

    switch(op)

    {

        case DLL_PROCESS_ATTACH:

            DEBUGREGISTER(hPCIBUS);

            break;

        ….

    }

}

完成了上述工作以后,就可以重新编译调试的模块,然后运行系统来调试了。调试域的一个好处就是在Debug的过程中,不需要终止系统可以动态 的改变调试域,方便我们分析问题。首先,我们可以基于Platform. Builder中的CE Debug Zones来调试,在VS2005的菜单中选

择Target,然后选择CE Debug Zones

 

 

然后会出现一个Debug Zones的窗口,在窗口弹出以后,它可能会花 一点时间来收集当前支持Debug Zone的模块

该图只是一个例子,左边显示了可调试 的模块,选择serial_SMDK2410.dll这个模块,就是S3C2410的串口驱动模块。在右侧可以看到各 个调试域及名字,用户可以根据需要来选择打开和关闭相应的调试域,最后点击Apply和OK就可以了。

 

当然,还有其他的方法来修改调试域, 一种方法是使用Target Control中的zo命令来修改,Target Control将在以后介绍。还有一种方法就是通过SetDbgZone(..)函数来修改。定义如下:

BOOL SetDbgZone(DWORDdwProcid, LPVOIDlpvMod, LPVOIDbaseptr, DWORDzone, LPDBGPARAMlpdbgTgt)

    dwProcid:    进程的句柄

    lpvMod:        调试模块的句柄

    baseptr:        设置为NULL

    zone:            新的调试域掩码

    lpdbgTgt:      返回新的DBGPARAM结构

 

上面对Debug Zone的定义,使用以及调试作了大致的介绍,按 照上面的步骤可以给一个模块添加调试域,注册调试域并在系统运行以后随时更改调试域,其根本目的无非是帮助我们来调试模块和分析问题。一般情况下,调试域 只在Debug模式下使用,但是也可以在Release模式下使用。但是有些地方需要修改,首先前面已经介绍过Debug模式下的打印用DEBUGMSG,而Release模式下的打印应该使用RETAILMSG函数。所以在Release模式下,打印函数应该改为RETAILMSG函数。还有在注册调试域的时候,不能再使 用DEBUGREGISTER(..)函数,而是应该改用RETAILREGISTERZONES(..)函数。

 

 

 

PUBLIC下面,很多地方是用不了RETAILMSG来打印信息,因为它取而代之的是DEBUGMSG,但是,如果我们不编译debug版本的话,这个打印函数又是不起作用的。如果想用使用RETAILMSG,就得自已定义了。例如在GPE里面,就没有对RETAILMSG的支持。我们可以自已定义

#include <windows.h>   //需要包含这两个头文件

#include <blcommon.h>

#undef RETAILMSG  //取消先前定义RETAILMSG,避免其他地方以定义了引起冲突

 #define RETAILMSG(cond,printf_exp)      ((cond)?(NKDbgPrintfW printf_exp),1:0)

 

当然,我们也可以定义自已命明的串口输出函数,如把RETAILMSG 命名为aulypMSG,呵呵。

 

本文来自作者:赖玉平(auly)aulyp@163.com博客:http://blog.csdn.net/ok138ok/archive/2009/07/25/4380273.aspx

 

©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页