2011年9月16日星期五

Standard Macros

From:http://developer.gnome.org/glib/2.29/glib-Standard-Macros.html#G-STRUCT-MEMBER-P:CAPS

Standard Macros
Standard Macros — commonly-used macros.

Synopsis
#include

#define G_OS_WIN32
#define G_OS_BEOS
#define G_OS_UNIX

#define G_DIR_SEPARATOR
#define G_DIR_SEPARATOR_S
#define G_IS_DIR_SEPARATOR (c)
#define G_SEARCHPATH_SEPARATOR
#define G_SEARCHPATH_SEPARATOR_S

#define TRUE
#define FALSE

#define NULL

#define MIN (a,
b)
#define MAX (a,
b)

#define ABS (a)
#define CLAMP (x,
low,
high)

#define G_STRUCT_MEMBER (member_type,
struct_p,
struct_offset)
#define G_STRUCT_MEMBER_P (struct_p,
struct_offset)
#define G_STRUCT_OFFSET (struct_type,
member)

#define G_MEM_ALIGN

#define G_CONST_RETURN
Description
These macros provide a few commonly-used features.

Details
G_OS_WIN32
#define G_OS_WIN32
This macro is defined only on Windows. So you can bracket Windows-specific code in "#ifdef G_OS_WIN32".

G_OS_BEOS
#define G_OS_BEOS
This macro is defined only on BeOS. So you can bracket BeOS-specific code in "#ifdef G_OS_BEOS".

G_OS_UNIX
#define G_OS_UNIX
This macro is defined only on UNIX. So you can bracket UNIX-specific code in "#ifdef G_OS_UNIX".

G_DIR_SEPARATOR
#define G_DIR_SEPARATOR '\\'
The directory separator character. This is '/' on UNIX machines and '\' under Windows.

G_DIR_SEPARATOR_S
#define G_DIR_SEPARATOR_S "\\"
The directory separator as a string. This is "/" on UNIX machines and "\" under Windows.

G_IS_DIR_SEPARATOR()
#define G_IS_DIR_SEPARATOR(c) ((c) == G_DIR_SEPARATOR || (c) == '/')
Checks whether a character is a directory separator. It returns TRUE for '/' on UNIX machines and for '\' or '/' under Windows.

c :
a character
Since 2.6

G_SEARCHPATH_SEPARATOR
#define G_SEARCHPATH_SEPARATOR ';'
The search path separator character. This is ':' on UNIX machines and ';' under Windows.

G_SEARCHPATH_SEPARATOR_S
#define G_SEARCHPATH_SEPARATOR_S ";"
The search path separator as a string. This is ":" on UNIX machines and ";" under Windows.

TRUE
#define TRUE (!FALSE)
Defines the TRUE value for the gboolean type.

FALSE
#define FALSE (0)
Defines the FALSE value for the gboolean type.

NULL
# define NULL (0L)
Defines the standard NULL pointer.

MIN()
#define MIN(a, b) (((a) < (b)) ? (a) : (b)) Calculates the minimum of a and b. a : a numeric value. b : a numeric value. Returns : the minimum of a and b. MAX() #define MAX(a, b) (((a) > (b)) ? (a) : (b))
Calculates the maximum of a and b.

a :
a numeric value.
b :
a numeric value.
Returns :
the maximum of a and b.
ABS()
#define ABS(a) (((a) < 0) ? -(a) : (a)) Calculates the absolute value of a. The absolute value is simply the number with any negative sign taken away. For example, ABS(-10) is 10. ABS(10) is also 10. a : a numeric value. Returns : the absolute value of a. CLAMP() #define CLAMP(x, low, high) (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x)))
Ensures that x is between the limits set by low and high. If low is greater than high the result is undefined.

For example,

CLAMP(5, 10, 15) is 10.

CLAMP(15, 5, 10) is 10.

CLAMP(20, 15, 25) is 20.

x :
the value to clamp.
low :
the minimum value allowed.
high :
the maximum value allowed.
Returns :
the value of x clamped to the range between low and high.
G_STRUCT_MEMBER()
#define G_STRUCT_MEMBER(member_type, struct_p, struct_offset)
Returns a member of a structure at a given offset, using the given type.

member_type :
the type of the struct field.
struct_p :
a pointer to a struct.
struct_offset :
the offset of the field from the start of the struct, in bytes.
Returns :
the struct member.
G_STRUCT_MEMBER_P()
#define G_STRUCT_MEMBER_P(struct_p, struct_offset)
Returns an untyped pointer to a given offset of a struct.

struct_p :
a pointer to a struct.
struct_offset :
the offset from the start of the struct, in bytes.
Returns :
an untyped pointer to struct_p plus struct_offset bytes.
G_STRUCT_OFFSET()
#define G_STRUCT_OFFSET(struct_type, member)
Returns the offset, in bytes, of a member of a struct.

