wince串口打印函数是如何实现的?(作者wogoyixikexie@gliet)
来源:互联网 发布:关于信息技术的软件 编辑:程序博客网 时间:2024/06/05 09:05
wince串口打印函数是如何实现的?(作者wogoyixikexie@gliet)
通常我们在BSP下一般使用RETAILMSG这个函数来实现串口打印,某些驱动也用DEBUGMSG。 在OAL又是另外一些串口打印函数。我们很早就知道这是OAL之下的debug.c的串口函数实现的,但是具体是怎么实现的,我从来没有去看过。今天碰到在串口MDD层无法使用串口打印的情况,搞得我很郁闷。就下决心找出来到底是怎么回事。
C:/WINCE500/PUBLIC/COMMON/SDK/INC中的dbgapi.h实现了RETAILMSG和DEBUGMSG,下面来看看到底是怎么回事。
Module Name: dbgapi.h
Purpose: Debug Message and Zone APIs.
--*/
#ifndef __DBGAPI_H__
#define __DBGAPI_H__
#ifdef __cplusplus
extern "C" {
#endif
void WINAPIV NKDbgPrintfW(LPCWSTR lpszFmt, );
void WINAPI WriteDebugLED(WORD wIndex, DWORD dwPattern);
/*
@doc EXTERNAL KERNEL
@struct DBGPARAM | Debug zone information structure
@comm The name of the module is used to look for zone initialization
information in the host PC registry. Zone names are displayed by
the control app (eg shell) which allows the user to dynamically
set zones.
@xref <f DEBUGREGISTER>
*/
typedef struct _DBGPARAM {
WCHAR lpszName[32]; // @field Name of module
WCHAR rglpszZones[16][32]; // @field names of zones for first 16 bits
ULONG ulZoneMask; // @field Current zone Mask
} DBGPARAM, *LPDBGPARAM;
BOOL RegisterDbgZones(HMODULE hMod, LPDBGPARAM lpdbgparam);
/*
@func BOOL | DEBUGZONE | Associates a mask bit with a zone
@parm int | bitnum | Bitnumber being defined
@rdesc A boolean which is TRUE if bitnum in '1' else is FALSE
@ex Example of use is |
// associate bit 0 with an info zone
#define ZONE_INFO DEBUGZONE(0)
// we can now use ZONE_INFO as a boolean for anything.
// We'd typically use it in a DEBUGMSG
*/
#define DEBUGZONE(n) (dpCurSettings.ulZoneMask&(0x00000001<<(n)))
#ifdef DEBUG
#ifdef SHIP_BUILD
#undef SHIP_BUILD
#pragma message (__FILE__ ":WARNING: SHIP_BUILD turned off since DEBUG defined")
#endif
#endif
#ifdef SHIP_BUILD //如果定义了SHIP_BUILD 那么以下串口打印函数就不会打印了。这个貌似可以使用环境变量设定。
#define ERRORMSG(cond,printf_exp) ((void)0)
#define RETAILMSG(cond,printf_exp) ((void)0)
#define DEBUGMSG(cond,printf_exp) ((void)0)
#define DEBUGLED(cond,parms) ((void)0)
#define DBGCHK(module,exp) ((void)0)
#define DEBUGCHK(exp) ((void)0)
#define DEBUGREGISTER(hMod) ((void)0)
#define RETAILREGISTERZONES(hMod) ((void)0)
#else // SHIP_BUILD
#ifdef DEBUG //debug模式NK
/*
@func BOOL | DEBUGMSG | Output a debug message conditionally
@parm BOOL | cond | The condition under which the message is printed
@parm <null> | (printf_exp) | A printf style expression to be output. Must be enclosed
in parentheses. Gets passed on to the <f NKDbgPrintf> function.
@ex Example of use |
DEBUGMSG(ZONE_INFO, (L"DLLNAME: Entered func1. Param 1 = %d/r/n", par1));
@xref <f RETAILMSG> <tab> <f ERRORMSG> <tab> <f NKDbgPrintf>
*/
#define DEBUGMSG(cond,printf_exp) /
((void)((cond)?(NKDbgPrintfW printf_exp),1:0)) //DEBUGMSG是通过NKDbgPrintfW 来实现的
#define DBGCHK(module,exp) /
((void)((exp)?1:( /
NKDbgPrintfW ( TEXT("%s: DEBUGCHK failed in file %s at line %d /r/n"), /
(LPWSTR)module, TEXT(__FILE__) ,__LINE__ ), /
DebugBreak(), /
0 /
)))
/*
@func BOOL | DEBUGLED | Output a debug LED pattern conditionally
@parm BOOL | cond | The condition under which the message is printed
@parm <null> | (parms) | The parameters to be passed to the WriteDebugLED
function. Must be in parentheses. First parameter is wIndex and second
parameter is dwPattern.
@ex Example of use |
DEBUGLED(ZONE_INFO, (3, 0x2345);
@xref <f RETAILMSG> <tab> <f ERRORMSG> <tab> <f WriteDebugLED>
*/
#define DEBUGLED(cond,parms) /
((void)((cond)?(WriteDebugLED parms),1:0))
/*
@func BOOL | DEBUGCHK | Asserts an expression
@parm BOOL | exp | Expression to be asserted
@comm If the expression is false, this will cause a DebugBreak to be hit which
will cause you to enter the debugger if you are running with one. It will
also give you the line number and file name where the assert failed.
*/
#define DEBUGCHK(exp) DBGCHK(dpCurSettings.lpszName, exp)
extern DBGPARAM dpCurSettings;
/*
@func BOOL | DEBUGREGISTER | Registers debug settings for a process / module
@parm HINSTANCE | hInstance | If target is a module this is it's hInstance. If
target is a process this should be NULL.
@comm This simply calls through to <f RegisterDebugZones>. It assumes that
there is a variable of name <b dpCurSettings> visible in the code.
*/
#define DEBUGREGISTER(hMod) RegisterDbgZones(hMod, &dpCurSettings)
#else // DEBUG 如果没有定义,就不会打印。
#define DEBUGMSG(cond,printf_exp) ((void)0)
#define DEBUGLED(cond,parms) ((void)0)
#define DBGCHK(module,exp) ((void)0)
#define DEBUGCHK(exp) ((void)0)
#define DEBUGREGISTER(hMod) ((void)0)
#endif // DEBUG
/*
@func BOOL | RETAILMSG | Output a message in retail builds
@parm BOOL | cond | The condition under which the message is printed
@parm <null> | (printf_exp) | A printf style expression to be output. Must be enclosed
in parentheses. This is simply passed in to the <f NKDbgPrintf> function.
@comm This should be used in a very limited fashion since it can increase
the size of your retail build.
@ex Example of use |
RETAILMSG(x==y, (L"DLLNAME: Expect. x==y = %d/r/n", x));
@xref <f DEBUGMSG> <tab> <f ERRORMSG> <tab> <f NKDbgPrintf>
*/
#define RETAILMSG(cond,printf_exp)///从这里可以知道,RETAILMSG、DEBUGMSG一模一样,只是换了名字,通过NKDbgPrintfW来实现的
((cond)?(NKDbgPrintfW printf_exp),1:0)
/*
@func BOOL | ERRORMSG | Output an error msg
@parm BOOL | cond | The condition under which the message is printed
@parm <null> | (printf_exp) | A printf style expression to be output. Must be enclosed
in parentheses. This is passed in to the <f NKDbgPrintf> function.
@comm Very similar to <f RETAILMSG> except that this will prefix the message
with "ERROR" and give the file name & line number of the error.
@ex Example of use |
ERRORMSG(x==y, (L"DLLNAME: x===y = %d/r/n", x));
@xref <f DEBUGMSG> <tab> <f RETAILMSG> <tab> <f NKDbgPrintf>
*/
#define ERRORMSG(cond,printf_exp) /
((cond)?(NKDbgPrintfW(TEXT("ERROR: %s line %d: "),TEXT(__FILE__),__LINE__), NKDbgPrintfW printf_exp),1:0)
/*
@func BOOL | RETAILREGISTERZONES | Registers zone settings for a process / module
(Same as DEBUGREGISTER except available in retail and debug builds)
@parm HINSTANCE | hInstance | If target is a module this is it's hInstance. If
target is a process this should be NULL.
@comm This simply calls through to <f RegisterDebugZones>. It assumes that
there is a variable of name <b dpCurSettings> visible in the code.
*/
#define RETAILREGISTERZONES(hMod) RegisterDbgZones(hMod, &dpCurSettings)
#endif // SHIP_BUILD
/*
@func BOOL | RETAILLED | Output a LED code in retail builds
@parm BOOL | cond | The condition under which the message is printed
@parm <null> | (parms) | The parameters to be passed to the WriteDebugLED
function. Must be in parentheses. First parameter is wIndex and second
parameter is dwPattern.
@comm This should be used in a very limited fashion since it can increase
the size of your retail build.
@ex Example of use |
RETAILLED(ZONE_INFO, (3, 0x2345);
@xref <f DEBUGMSG> <tab> <f ERRORMSG> <tab> <f WriteDebugLED>
*/
#define RETAILLED(cond,parms) /
((void)((cond)?(WriteDebugLED parms),1:0))
// some alternate ways to get to these
#define ASSERTMSG(msg, exp) (DEBUGMSG(!exp,(msg)),DBGCHK(TEXT("Unknown"),exp))
#define ASSERT( exp ) DBGCHK(TEXT("Unknown"), exp)
#define ASSERT_IMPLIES( cond, exp ) ASSERT( !(cond) || (exp) )
#ifdef DEBUG
#define VERIFY(exp) ASSERT(exp)
#else
#define VERIFY(exp) ((void)(exp))
#endif
// Enable providing a hint to prefast via __assume
// e.g.
// PREFAST_ASSUME( pPointer); // we know pPointer can never be NULL
#ifdef _PREFAST_
#define PREFAST_ASSUME(exp) __assume(exp)
#else
#define PREFAST_ASSUME(exp)
#endif
// Simplify the cases where a PREFAST_ASSUME would be followed by an assertion
#define PREFAST_DEBUGCHK(exp) /
{ /
PREFAST_ASSUME(exp); /
DEBUGCHK(exp); /
}
#define PREFAST_ASSERT(exp) /
{ /
PREFAST_ASSUME(exp); /
ASSERT(exp); /
}
// macro to tell Prefast to not issue a specific warning for the following line of code
// use to suppress false positives from Prefast
// e.g.
// if( fPointerNotNull )
// PREFAST_SUPPRESS( 11, "pointer access is guarded by 'fPointerNotNull'" )
// p->Foo();
#ifdef _PREFAST_
#define PREFAST_SUPPRESS( cWarning, comment) __pragma ( prefast(suppress: cWarning, comment) )
#else
#define PREFAST_SUPPRESS( cWarning, comment)
#endif
// Helpful DBG macros that tighten up code.
// They prepend __FUNCTION__ to your debug msg and add a /n to the end.
#define DEB_0(ZONE,STR) DEBUGMSG(ZONE,(L"%S:"STR L"/n",__FUNCTION__))
#define DEB_1(ZONE,STR,ARG1) DEBUGMSG(ZONE,(L"%S:"STR L"/n",__FUNCTION__,ARG1))
#define DEB_2(ZONE,STR,ARG1,ARG2) DEBUGMSG(ZONE,(L"%S:"STR L"/n",__FUNCTION__,ARG1,ARG2))
#define DEB_3(ZONE,STR,ARG1,ARG2,ARG3) DEBUGMSG(ZONE,(L"%S:"STR L"/n",__FUNCTION__,ARG1,ARG2,ARG3))
#define DEB_4(ZONE,STR,ARG1,ARG2,ARG3,ARG4) DEBUGMSG(ZONE,(L"%S:"STR L"/n",__FUNCTION__,ARG1,ARG2,ARG3,ARG4))
#define DEB_5(ZONE,STR,ARG1,ARG2,ARG3,ARG4,ARG5) DEBUGMSG(ZONE,(L"%S:"STR L"/n",__FUNCTION__,ARG1,ARG2,ARG3,ARG4,ARG5))
//
// The _A version of the above are identical, except they call assert after the DEB_*.
// It's highly recommend that you use DEB_*_A with ZONE_ERROR so the user can always see the error.
// printed with the assert.
// NOTE: The assert is not conditioned on the ZONE.
#define DEB_0_A(ZONE,STR) { DEB_0(ZONE,STR);ASSERT(FALSE); }
#define DEB_1_A(ZONE,STR,ARG1) { DEB_1(ZONE,STR,ARG1); ASSERT(FALSE);}
#define DEB_2_A(ZONE,STR,ARG1,ARG2) { DEB_2(ZONE,STR,ARG1,ARG2); ASSERT(FALSE);}
#define DEB_3_A(ZONE,STR,ARG1,ARG2,ARG3) { DEB_3(ZONE,STR,ARG1,ARG2,ARG3); ASSERT(FALSE);}
#define DEB_4_A(ZONE,STR,ARG1,ARG2,ARG3,ARG4) { DEB_4(ZONE,STR,ARG1,ARG2,ARG3,ARG4); ASSERT(FALSE);}
#define DEB_5_A(ZONE,STR,ARG1,ARG2,ARG3,ARG4,ARG5) {DEB_5(ZONE,STR,ARG1,ARG2,ARG3,ARG4,ARG5); ASSERT(FALSE);}
#ifdef __cplusplus
}
#endif
#endif
从上面可以知道,RETAILMSG、DEBUGMSG一模一样,只是换了名字,通过NKDbgPrintfW来实现的,那么这个NKDbgPrintfW又是怎么来的呢?
1//
2// Copyright (c) Microsoft Corporation. All rights reserved.
3//
4//
5// This source code is licensed under Microsoft Shared Source License
6// Version 1.0 for Windows CE.
7// For a copy of the license visit http://go.microsoft.com/fwlink/?LinkId=3223.
8//
9/**//*
10 * NK Kernel printf code
11 *
12 *
13 * Module Name:
14 *
15 * printf.c
16 *
17 * Abstract:
18 *
19 * This file implements debug and string routines
20 *
21 */
22
23/**//*
24@doc EXTERNAL KERNEL
25@topic Debug Support for Applications |
26 The kernel provides several kinds of supports for debugging
27 applications. These are:
28
29 <b Debug Messages>: The kernel provides API's for printing out
30 of debug messages which can be turned on and off dynamically
31 using zones. Any module (DLL/Process) can register itself
32 with the debug subsystem using <f DEBUGREGISTER>. This API
33 registers the address of a Zonemask (which is a DWORD) with the
34 kernel. Using the debug shell, a user can now dynamically turn
35 bits of this zonemask on and off from the shell window.
36 The most typical way to use this is to filter debug messages
37 based on these bits. A structured way to do this is to use
38 the <f DEBUGZONE> macro to associate zones with bits, and then
39 use the <f DEBUGMSG> function to associate each debug message
40 with a zone. Type ? in the shell to see how to change zones
41 dynamically from the shell which uses the <f SetDbgZone> function
42 to implement the change. See the example below for general zone
43 usage.
44
45 <b Asserts>: The kernel also provides for simple asserts. See
46 <f DEBUGCHK> for details.
47
48@ex An example of using debug zones |
49 // Declare a DBGPARAM structure & give names to all used zones
50 DBGPARAM dpCurSettings = { L"foodll", {
51 L"Info", L"Validate", L"bar", L"random",
52 L"Undefined", L"Undefined", L"Undefined", L"Undefined",
53 L"Undefined", L"Undefined", L"Undefined", L"Undefined",
54 L"Undefined", L"Undefined", L"Undefined", L"Undefined" },
55 0x00000000 };
56
57 // Associate bits with a zone
58 // these should match up with the text strings above!
59 #define ZONE_INFO DEBUGZONE(0)
60 #define ZONE_VALIDATE DEBUGZONE(1)
61
62 // Register : Assume this is a DLL
63 // A Process would do the same in their libmain
64 BOOL DllEntry (HANDLE hinstDLL, DWORD fdwReason, LPVOID lpv) {
65 if ( fdwReason == DLL_PROCESS_ATTACH ) {
66 DEBUGREGISTER(hinstDLL);
67 }
68
69 }
70
71 // Use the defined zone in debug messages
72 DEBUGMSG (ZONE_INFO, (L"This is an illustrative messages only!"));
73
74 // Or use a zone to turn execution of some code on & off
75 if (ZONE_VALIDATE) {
76 // validate some stuff
77 }
78
79@xref
80 <f DEBUGMSG> <tab> <f RETAILMSG> <tab> <f ERRORMSG> <tab> <f DEBUGCHK> <tab>
81 <f DEBUGREGISTER> <tab> <f DEBUGZONE> <tab> <t DBGPARAM> <tab>
82 <f RegisterDebugZones> <tab> <f SetDbgZone>
83*/
84
85#include "kernel.h"
86
87#define out(c) if (--cchLimit) *lpOut++=(c); else goto errorout
88
89//-------------------------- Prototype declarations ---------------------------
90
91int NKwvsprintfW(LPWSTR lpOut, LPCWSTR lpFmt, CONST VOID * lpParms, int maxchars);
92LPCWSTR SP_GetFmtValue(LPCWSTR lpch, int *lpw, va_list *plpParms);
93int SP_PutNumber(LPWSTR, ULONG, int, int, int);
94int SP_PutNumber64(LPWSTR lpb, __int64 i64, int limit, int radix, int mycase);
95void SP_Reverse(LPWSTR lp1, LPWSTR lp2);
96
97extern CRITICAL_SECTION ODScs, DbgApiCS, VAcs, PhysCS;
98
99extern BOOL fSysStarted;
100extern BOOL g_cInterruptsOff; // this indicates KD had turned interrupts off
101
102
103//------------------------------------------------------------------------------
104//------------------------------------------------------------------------------
105VOID WINAPI
106OutputDebugStringW(
107 LPCWSTR str
108 )
109{
110 BOOL fGetODScs = FALSE, fLockPages = FALSE;
111 int len;
112
113 // if we ever call OutputDebugString with interrupts off, send it to serial
114 // port and return right away
115 if (g_cInterruptsOff) {
116 OEMWriteDebugString((unsigned short *)str);
117 return;
118 }
119
120 // increase debug count to indicate we're in ODS
121 if (!str)
122 str = __TEXT("(NULL)");
123
124 if (pCurThread) {
125
126 pCurThread->bDbgCnt ++;
127
128 // do not notify debugger while in power handler because we cannot block
129 if (!InSysCall () && !IsInPwrHdlr ()) {
130
131 if (pCurThread->pThrdDbg && (DbgApiCS.OwnerThread != hCurThread)
132 && ProcStarted(pCurProc) && pCurThread->pThrdDbg->hEvent) {
133 pCurThread->pThrdDbg->dbginfo.dwDebugEventCode = OUTPUT_DEBUG_STRING_EVENT;
134 pCurThread->pThrdDbg->dbginfo.dwProcessId = (DWORD)hCurProc;
135 pCurThread->pThrdDbg->dbginfo.dwThreadId = (DWORD)hCurThread;
136 pCurThread->pThrdDbg->dbginfo.u.DebugString.lpDebugStringData = (LPBYTE)str;
137 pCurThread->pThrdDbg->dbginfo.u.DebugString.fUnicode = TRUE;
138 pCurThread->pThrdDbg->dbginfo.u.DebugString.nDebugStringLength = (strlenW(str)+1)*2;
139 SetEvent(pCurThread->pThrdDbg->hEvent);
140 SC_WaitForMultiple(1,&pCurThread->pThrdDbg->hBlockEvent,FALSE,INFINITE);
141 }
142
143 fGetODScs = !ReadyForStrings && (hCurThread != ODScs.OwnerThread);
144 fLockPages = (1 == pCurThread->bDbgCnt);
145
146 }
147 }
148
149 // forces the string to be paged in if not already
150 len = (strlenW(str)+1)*sizeof(WCHAR);
151
152 // Lock page if we need to
153 if (fLockPages)
154 LockPages((LPVOID)str,len,0,0);
155
156 if (fGetODScs)
157 EnterCriticalSection(&ODScs);
158
159 lpWriteDebugStringFunc((unsigned short *)str);
160
161 if (fGetODScs)
162 LeaveCriticalSection(&ODScs);
163
164 if (fLockPages)
165 UnlockPages((LPVOID)str,len);
166
167 // decrement debug count to indicate we're out of ODS
168 if (pCurThread) {
169 pCurThread->bDbgCnt --;
170 }
171}
172
173
174
175//------------------------------------------------------------------------------
176//------------------------------------------------------------------------------
177int
178InputDebugCharW(void)
179{
180 int retvalue;
181 if (!InSysCall())
182 EnterCriticalSection(&ODScs);
183 retvalue = OEMReadDebugByte();
184 if (!InSysCall())
185 LeaveCriticalSection(&ODScs);
186 return retvalue;
187}
188
189//------------------------------------------------------------------------------
190// special version if we're on KStack
191//------------------------------------------------------------------------------
192static VOID _NKvDbgPrintfW(LPCWSTR lpszFmt, va_list lpParms) {
193 static WCHAR rgchBuf[384];
194 NKwvsprintfW(rgchBuf, lpszFmt, lpParms, sizeof(rgchBuf)/sizeof(WCHAR));
195 OutputDebugStringW(rgchBuf);
196}
197
198//------------------------------------------------------------------------------
199//------------------------------------------------------------------------------
200#if (_MSC_VER >= 1300)
201__declspec(noinline) // Too much KStack is used if this is inlined
202#endif
203static VOID NKvDbgPrintfWOnStack(LPCWSTR lpszFmt, va_list lpParms)
204{
205 WCHAR rgchBuf[384];
206 WORD wLen = 0;
207 // Get it into a string
208#ifdef DEBUG
209 if (ZONE_DEBUG) {
210 rgchBuf[0] = '0';
211 rgchBuf[1] = 'x';
212 wLen += 2;
213 wLen += SP_PutNumber(rgchBuf+2,(ULONG)pCurThread,8,16,0);
214 SP_Reverse(rgchBuf+2,rgchBuf+wLen-1);
215 rgchBuf[wLen++] = ':';
216 rgchBuf[wLen++] = ' ';
217 }
218#endif
219 wLen += NKwvsprintfW(rgchBuf + wLen, lpszFmt, lpParms, sizeof(rgchBuf)/sizeof(WCHAR) - wLen);
220
221 // don't need to call LockPages since it's on stack.
222 if (pCurThread) {
223 pCurThread->bDbgCnt ++;
224 }
225 OutputDebugStringW(rgchBuf);
226 if (pCurThread) {
227 pCurThread->bDbgCnt --;
228 }
229}
230
231
232//------------------------------------------------------------------------------
233//
234// @doc EXTERNAL KERNEL
235// @func VOID | NKDbgPrintf | Prints debug messages
236// @parm LPWSTR | lpszFmt | Printf style formatting string
237// @parmvar Variable argument list
238// @comm Should not be used directly - macros like <f DEBUGMSG> should
239// be used to print messages. This function will format the
240// debug string into a buffer and then log it according to the
241// current logging paramters. If terminal logging is on it
242// outputs this to the debug terminal, and if file logging
243// is on it stores it to the file peg.log on the host PC.
244//
245// <b WARNING>: The message being output must be smaller than
246// 256 bytes - ie 128 unicode characters.
247// @xref <f DEBUGMSG>
248//
249//------------------------------------------------------------------------------
250void WINAPIV
251NKDbgPrintfW(
252 LPCWSTR lpszFmt,
253
254 )
255{
256 va_list arglist;
257 va_start(arglist, lpszFmt);
258 NKvDbgPrintfW(lpszFmt, arglist);
259 va_end(arglist);
260}
261
262VOID NKvDbgPrintfW (LPCWSTR lpszFmt, va_list lpParms)
263{
264 if (fSysStarted && !InSysCall ())
265 NKvDbgPrintfWOnStack (lpszFmt, lpParms);
266 else
267 _NKvDbgPrintfW(lpszFmt, lpParms);
268}
269
270
271//------------------------------------------------------------------------------
272//------------------------------------------------------------------------------
273int
274NKwvsprintfW(
275 LPWSTR lpOut,
276 LPCWSTR lpFmt,
277 va_list lpParms,
278 int maxchars
279 )
280{
281 int left, width, prec, size, sign, radix, upper, cch, cchLimit;
282 WCHAR prefix, fillch;
283 LPWSTR lpT;
284 LPCHAR lpC;
285 union {
286 long l;
287 unsigned long ul;
288 __int64 i64;
289 WCHAR sz[sizeof(long)];
290 } val;
291
292 cchLimit = maxchars;
293 while (*lpFmt) {
294 if (*lpFmt==(WCHAR)'%') {
295 /**//* read the flags. These can be in any order */
296 left=0;
297 prefix=0;
298 while (*++lpFmt) {
299 if (*lpFmt==(WCHAR)'-')
300 left++;
301 else if (*lpFmt==(WCHAR)'#')
302 prefix++;
303 else
304 break;
305 }
306 /**//* find fill character */
307 if (*lpFmt==(WCHAR)'0') {
308 fillch=(WCHAR)'0';
309 lpFmt++;
310 } else
311 fillch=(WCHAR)' ';
312 /**//* read the width specification */
313 lpFmt=SP_GetFmtValue(lpFmt,&cch, &lpParms);
314 width=cch;
315 /**//* read the precision */
316 if (*lpFmt==(WCHAR)'.') {
317 lpFmt=SP_GetFmtValue(++lpFmt,&cch, &lpParms);
318 prec=cch;
319 } else
320 prec=-1;
321 /**//* get the operand size */
322 size=1;
323 if (*lpFmt=='l') {
324 lpFmt++;
325 } else if (*lpFmt=='h') {
326 size=0;
327 lpFmt++;
328 } else if ((*lpFmt == 'I') && (*(lpFmt+1) == '6') && (*(lpFmt+2) == '4')) {
329 lpFmt+=3;
330 size = 2;
331 }
332 upper=0;
333 sign=0;
334 radix=10;
335 switch (*lpFmt) {
336 case 0:
337 goto errorout;
338 case (WCHAR)'i':
339 case (WCHAR)'d':
340 sign++;
341 case (WCHAR)'u':
342 /**//* turn off prefix if decimal */
343 prefix=0;
344donumeric:
345 /**//* special cases to act like MSC v5.10 */
346 if (left || prec>=0)
347 fillch=(WCHAR)' ';
348 if (size == 1)
349 val.l=va_arg(lpParms, long);
350 else if (size == 2)
351 val.i64 = va_arg(lpParms, __int64);
352 else if (sign)
353 val.l=va_arg(lpParms, short);
354 else
355 val.ul=va_arg(lpParms, unsigned);
356 if (sign && val.l<0L)
357 val.l=-val.l;
358 else
359 sign=0;
360 lpT=lpOut;
361 /**//* blast the number backwards into the user buffer */
362 if (size == 2)
363 cch=SP_PutNumber64(lpOut,val.i64,cchLimit,radix,upper);
364 else
365 cch=SP_PutNumber(lpOut,val.l,cchLimit,radix,upper);
366 if (!(cchLimit-=cch))
367 goto errorout;
368 lpOut+=cch;
369 width-=cch;
370 prec-=cch;
371 if (prec>0)
372 width-=prec;
373 /**//* fill to the field precision */
374 while (prec-->0)
375 out((WCHAR)'0');
376 if (width>0 && !left) {
377 /**//* if we're filling with spaces, put sign first */
378 if (fillch!=(WCHAR)'0') {
379 if (sign) {
380 sign=0;
381 out((WCHAR)'-');
382 width--;
383 }
384 if (prefix) {
385 out(prefix);
386 out((WCHAR)'0');
387 prefix=0;
388 }
389 }
390 if (sign)
391 width--;
392 /**//* fill to the field width */
393 while (width-->0)
394 out(fillch);
395 /**//* still have a sign? */
396 if (sign)
397 out((WCHAR)'-');
398 if (prefix) {
399 out(prefix);
400 out((WCHAR)'0');
401 }
402 /**//* now reverse the string in place */
403 SP_Reverse(lpT,lpOut-1);
404 } else {
405 /**//* add the sign character */
406 if (sign) {
407 out((WCHAR)'-');
408 width--;
409 }
410 if (prefix) {
411 out(prefix);
412 out((WCHAR)'0');
413 }
414 /**//* reverse the string in place */
415 SP_Reverse(lpT,lpOut-1);
416 /**//* pad to the right of the string in case left aligned */
417 while (width-->0)
418 out(fillch);
419 }
420 break;
421 case (WCHAR) 'p' :
422 // Fall into case below, since NT is going to 64 bit
423 // they are starting to use p to indicate a pointer
424 // value. They only seem to support lower case 'p'
425 case (WCHAR)'X':
426 upper++;
427 case (WCHAR)'x':
428 radix=16;
429 if (prefix)
430 if (upper)
431 prefix=(WCHAR)'X';
432 else
433 prefix=(WCHAR)'x';
434 goto donumeric;
435 case (WCHAR)'c':
436 val.sz[0] = va_arg(lpParms, WCHAR);
437 val.sz[1]=0;
438 lpT=val.sz;
439 cch = 1; // Length is one character.
440 /**//* stack aligned to larger size */
441 goto putstring;
442 case 'a': // ascii string!
443 case 'S':
444PrtAscii:
445 if (!(lpC=va_arg(lpParms, LPCHAR)))
446 lpC = "(NULL)";
447 cch=strlen(lpC);
448 if (prec>=0 && cch>prec)
449 cch=prec;
450 width -= cch;
451 if (left) {
452 while (cch--)
453 out((WCHAR)*lpC++);
454 while (width-->0)
455 out(fillch);
456 } else {
457 while (width-->0)
458 out(fillch);
459 while (cch--)
460 out((WCHAR)*lpC++);
461 }
462 break;
463 case 's':
464 if (!size)
465 goto PrtAscii;
466 if (!(lpT=va_arg(lpParms,LPWSTR)))
467 lpT = L"(NULL)";
468 cch=strlenW(lpT);
469putstring:
470 if (prec>=0 && cch>prec)
471 cch=prec;
472 width -= cch;
473 if (left) {
474 while (cch--)
475 out(*lpT++);
476 while (width-->0)
477 out(fillch);
478 } else {
479 while (width-->0)
480 out(fillch);
481 while (cch--)
482 out(*lpT++);
483 }
484 break;
485 default:
486 out(*lpFmt); /**//* Output the invalid char and continue */
487 break;
488 }
489 } else /**//* character not a '%', just do it */
490 out(*lpFmt);
491 /**//* advance to next format string character */
492 lpFmt++;
493 }
494errorout:
495 *lpOut=0;
496 return maxchars-cchLimit;
497}
498
499
500
501//------------------------------------------------------------------------------
502// GetFmtValue
503// reads a width or precision value from the format string
504//------------------------------------------------------------------------------
505LPCWSTR
506SP_GetFmtValue(
507 LPCWSTR lpch,
508 int *lpw,
509 va_list *plpParms
510 )
511{
512 int i=0;
513 if (*lpch == TEXT('*')) {
514 *lpw = va_arg(*plpParms, int);
515 lpch++;
516 } else {
517 while (*lpch>=(WCHAR)'0' && *lpch<=(WCHAR)'9') {
518 i = i*10 + (*lpch-(WCHAR)'0');
519 lpch++;
520 }
521 *lpw=i;
522 }
523 /**//* return the address of the first non-digit character */
524 return lpch;
525}
526
527
528
529//------------------------------------------------------------------------------
530//------------------------------------------------------------------------------
531void
532SP_Reverse(
533 LPWSTR lpFirst,
534 LPWSTR lpLast
535 )
536{
537 int swaps;
538 WCHAR tmp;
539 swaps = ((((DWORD)lpLast - (DWORD)lpFirst)/sizeof(WCHAR)) + 1)/2;
540 while (swaps--) {
541 tmp = *lpFirst;
542 *lpFirst++ = *lpLast;
543 *lpLast-- = tmp;
544 }
545}
546
547const WCHAR lowerval[] = TEXT("0123456789abcdef");
548const WCHAR upperval[] = TEXT("0123456789ABCDEF");
549
550
551
552//------------------------------------------------------------------------------
553//------------------------------------------------------------------------------
554int
555SP_PutNumber(
556 LPWSTR lpb,
557 ULONG n,
558 int limit,
559 int radix,
560 int mycase
561 )
562{
563 int used = 0;
564 while (limit--) {
565 *lpb++ = (mycase ? upperval[(n % radix)] : lowerval[(n % radix)]);
566 used++;
567 if (!(n /= radix))
568 break;
569 }
570 return used;
571}
572
573
574
575//------------------------------------------------------------------------------
576//------------------------------------------------------------------------------
577int
578SP_PutNumber64(
579 LPWSTR lpb,
580 __int64 i64,
581 int limit,
582 int radix,
583 int mycase
584 )
585{
586 int used = 0;
587 while (limit--) {
588 *lpb++ = (mycase ? upperval[(i64 % radix)] : lowerval[(i64 % radix)]);
589 used++;
590 if (!(i64 /= radix))
591 break;
592 }
593 return used;
594}
595
596
- wince串口打印函数是如何实现的?(作者wogoyixikexie@gliet)
- 如何删除wince的驱动(作者:wogoyixikexie@gliet)
- wince串口之MDD分析(作者:wogoyixikexie@gliet)
- wince 2440串口驱动PDD分析(作者:wogoyixikexie@gliet)
- OEMAddressTable 内存映射表是怎么被wince使用的(作者:wogoyixikexie@gliet)
- 如何实现OV9650摄像头拍照(作者gooogleman/wogoyixikexie@gliet)
- 如何实现OV9650摄像头拍照(作者gooogleman/wogoyixikexie@gliet)
- wince串口线程、中断等相关学习(作者:wogoyixikexie@gliet)
- wince串口线程、中断等相关学习(作者:wogoyixikexie@gliet)
- 转---------------wince串口线程、中断等相关学习(作者:wogoyixikexie@gliet)
- 如何在wince下添加和删除驱动(作者:wogoyixikexie@gliet)
- 2440 5.0BSP增加三串口(作者:wogoyixikexie@gliet)
- 2440 外部串口驱动调试(作者:wogoyixikexie@gliet)
- ZLG7290(wince下)驱动之不停执行同一动作的解决办法(作者:wogoyixikexie@gliet)
- wince 5.0 .2440 5.0BSP的中断过程(作者:wogoyixikexie@gliet)
- 转:wince 5.0 .2440 5.0BSP的中断过程(作者:wogoyixikexie@gliet)
- 提高wince中断响应速度的一种方法(作者:wogoyixikexie@gliet)
- 如何实现2440软件重启/software reset(作者:wogoyixikexie@gliet)
- 关于4.6C升级到ECC UNICODE时全角字符串长度问题
- 关于学习css样式的收获
- 开源数据库
- Mass additions transfer to fixed assets[payable module](Ask and Answer)
- C#实现从EXCEL将数据导出到datagridview
- wince串口打印函数是如何实现的?(作者wogoyixikexie@gliet)
- 杂记
- QTP 重复添加
- 以Vista下管理员身份启动程序
- flash打开本地文件 代码
- arm-linux-gdb+gdbserver环境搭建以及远程调试
- Head First C# 中文版 图文皆译 第五章 封装 page195
- 程序编译中如何调试configure
- 使用 GStreamer 进行多用途的多媒体处理