Windows错误码编码问题

SDK错误码编码问题


一、Windows错误码编码规则
Windows错误码编码规则见下图,可以看出,我们在第29位设置为1,便可以编码我们自己的错误码。参考Windows错误码编码规则并结合实际情况编码SDK自己的错误码。
参考Windows核心编程,第一章表1-2。
二、现状分析
1、项目XXX错误码已经到999999(0x F423F);
 
2、流媒体错误码存在负数错误码;
 
3、存在多种模块:SDK1、SDK2、SDK3等库。
三、应对方法
鉴于如上问题,我们需要适当修改Windows编码规则:
1、扩展异常代码值到20位(1048575),以便容纳ANPR错误码;
2、错误码存在负数,我们可以编码第28位保留字段,即1:负数、0:正数;
3、经过步骤1的修改,设备代码只剩8位可用,即只能容纳256种设备类型(模块类型),目前来看已经够用。故问题3解决。
四、实施
1、新增接口uint GetLastErrorEx();
2、新增接口void DecodeError(const unsigned int uEncodeError, byte& uModuleType, int& iErrorCode, unsigned int& uWindowsErrorCode);具体实现参见CodecError.h;
3、定义设备代码,定义好后不可修改;
//模块类型
enum ERROR_MODULE_TYPE
{
ERROR_MODULE_TYPE_WINDOWS = 0, //Windows错误码直接使用系统默认的错误码,不需要进行编码,即不符合我们的错误码编码扩展协议
ERROR_MODULE_TYPE_SDK1 = 1, //SDK1
ERROR_MODULE_TYPE_SDK2 = 2, //SDK2
};


4、编解码
编解码测试结果:
 
编解码代码:
//CodecError.h
#ifndef _CODEC_ERROR_H_
#define _CODEC_ERROR_H_


#include


namespace CodecError
{
enum ERROR_MODULE_TYPE
{
ERROR_MODULE_TYPE_WINDOWS = 0, //Windows错误码直接使用系统默认的错误码,不需要进行编码,即不符合我们的错误码编码扩展协议
ERROR_MODULE_TYPE_SDK1 = 1, //SDK1
ERROR_MODULE_TYPE_SDK2 = 2, //SDK2
};


//严重等级
enum ErrorLevel
{
Success = 0, //成功
FYI  = 1, //供参考
Warning = 2, //警告
Error = 3 //错误,编码时默认类型
};


//模块类型最小值
const unsigned int MinModuleType = 0;
//模块类型最大值
const unsigned int MaxModuleType = (((unsigned int)1 << 8) - 1); //255


//错误最大值,非Windows错误码
const int MaxErrorCode = (((unsigned int)1 << 20) - 1); //1048575
//错误码最小值,非Windows错误码
const int MinErrorCode = -MaxErrorCode; //-1048575

/** @fn int EncodeError
* @brief <编码错误码>
* @param byModuleType 错误码所属模块类型,参见:MODULE_TYPE
* @param iErrorCode 模块不为Windows时有效
*   @param uWindowsErrorCode 模块为Windows时有效
* @return <编码后错误码>
*/
unsigned int EncodeError(const byte byModuleType, const int iErrorCode, const unsigned int uWindowsErrorCode)
{
unsigned int uEncodeError = 0;


if(byModuleType == ERROR_MODULE_TYPE_WINDOWS) //Windows错误码直接返回
{
return uWindowsErrorCode;
}


if(!(byModuleType >= MinModuleType && byModuleType <= MaxModuleType)
&& (iErrorCode >= MinErrorCode && iErrorCode <= MaxErrorCode))
{
return uEncodeError; //需要调用者保证入参的正确性
}




{
uEncodeError = ((unsigned int)3 << 30); //写死严重等级为,即错误


uEncodeError += ((unsigned int)1 << 29);


uEncodeError += (iErrorCode >= 0) ?  0 : (1 << 28);


uEncodeError += ((unsigned int)byModuleType << 20);


uEncodeError += abs(iErrorCode);
}


return uEncodeError;
}



/** @fn int DecodeError
* @brief <解码错误码>
* @param uEncodeError 编码后错误码
* @param uModuleType  错误码所属模块类型,参见:MODULE_TYPE
* @param iErrorCode 模块不为Windows时有效
* @param uWindowsErrorCode 模块为Windows时有效
* @return <无>
*/
void DecodeError(const unsigned int uEncodeError, byte& uModuleType, int& iErrorCode, unsigned int& uWindowsErrorCode)
{
iErrorCode = 0;
uWindowsErrorCode = 0;


uModuleType = (uEncodeError >> 20) & ((unsigned int)0xFF);


if(uModuleType != ERROR_MODULE_TYPE_WINDOWS) //Client
{
iErrorCode = (uEncodeError & ((unsigned int)0xFFFFF));


if(((uEncodeError >> 28) & ((unsigned int)0x1)) == 1)
{
iErrorCode = -iErrorCode;
}
}
else //Windows
{
uWindowsErrorCode = uEncodeError; //Windows错误码原样返回
}
}
}
五、优缺点
1、优点
对各个模块的错误码进行编码,一旦SDK发生错误,可以依据错误码唯一定位到某一指定模块和具体的错误码,方便问题排查定位,同时也避免了错误码混乱问题。
2、缺点
需要对每一个错误码进行编码操作,其次,用户需要多调用一个解码接口,解码出模块类型和错误号,才能到对应模块错误码表查找该错误码表示的意思。


六、其他方案
本方案可以解决出现的问题,但过于麻烦,错误码不够直观,用户需要额外的调用解码接口。鉴于此,可以考虑修改接口,直接给用户返回错误码模块类型和错误码。具体实施可以根据项目实际情况进行选择使用。

你可能感兴趣的:(C++)