struct_type :
a structure type, e.g. GtkWidget.
member :
a field in the structure, e.g. window.
Returns :
the offset of member from the start of struct_type.
G_MEM_ALIGN
# define G_MEM_ALIGN GLIB_SIZEOF_VOID_P
Indicates the number of bytes to which memory will be aligned on the current platform.

G_CONST_RETURN
#define G_CONST_RETURN
Warning
G_CONST_RETURN has been deprecated since version 2.30 and should not be used in newly-written code. API providers should replace all existing uses with const and API consumers should adjust their code accordingly.

If G_DISABLE_CONST_RETURNS is defined, this macro expands to nothing. By default, the macro expands to const. The macro should be used in place of const for functions that return a value that should not be modified. The purpose of this macro is to allow us to turn on const for returned constant strings by default, while allowing programmers who find that annoying to turn it off. This macro should only be used for return values and for out parameters, it doesn't make sense for in parameters.

Generated by GTK-Doc V1.17

2011年9月15日星期四

#define用法集锦

Definition:
The #define Directive
  You can use the #define directive to give a meaningful name to a constant in your program. The two forms of the syntax are:
  Syntax
  #define identifier token-stringopt
  #define identifier[( identifieropt, ... , identifieropt )] token-stringopt

Usage:

1. 简单的define定义
#define MAXTIME 1000
一个简单的MAXTIME就定义好了,它代表1000,如果在程序里面写
if(i编译器在处理这个代码之前会对MAXTIME进行处理替换为1000。
这样的定义看起来类似于普通的常量定义CONST,但也有着不同,因为define的定义更像是简单的文本替换,而不是作为一个量来使用,这个问题在下面反映的尤为突出。
2.define的“函数定义”
define可以像函数那样接受一些参数,如下
#define max(x,y) (x)>(y)?(x):(y);
这个定义就将返回两个数中较大的那个,看到了吗?因为这个“函数”没有类型检查,就好像一个函数模板似的,当然,它绝对没有模板那么安全就是了。可以作为一个简单的模板来使用而已。
但是这样做的话存在隐患,例子如下:
#define Add(a,b) a+b;
在一般使用的时候是没有问题的,但是如果遇到如:c * Add(a,b) * d的时候就会出现问题,代数式的本意是a+b然后去和c,d相乘,但是因为使用了define(它只是一个简单的替换),所以式子实际上变成了
c*a + b*d
另外举一个例子:
#define pin (int*);
pin a,b;
本意是a和b都是int型指针,但是实际上变成int* a,b;
a是int型指针,而b是int型变量。
这是应该使用typedef来代替define,这样a和b就都是int型指针了。
所以我们在定义的时候,养成一个良好的习惯,建议所有的层次都要加括号。
3.宏的单行定义(少见用法)
#define A(x) T_##x
#define B(x) #@x
#define C(x) #x
我们假设:x=1,则有:
A(1)------〉T_1
B(1)------〉'1'
C(1)------〉"1"
(这里参考了 hustli的文章)
3.define的多行定义
define可以替代多行的代码,例如MFC中的宏定义(非常的经典,虽然让人看了恶心)
#define MACRO(arg1, arg2) do { \
/* declarations */ \
stmt1; \
stmt2; \
/* ... */ \
} while(0) /* (no trailing ; ) */
关键是要在每一个换行的时候加上一个"\"
4.在大规模的开发过程中,特别是跨平台和系统的软件里,define最重要的功能是条件编译。
就是:
#ifdef WINDOWS
......
......
#endif
#ifdef LINUX
......
......
#endif
可以在编译的时候通过#define设置编译环境
5.如何定义宏、取消宏
//定义宏
#define [MacroName] [MacroValue]
//取消宏
#undef [MacroName]
//普通宏
#define PI (3.1415926)
带参数的宏
#define max(a,b) ((a)>(b)? (a),(b))
关键是十分容易产生错误,包括机器和人理解上的差异等等。
6.条件编译
#ifdef XXX…(#else) … #endif
例如
#ifdef DV22_AUX_INPUT
#define AUX_MODE 3
#else
#define AUY_MODE 3
#endif
#ifndef XXX … (#else) … #endif
7.头文件(.h)可以被头文件或C文件包含;
重复包含(重复定义)
由于头文件包含可以嵌套,那么C文件就有可能包含多次同一个头文件,就可能出现重复定义的问题的。
通过条件编译开关来避免重复包含(重复定义)
例如
#ifndef __headerfileXXX__
#define __headerfileXXX__

//文件内容

#endif


Instances:

1、防止一个头文件被重复包含
#ifndef COMDEF_H
#define COMDEF_H
//头文件内容
#endif
2、重新定义一些类型,防止由于各种平台和编译器的不同,而产生的类型字节数差异,方便移植。
typedef unsigned char boolean; /* Boolean value type. */
typedef unsigned long int uint32; /* Unsigned 32 bit value */
typedef unsigned short uint16; /* Unsigned 16 bit value */
typedef unsigned char uint8; /* Unsigned 8 bit value */
typedef signed long int int32; /* Signed 32 bit value */
typedef signed short int16; /* Signed 16 bit value */
typedef signed char int8; /* Signed 8 bit value */
//下面的不建议使用
typedef unsigned char byte; /* Unsigned 8 bit value type. */
typedef unsigned short word; /* Unsinged 16 bit value type. */
typedef unsigned long dword; /* Unsigned 32 bit value type. */
typedef unsigned char uint1; /* Unsigned 8 bit value type. */
typedef unsigned short uint2; /* Unsigned 16 bit value type. */
typedef unsigned long uint4; /* Unsigned 32 bit value type. */
typedef signed char int1; /* Signed 8 bit value type. */
typedef signed short int2; /* Signed 16 bit value type. */
typedef long int int4; /* Signed 32 bit value type. */
typedef signed long sint31; /* Signed 32 bit value */
typedef signed short sint15; /* Signed 16 bit value */
typedef signed char sint7; /* Signed 8 bit value */
3、得到指定地址上的一个字节或字
#define MEM_B( x ) ( *( (byte *) (x) ) )
#define MEM_W( x ) ( *( (word *) (x) ) )
4、求最大值和最小值
#define MAX( x, y ) ( ((x) > (y)) ? (x) : (y) )
#define MIN( x, y ) ( ((x) < (y)) ? (x) : (y) )
5、得到一个field在结构体(struct)中的偏移量
#define FPOS( type, field ) \
/*lint -e545 */ ( (dword) &(( type *) 0)-> field ) /*lint +e545 */
6、得到一个结构体中field所占用的字节数
#define FSIZ( type, field ) sizeof( ((type *) 0)->field )
7、按照LSB格式把两个字节转化为一个Word
#define FLIPW( ray ) ( (((word) (ray)[0]) * 256) + (ray)[1] )
8、按照LSB格式把一个Word转化为两个字节
#define FLOPW( ray, val ) \
(ray)[0] = ((val) / 256); \
(ray)[1] = ((val) & 0xFF)
9、得到一个变量的地址(word宽度)
#define B_PTR( var ) ( (byte *) (void *) &(var) )
#define W_PTR( var ) ( (word *) (void *) &(var) )
10、得到一个字的高位和低位字节
#define WORD_LO(xxx) ((byte) ((word)(xxx) & 255))
#define WORD_HI(xxx) ((byte) ((word)(xxx) >> 8))
11、返回一个比X大的最接近的8的倍数
#define RND8( x ) ((((x) + 7) / 8 ) * 8 )
12、将一个字母转换为大写
#define UPCASE( c ) ( ((c) >= 'a' && (c) <= 'z') ? ((c) - 0x20) : (c) )
13、判断字符是不是10进值的数字
#define DECCHK( c ) ((c) >= '0' && (c) <= '9')
14、判断字符是不是16进值的数字
#define HEXCHK( c ) ( ((c) >= '0' && (c) <= '9') ||\
((c) >= 'A' && (c) <= 'F') ||\
((c) >= 'a' && (c) <= 'f') )
15、防止溢出的一个方法
#define INC_SAT( val ) (val = ((val)+1 > (val)) ? (val)+1 : (val))
16、返回数组元素的个数
#define ARR_SIZE( a ) ( sizeof( (a) ) / sizeof( (a[0]) ) )
17、返回一个无符号数n尾的值MOD_BY_POWER_OF_TWO(X,n)=X%(2^n)
#define MOD_BY_POWER_OF_TWO( val, mod_by ) \
( (dword)(val) & (dword)((mod_by)-1) )
18、对于IO空间映射在存储空间的结构,输入输出处理
#define inp(port) (*((volatile byte *) (port)))
#define inpw(port) (*((volatile word *) (port)))
#define inpdw(port) (*((volatile dword *)(port)))
#define outp(port, val) (*((volatile byte *) (port)) = ((byte) (val)))
#define outpw(port, val) (*((volatile word *) (port)) = ((word) (val)))
#define outpdw(port, val) (*((volatile dword *) (port)) = ((dword) (val)))
19、使用一些宏跟踪调试
ANSI标准说明了五个预定义的宏名。它们是:
__LINE__
__FILE__
__DATE__
__TIME__
__STDC__
C++中还定义了 __cplusplus
如果编译器不是标准的,则可能仅支持以上宏名中的几个,或根本不支持。记住编译程序也许还提供其它预定义的宏名。
__LINE__ 及 __FILE__ 宏指示,#line指令可以改变它的值,简单的讲,编译时,它们包含程序的当前行数和文件名。
__DATE__ 宏指令含有形式为月/日/年的串,表示源文件被翻译到代码时的日期。
__TIME__ 宏指令包含程序编译的时间。时间用字符串表示,其形式为:分:秒
__STDC__ 宏指令的意义是编译时定义的。一般来讲,如果__STDC__已经定义,编译器将仅接受不包含任何非标准扩展的标准C/C++代码。如果实现是标准的,则宏__STDC__含有十进制常量1。如果它含有任何其它数,则实现是非标准的。
__cplusplus 与标准c++一致的编译器把它定义为一个包含至少6为的数值。与标准c++不一致的编译器将使用具有5位或更少的数值。
可以定义宏,例如:
当定义了_DEBUG,输出数据信息和所在文件所在行
#ifdef _DEBUG
#define DEBUGMSG(msg,date) printf(msg);printf(“%d%d%d”,date,_LINE_,_FILE_)
#else
#define DEBUGMSG(msg,date)
#endif

20、宏定义防止错误使用小括号包含。
例如:
有问题的定义:#define DUMP_WRITE(addr,nr) {memcpy(bufp,addr,nr); bufp += nr;}
应该使用的定义: #difne DO(a,b) do{a+b;a++;}while(0)
例如:
if(addr)
DUMP_WRITE(addr,nr);
else
do_somethong_else();
宏展开以后变成这样:
if(addr)
{memcpy(bufp,addr,nr); bufp += nr;};
else
do_something_else();
gcc在碰到else前面的“;”时就认为if语句已经结束,因而后面的else不在if语句中。而采用do{} while(0)的定义,在任何情况下都没有问题。而改为 #difne DO(a,b) do{a+b;a++;}while(0) 的定义则在任何情况下都不会出错

21. define中的特殊标识符
#define Conn(x,y) x##y
#define ToChar(x) #@x
#define ToString(x) #x

int a=Conn(12,34);
char b=ToChar(a);
char c[]=ToString(a);
结果是 a=1234,c='a',c='1234';
可以看出 ## 是简单的连接符,#@用来给参数加单引号,#用来给参数加双引号即转成字符串

2011年9月6日星期二

符号长整数 UL

那不加“UL”与加“UL”有什么区别?符号区别?
为什么宏定义中有的加了UL,有的却不加?
加了UL就不进行类型检查,直接以UL的形式把值赋给某个对应的内存,如果超出定义变量的范围,则截取。

2011年9月3日星期六

字节顺序:大端字节(big-endian)和小端字节(little-endian)

转自:http://www.sf.org.cn/Article/base/200606/18679.html

作者:suyouxin 文章来源:csdn blog 更新时间:2006-6-24 22:20:32

今天碰一个关于字节顺序的问题,虽然看起来很简单,但一直都没怎么完全明白这个东西,索性就找了下资料,把它弄清楚.
因为现行的计算机都是以八位一个字节为存储单位,那么一个16位的整数,也就是C语言中的short,在内存中可能有两种存储顺序big-endian和litte-endian.考虑一个short整数0x3132(0x32是低位,0x31是高位),把它赋值给一个short变量,那么它在内存中的存储可能有如下两种情况:
大端字节(Big-endian):
----------------->>>>>>>>内存地址增大方向
short变量地址
0x1000 0x1001
_____________________________
| |
| 0x31 | 0x32
|________________ | ________________
高位字节在低位字节的前面,也就是高位在内存地址低的一端.可以这样记住(大端->高位->在前->正常的逻辑顺序)

小端字节(little-endian):
----------------->>>>>>>>内存地址增大方向
short变量地址
0x1000 0x1001
_____________________________
| |
| 0x32 | 0x31
|________________ | ________________
低位字节在高位字节的前面,也就是低位在内存地址低的一端.可以这样记住(小端->低位->在前->与正常逻辑顺序相反)

可以做个实验
在windows上下如下程序
#include
#include

void main( void )
{
short test;
FILE* fp;

test = 0x3132; //(31ASIIC码的’1’,32ASIIC码的’2’)
if ((fp = fopen ("c:\\test.txt", "wb")) == NULL)
assert(0);
fwrite(&test, sizeof(short), 1, fp);
fclose(fp);
}
然后在C盘下打开test.txt文件,可以看见内容是21,而test等于0x3132,可以明显的看出来x86的字节顺序是低位在前.如果我们把这段同样的代码放到(big-endian)的机器上执行,那么打出来的文件就是12.这在本机中使用是没有问题的.但当你把这个文件从一个big-endian机器复制到一个little-endian机器上时就出现问题了.
如上述例子,我们在big-endian的机器上创建了这个test文件,把其复制到little-endian的机器上再用fread读到一个short里面,我们得到的就不再是0x3132而是0x3231了,这样读到的数据就是错误的,所以在两个字节顺序不一样的机器上传输数据时需要特别小心字节顺序,理解了字节顺序在可以帮助我们写出移植行更高的代码.
正因为有字节顺序的差别,所以在网络传输的时候定义了所有字节顺序相关的数据都使用big-endian,BSD的代码中定义了四个宏来处理:
#define ntohs(n) //网络字节顺序到主机字节顺序 n代表net, h代表host, s代表short
#define htons(n) //主机字节顺序到网络字节顺序 n代表net, h代表host, s代表short
#define ntohl(n) //网络字节顺序到主机字节顺序 n代表net, h代表host, s代表 long
#define htonl(n) //主机字节顺序到网络字节顺序 n代表net, h代表host, s代表 long

举例说明下这其中一个宏的实现:
#define sw16(x) \
((short)( \
(((short)(x) & (short)0x00ffU) << 8) | \
(((short)(x) & (short)0xff00U) >> 8) ))
这里实现的是一个交换两个字节顺序.其他几个宏类似.

我们改写一下上面的程序
#include
#include

#define sw16(x) \
((short)( \
(((short)(x) & (short)0x00ffU) << 8) | \
(((short)(x) & (short)0xff00U) >> 8) ))

// 因为x86下面是低位在前,需要交换一下变成网络字节顺序
#define htons(x) sw16(x)

void main( void )
{
short test;
FILE* fp;

test = htons(0x3132); //(31ASIIC码的’1’,32ASIIC码的’2’)
if ((fp = fopen ("c:\\test.txt", "wb")) == NULL)
assert(0);
fwrite(&test, sizeof(short), 1, fp);
fclose(fp);
}

如果在高字节在前的机器上,由于与网络字节顺序一致,所以我们什么都不干就可以了,只需要把#define htons(x) sw16(x)宏替换为 #define htons(x) (x).
一开始我在理解这个问题时,总在想为什么其他数据不用交换字节顺序?比如说我们write一块buffer到文件,最后终于想明白了,因为都是unsigned char类型一个字节一个字节的写进去,这个顺序是固定的,不存在字节顺序的问题,够笨啊..

2011年9月1日星期四

vc设置程序置顶

//设置对话框置顶,在OnInitDialog()函数或者其它的函数中响应。
SetWindowPos(&wndTopMost,10,1000,10,1000,SWP_NOMOVE|SWP_NOSIZE);

//设置SDI和MDI程序置顶,在OnMenuTop()虚函数中
::SetWindowPos(AfxGetMainWnd()->m_hWnd,HWND_ TopMost, 10,1000,10,1000,SWP_NOMOVE|SWP_NOSIZE);

利用WM_CTLCOLOR消息实现编辑控制(Edit Control)的文本与背景色的改变

首先要明白:WM_CTLCOLOR是一个由控制(Control)发送给它父窗口的通知消息(Notification message)。

实现步骤:
生成一个标准的单文档应用程序框架,假设应用程序的名称为Color。我将利用它的About对话框做示范。在About dialog中添加两个Edit control,设定其ID为IDC_EDIT1与IDC_EDIT2。

第一种方法(对应于IDC_EDIT1): 按照标准的Windows编程,由其父窗口的消息处理函数负责处理WM_CTLCOLOR消息。

1. 在CAboutDlg中添加一个数据成员:HBRUSH m_brMine;
2. 利用向导映射AboutDlg的WM_CTLCOLOR消息,产生函数:HBRUSH CAboutDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor);
pDC是AboutDlg的设备上下文,pWnd是AboutDlg中发送该消息的control指针,nCtlColor市Control的类型编码。对其进行如下修改:

HBRUSH CAboutDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
if ((pWnd->GetDlgCtrlID() == IDC_EDIT1) && (nCtlColor == CTLCOLOR_EDIT))
{
COLORREF clr = RGB(255,0,0);
pDC->SetTextColor(clr); //设置红色的文本
clr = RGB(0,0,0);
pDC->SetBkColor(clr); //设置黑色的背景
m_brMine = ::CreateSolidBrush(clr);
return m_brMine; //作为约定,返回背景色对应的刷子句柄
}
else
{
HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
return hbr;
}
}

第二种方法(对应于IDC_EDIT2):
利用MFC 4.0的新特性: Message reflection。

1.利用向导添加一个新的类:CColorEdit,基类为CEdit;
2.在CColorEdit中添加一个数据成员: HBRUSH m_bkBrush;
3.利用向导映射CColorEdit的"=WM_CTLCOLOR"消息,产生函数:

HBRUSH CColorEdit::CtlColor(CDC* pDC, UINT nCtlColor);

对其进行如下修改:

HBRUSH CColorEdit::CtlColor(CDC* pDC, UINT nCtlColor)
{
COLORREF clr = RGB(0,0,0);
pDC->SetTextColor(clr); //设置黑色的文本
clr = RGB(255,0,0);
pDC->SetBkColor(clr); //设置红色的背景
m_bkBrush = ::CreateSolidBrush(clr);
return m_bkBrush; //作为约定,返回背景色对应的刷子句柄
}

4.利用向导为IDC_EDIT2生成一个数据成员CColorEdit m_coloredit;
5.在定义CAboutDlg的color.cpp文件中加入:#include "coloredit.h"

利用WM_CTLCOLOR消息实现编辑控制(Edit Control)的文本与背景色的改变

首先要明白:WM_CTLCOLOR是一个由控制(Control)发送给它父窗口的通知消息(Notification message)。

实现步骤:
生成一个标准的单文档应用程序框架,假设应用程序的名称为Color。我将利用它的About对话框做示范。在About dialog中添加两个Edit control,设定其ID为IDC_EDIT1与IDC_EDIT2。

第一种方法(对应于IDC_EDIT1): 按照标准的Windows编程,由其父窗口的消息处理函数负责处理WM_CTLCOLOR消息。

1. 在CAboutDlg中添加一个数据成员:HBRUSH m_brMine;
2. 利用向导映射AboutDlg的WM_CTLCOLOR消息,产生函数:HBRUSH CAboutDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor);
pDC是AboutDlg的设备上下文,pWnd是AboutDlg中发送该消息的control指针,nCtlColor市Control的类型编码。对其进行如下修改:

HBRUSH CAboutDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
if ((pWnd->GetDlgCtrlID() == IDC_EDIT1) && (nCtlColor == CTLCOLOR_EDIT))
{
COLORREF clr = RGB(255,0,0);
pDC->SetTextColor(clr); //设置红色的文本
clr = RGB(0,0,0);
pDC->SetBkColor(clr); //设置黑色的背景
m_brMine = ::CreateSolidBrush(clr);
return m_brMine; //作为约定,返回背景色对应的刷子句柄
}
else
{
HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
return hbr;
}
}

第二种方法(对应于IDC_EDIT2):
利用MFC 4.0的新特性: Message reflection。

1.利用向导添加一个新的类:CColorEdit,基类为CEdit;
2.在CColorEdit中添加一个数据成员: HBRUSH m_bkBrush;
3.利用向导映射CColorEdit的"=WM_CTLCOLOR"消息,产生函数:

HBRUSH CColorEdit::CtlColor(CDC* pDC, UINT nCtlColor);

对其进行如下修改:

HBRUSH CColorEdit::CtlColor(CDC* pDC, UINT nCtlColor)
{
COLORREF clr = RGB(0,0,0);
pDC->SetTextColor(clr); //设置黑色的文本
clr = RGB(255,0,0);
pDC->SetBkColor(clr); //设置红色的背景
m_bkBrush = ::CreateSolidBrush(clr);
return m_bkBrush; //作为约定,返回背景色对应的刷子句柄
}

4.利用向导为IDC_EDIT2生成一个数据成员CColorEdit m_coloredit;
5.在定义CAboutDlg的color.cpp文件中加入:#include "coloredit.h"

vc 添加打开文件对话框并读取文件

.创建打开文件对话框:
CFileDialog dlg(TRUE,//TRUE是创建打开文件对话框,FALSE则创建的是保存文件对话框
".txt",//默认的打开文件的类型
NULL,//默认打开的文件名
OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,//打开只读文件
"文本文件(*.txt)|*.txt|所有文件 (*.*)|*.*||");//所有可以打开的文件类型
2.点打开文件对话框上面的确定键后
if(dlg.DoModal()==IDOK)
{
CString m_FilePath = dlg.GetPathName();////////取出文件路径
CString m_path;
m_path=m_FilePath;//将文件的路径放入m_path
UpdateData(FALSE);
}
3.打开文件:File.Open(m_path,CFile::modeRead);
4.逐行读取文件:CStdioFile File;///可以逐行读文件的类
CString strLine;
while(File.ReadString(strLine)) //////将每行都放进strLine字符串里
{
AfxMessgeBox(strLine);
}
5判断读出来的字:
strLine=“1|2|3|”;//要判断的字符串
int strIndex1 = strLine.Find('|');//在字符串中寻找“|”
CString a[11];
if(-1 != strIndex1)//只要找到“|”就不会返回-1
{
int i=0;
while( -1 != strIndex1)//
{
strIndex1 = strLine.Find('|');
a[i] = strLine.Left(strIndex1);
strLine = strLine.Right(strLine.GetLength() - strIndex1-1) ;
i++;
if (i > 10)//退出循环
break;
}
}

VC中调用外部程序方式总结

目前知道三种方式:WinExec,ShellExecute ,CreateProcess,别人已经总结的很好了《vc中调用其他应用程序的方法(函数) winexec,shellexecute ,createprocess》,我全文转载一下,另外后面加点自己的总结(黑体部分,除了标题)。
三个SDK函数: WinExec,ShellExecute ,CreateProcess可以实现调用其他程序的要求,其中以WinExec最为简单,ShellExecute比WinExec灵活一些,CreateProcess最为复杂。
WinExec 两个参数,前一个指定路径,后一个指定显示方式。
ShellExecute 可以指定工作目录,并且还可以寻找文件的关联直接打开不用加载与文件关联的应用程序,ShellExecute还可以打开网页,启动相应的邮件关联发送邮件等等。
CreateProcess 一共有十个参数,不过大部分都可以用NULL代替,它可以指定进程的安全属性,继承信息,类的优先级等等。如果我们要得到足够多的关于新的进程的信息,控制新的进程的细节属性,若要达到这些目的,我们就需要使用CreateProcess函数了。
三个SDK函数( WinExec、ShellExec、CrateProcess )的语法:
(一)WinExec
这个函数最简单,只有两个参数,原型如下:
UINT WinExec(
LPCSTR lpCmdLine, // 命令路径
UINT uCmdShow // 显示方式
);
使用方法如下:
WinExec("Notepad.exe", SW_SHOW); // 打开记事本
WinExec("D:\\Program Files\\Test\\Test.exe",SW_SHOWMAXIMIZED); // 以最大化的方式打开Test.exe
需要注意的是若用 SW_SHOWMAXMIZED 方式去加载一个无最大化按钮的程序,譬如Neterm,Calc 等等,就不会出现正常的 窗体,但是已经被加到任务列表里了。
这个函数只能打开exe文件。
需要的头文件:windows.h,winbase.h(前者是试验出来,后者是msdn上说明),另外,这两者的先后顺序不能变。
msdn上的说明:[url]http://msdn.microsoft.com/en-us/library/ms687393[/url](VS.85).aspx
(二)ShellExecute
原型如下:
HINSTANCE ShellExecute(
HWND hwnd, //父窗口句柄
LPCTSTR lpOperation, //操作, 打开方式 "edit","explore","open","find","print","NULL"
LPCTSTR lpFile, //文件名,前面可加路径
LPCTSTR lpParameters, //参数
LPCTSTR lpDirectory, //默认文件夹
INT nShowCmd //显示方式
);
使用方法如下:
ShellExecute(NULL,"open","C:\\Test.txt",NULL,NULL,SW_SHOWNORMAL); // 打开C:\Test.txt 文件
ShellExecute(NULL, "open", "[url]http://www.google.com/[/url]", NULL, NULL, SW_SHOWNORMAL); // 打开网页[url]www.google.com[/url]
ShellExecute(NULL,"explore", "D:\\C++",NULL,NULL,SW_SHOWNORMAL); // 打开目录D:\C++
ShellExecute(NULL,"print","C:\\Test.txt",NULL,NULL, SW_HIDE); // 打印文件C:\Test.txt
ShellExecute不支持定向输出。
这个函数可以打开任意文件,会调用系统注册的程序来打开对应后缀名的文件。
需要的头文件:windows.h,shellapi.h(前者是我试验出来的,后者是msdn说需要的)。另外这两者的先后顺序不能变。
msdn上说明:[url]http://msdn.microsoft.com/en-us/library/bb762153[/url](VS.85).aspx
(三)CreateProcess
原型如下:
BOOL CreateProcess(
LPCTSTR lpApplicationName, //执行程序名
LPTSTR lpCommandLine, // 参数行
//下面两个参数描述了所创建的进程和线程的安全属性,如果为NULL则使用默认的安全属性
LPSECURITY_ATTRIBUTES lpProcessAttributes, // process security attributes
LPSECURITY_ATTRIBUTES lpThreadAttributes, // thread security attributes
BOOL bInheritHandles, // 继承标志
DWORD dwCreationFlags, // 创建标志
LPVOID lpEnvironment, // 环境变量
LPCTSTR lpCurrentDirectory, // 运行该进程的初始目录
LPSTARTUPINFO lpStartupInfo, // 用于在创建子进程时设置各种属性
LPPROCESS_INFORMATION lpProcessInformation //用于在进程创建后接受相关信息
);
使用方法如下:
PROCESS_INFORMATION pi;
STARTUPINFO si;
memset(&si,0,sizeof(si));
si.cb=sizeof(si);
si.wShowWindow=SW_SHOW;
si.dwFlags=STARTF_USESHOWWINDOW;
bool fRet=CreateProcess("D:\\putty.exe",NULL,NULL,FALSE,NULL,NULL,NULL,NULL,&si,&pi);
这个函数可以打开任意文件,会调用系统注册的程序来打开对应后缀名的文件。
需要的头文件:windows.h,winbase.h(前者是试验出来,后者是msdn上说明),另外,这两者的先后顺序不能变。
msdn上的说明:[url]http://msdn.microsoft.com/en-us/library/ms682425[/url](VS.85).aspx
可以看出,通过上面的几个不同的方法,都可以实现在应用程序中打开其他应用程序的目的,其中有些方法可能会麻烦一点,所以就需要我们根据不同的目的去选择最适合自己的方法去实现自己的目的!
关于三个SDK函数: WinExec, ShellExecute,CreateProcess 的其他注意事项:
1、定义头文件
原作者的内容删去。
这个是引用新函数都必须注意的内容。但是MS的头文件引用顺序有点怪,比如上面的三种清理。另外,如果用了预编译,那么记得在任何源程序中的#include “stdafx.h”之前的引用都会失效,从其后才生效。(不可否认,预编译有他的好处,尤其当程序很大的时候,但是任何好处都是要付出代价的)
2、定义路径
C++中所表示的路径要用 " \\ "而不是平常所用的" \ ",所以以上三个函数表示路径都为:
Disk:\\Directory\\...\\File name
WinExec("D:\\Program Files\\Test\\Test.exe",SW_SHOWMAXIMIZED);
ShellExecute(NULL,"open","C:\\Test.txt",NULL,NULL,SW_SHOWNORMAL);
bool fRet=CreateProcess("D:\\putty.exe",NULL,NULL,FALSE,NULL,NULL,NULL,NULL,&si,&pi)
3、注意文件的路径
在程序a调用程序b的时候,b原来的默认的当前路径都会变成a的当前路径。所以,一定要注意。
可以养成使用绝对路径的习惯,另外,记得打开文件之类的操作,一定要验证是否有错。

MFC中建个Cmd控制台

1.初始化的时候
AllocConsole()

2.在想输出内容到 控制台窗口的时候调用
int _cprintf(const char *, ...);


3.使用完了释放
FreeConsole()

用 avrdude 燒錄 Arduino Sketch

這篇說明如何用 avrdude 燒錄 Arduino Sketch,以下指令的方式燒錄韌體。

用 Arduino IDE 就可以燒錄韌體了,而且很方便,只要按個 upload 鍵就行了,為什麼還要學下指令的方式燒錄韌體呢?理由很簡單,其實 Arduino IDE 也是透過 avrdude 進行韌體燒錄的工作,下指令可以讓我們知道更多技術細節。

設定 PATH 環境變數

首先,為了使用 avrdude,你必須先把底下幾個路徑加到 PATH 環境變數裏:

C:\arduino-00xx\hardware\tools\avr\bin;
C:\arduino-00xx\hardware\tools\avr\utils\bin;
C:\arduino-00xx\hardware\tools\avr\etc

其中,arduino-00xx 是 Arduino IDE 的版本號碼,例如 arduino-0021。

燒錄 Arduino Sketch

以 Blink 為例,當你下底下這行指令時,avrdude 會把 Blink.cpp.hex 燒錄到 Arduino 板子上:

avrdude -q -c stk500v1 -P com4 -b 57600 -p atmega328p -U flash:w:Blink.cpp.hex:i

這行指令在做什麼呢?

● -q

省略燒錄訊息。如果你想看燒錄過程中的資訊,可以把 -q 換成 -v 選項。

● –c stk500v1

使用 stk500v1 協定燒錄程式。Arduino 大部份 bootloader 用的都是講 stk500v1 的協定。

● –P com4 –b 57600

使用 COM4 並且以 57600 bps 的 baud rate 速率。如果你的 Serial port 不是 COM4,請適當調整。關於 baud rate 的設定,稍後會補充說明。

● –p atmega328p

使用 atmega328p 晶片。你必須知道你 Arduino 板子所用的 AVR 晶片為何。

● –U flash:w:Blink.cpp.hex:i

把 Blink.cpp.hex 寫到 Flash 中。最後的小寫 i 代表 intel hex format,可省略。

要怎麼取得 Arduino IDE 產生的 HEX 檔呢?這部份請參考「Arduino IDE Tweak (開發環境調校)」或「Arduino 產生的 HEX 檔」。

底下是實際操作畫面:


▲ Blink.cpp.hex 上傳到 Arduino 板子後,pin 13 上的 LED 就會開始閃爍

查詢適當的 baud rate

前面的範例使用 baud rate 是 57600 bps,其實並不是所有 Arduino 都用 57600。那麼要怎麼知道你的 Arduino 板子所用的 baud rate 是多少呢?答案是到 "arduino-00xx\hardware\arduino\boards.txt" 這個檔案裏查詢。

我用的板子是 Arduino Duemilanove,在 boards.txt 裏有這麼一筆記錄:

1
atmega328.name=Arduino Duemilanove or Nano w/ ATmega328
2

3
atmega328.upload.protocol=stk500
4
atmega328.upload.maximum_size=30720
5
atmega328.upload.speed=57600

從這裏我就可以知道 Duemilanove 所用的燒錄速度是 57600 bps。其它 Arduino 板子的燒錄速度也都可以在 boards.txt 裏查出,例如 Diecimila 用的是 19200, Mega (Atmega1280) 用的是 57600,而較新款的 UNO 和 Mega 2560 則使用 115200。

用其它 ISP 燒錄韌體

除了透過 Arduino 的 bootloader 燒錄的方法外,avrdude 也支援其它 ISP (In System Programmer) 燒錄器,支援的種類很多,例如 AVR Dragon, USBTiny, avrispmkii 以及 arduinoisp 等。

以走 USB 介面的 AVR dragon 為例,燒錄 Flash 的指令是:

avrdude -c dragon_isp -P usb -p atmega328p -U flash:w:Blink.cpp.hex

如果你把 Arduino 當成 ISP 用,燒錄的指令則是:

avrdude -q -c stk500v1 -P com4 -b 57600 -p atmega328p -U flash:w:Blink.cpp.hex:i

注意!這行指令跟最前面介紹的是一樣的,不過 Arduino ISP 硬體接法不一樣,而且結果也不同。這部份請參考「Arduino 當成一個 AVR ISP (In-System Programmer) 使用 (3)」的說明。

另外,用 ISP 直接把 Arduino Sketch 燒錄到板子上,這種方式沒有用到 bootloader,這讓你得以使用 ATmega 晶片全部的程式空間 (program space)。