现象:
当你编译一个ATL工程的Release版时,你得到了下面这个链接错误:
LIBCMT.LIB(crt0.obj) : error LNK2001: unresolved external symbol _main
如下图所示:
而Debug版本的编连却顺利通过。
原因与解决方法:
出错原因:
如果你在工程中使用了CRT函数,而这些函数又需要CRT启动代码,就会出现这种链接错误。默认情况下,Release配置的Preprocessor definitions中定义了_ATL_MIN_CRT,它将CRT启动代码从你的EXE或DLL剔出去了。
背景知识:
1:
ATL支持把一个服务器编连优化成最小尺寸或者依赖性最小。我们可以定义三个预处理器符号来影响服务器的优化。
_ATL_MIN_CRT 服务器不链接标准的C/C++运行库
_ATL_DLL 服务器动态链接工具函数库atl.dll
_ATL_STATIC_REGISTRY 服务器静态链接对组件注册的支持
如果定义了预处理器符号_ATL_MIN_CRT,那么我们的服务器不链接C/C++运行库,并且ATL提供了函数malloc、realloc、new和delete的一个实现。当定义了这个符号时,我们不能调用任何其他的C/C++运行库的函数。否则,就会受到这样的待遇:
LIBCMT.LIB(crt0.obj) : error LNK2001: unresolved external symbol _main
ATL向导生成的ATL工程为所有的Release版本的编连定义了_ATL_MIN_CRT,但是没有为Debug版本定义这个符号。
Debug配置没有定义这三个符号中的任何一个。
RelMinSize配置定义了_ATL_MIN_CRT和_ATL_DLL。
RelMinDependency配置定义了_ATL_MIN_CRT和_ATL_STATIC_REGISTRY。
2:
C Run-Time Library (without iostream)
Characteristics
Option
Defined
LIBC.LIB
a statically linked library for single-threaded programs
(Single threaded, static link)
/ML
LIBCMT.LIB
a statically linked library that supports multithreaded programs
(Multithreaded, static link)
/MT
_MT
MSVCRT.LIB
Multithreaded, dynamic link (import library for MSVCRT.DLL)
/MD
_MT, _DLL
解决方法:
下面方法中的任何一个都可以纠正这个错误:
Ø 去除_ATL_MIN_CRT这个预处理符号;
Ø 打开stdafx.cpp,注释掉#include <atlimpl.cpp>这句话,然后编译,即可;
Ø 在工程的配置对话框的Link页面上,"ignore libraries"编辑框中输入Libcmt.lib,然后编译,如下图所示:
你将会得到几个“unresolved external”的错误,如下所示。
这个列表就是你用到的CRT的函数。
Look for things that you think may be pulling in the startup code and remove them if you can.Instead, use their Win32 equivalents. For example, use lstrcmp() instead of strcmp(). Known functions that require CRT startup code are some of the string and floating point functions.
其他:
我的VC IDE是6.0版本和SP5,如果用ATL COM AppWizard创建Service (EXE)工程。在这种情况下,它的RelMinDependency版本的配置中就没有定义_ATL_MIN_CRT符号!这和微软声称的“Service EXE Created with ATL COM AppWizard Doesn't Build in Release Mode”不一样,可能这是一个已经被FIX了的Bug。
Written by zhengyun
参考文献:
1. 《INFO: Active Template Library (ATL) 2.0 Readme File [Q165259]》
2. 《INFO: LNK2001 on CRT Symbols in ATL Release Build [Q165076]》
re: VC中Combo Box控件使用大全 isabc 2008-02-21 22:00
VC++ Combo Box/Combo Box Ex控件
组合窗口是由一个输入框和一个列表框组成。创建一个组合窗口可以使用成员函数:
BOOL CListBox::Create( LPCTSTR lpszText, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID = 0xffff );
其中dwStyle将指明该窗口的风格,除了子窗口常用的风格WS_CHILD,WS_VISIBLE外,你可以针对列表控件指明专门的风格。
CBS_DROPDOWN 下拉式组合框
CBS_DROPDOWNLIST 下拉式组合框,但是输入框内不能进行输入
CBS_SIMPLE 输入框和列表框同时被显示
LBS_SORT 所有的行按照字母顺序进行排序
由于组合框内包含了列表框,所以列表框的功能都能够使用,如可以利用:
int AddString( LPCTSTR lpszItem )添加行,
int DeleteString( UINT nIndex )删除指定行,
int InsertString( int nIndex, LPCTSTR lpszItem )将行插入到指定位置。
void ResetContent( )可以删除列表框中所有行。
通过调用int GetCount( )得到当前列表框中行的数量。
如果需要得到/设置当前被选中的行的位置,可以调用int GetCurSel( )/int SetCurSel(int iIndex)。通过调用int GetLBText( int nIndex, LPTSTR lpszText )得到列表框内指定行的字符串。
此外通过调用int FindString( int nStartAfter, LPCTSTR lpszItem )可以在当前所有行中查找指定的字符传的位置,nStartAfter指明从那一行开始进行查找。
int SelectString( int nStartAfter, LPCTSTR lpszItem )可以选中包含指定字符串的行。
此外输入框的功能都能够使用,如可以利用:
DWORD GetEditSel( ) /BOOL SetEditSel( int nStartChar, int nEndChar )得到或设置输入框中被选中的字符位置。
BOOL LimitText( int nMaxChars )设置输入框中可输入的最大字符数。
输入框的剪贴板功能Copy,Clear,Cut,Paste动可以使用。
最后介绍一下列表框几种常用的消息映射宏:
ON_CBN_DBLCLK 鼠标双击
ON_CBN_DROPDOWN 列表框被弹出
ON_CBN_KILLFOCUS / ON_CBN_SETFOCUS 在输入框失去/得到输入焦点时产生
ON_CBN_SELCHANGE 列表框中选择的行发生改变
ON_CBN_EDITUPDATE 输入框中内容被更新
使用以上几种消息映射的方法为定义原型如:afx_msg void memberFxn( );的函数,并且定义形式如ON_Notification( id, memberFxn )的消息映射。如果在对话框中使用组合框,Class Wizard会自动列出相关的消息,并能自动产生消息映射代码。
在MFC 4.2中对组合框进行了增强,你可以在组合框中使用ImageList,有一个新的类CComboBoxEx(由CComboBox派生)来实现这一功能。在CComboBoxEx类中添加了一些新的成员函数来实现新的功能:首先你需要调用CImageList* SetImageList( CImageList* pImageList );来设置ImageList,然后调用
int InsertItem( const COMBOBOXEXITEM* pCBItem );来添加行,其中COMBOBOXEXITEM定义如下:
typedef struct { UINT mask; int iItem; LPTSTR pszText; int cchTextMax; int iImage; int iSelectedImage; int iOverlay; int iIndent; LPARAM lParam;} COMBOBOXEXITEM, *PCOMBOBOXEXITEM;
你需要设置mask=CBEIF_IMAGE CBEIF_TEXT,并设置iItem为插入位置,设置pszText为显示字符串,设置iImage为显示的图标索引。下面的代码演示了如何进行插入:
/*m_cbeWnd 为已经创建的CComboBox对象
m_list 为CImageList对象IDB_IMG 为16*(16*4)的位图,每个图片为16*16共4个图标*/
m_list.Create(IDB_IMG,16,4,RGB(0,0,0));
m_cbeWnd.SetImageList(&m_list);
COMBOBOXEXITEM insItem;insItem.mask=CBEIF_IMAGE CBEIF_TEXT;insItem.iItem=0; insItem.iImage=0;insItem.pszText="Line 1";m_cbeWnd.InsertItem(&insItem);insItem.iItem=1;insItem.iImage=1;insItem.pszText="Line 2";m_cbeWnd.InsertItem(&insItem);
通过调用int DeleteItem( int iIndex );来删除行,并指明行的位置。
通过调用BOOL GetItem( COMBOBOXEXITEM* pCBItem )/BOOL SetItem( const COMBOBOXEXITEM* pCBItem );来得到/设置行数据。
Network Working Group K. Egevang
Request for Comments: 1631 Cray Communications
Category: Informational P. Francis
NTT
May 1994
The IP Network Address Translator (NAT)
Status of this Memo
This memo provides information for the Internet community. This memo
does not specify an Internet standard of any kind. Distribution of
this memo is unlimited.
Abstract
The two most compelling problems facing the IP Internet are IP
address depletion and scaling in routing. Long-term and short-term
solutions to these problems are being developed. The short-term
solution is CIDR (Classless InterDomain Routing). The long-term
solutions consist of various proposals for new internet protocols
with larger addresses.
It is possible that CIDR will not be adequate to maintain the IP
Internet until the long-term solutions are in place. This memo
proposes another short-term solution, address reuse, that complements
CIDR or even makes it unnecessary. The address reuse solution is to
place Network Address Translators (NAT) at the borders of stub
domains. Each NAT box has a table consisting of pairs of local IP
addresses and globally unique addresses. The IP addresses inside the
stub domain are not globally unique. They are reused in other
domains, thus solving the address depletion problem. The globally
unique IP addresses are assigned according to current CIDR address
allocation schemes. CIDR solves the scaling problem. The main
advantage of NAT is that it can be installed without changes to
routers or hosts. This memo presents a preliminary design for NAT,
and discusses its pros and cons.
Acknowledgments
This memo is based on a paper by Paul Francis (formerly Tsuchiya) and
Tony Eng, published in Computer Communication Review, January 1993.
Paul had the concept of address reuse from Van Jacobson.
Kjeld Borch Egevang edited the paper to produce this memo and
introduced adjustment of sequence-numbers for FTP. Thanks to Jacob
Michael Christensen for his comments on the idea and text (we thought
for a long time, we were the only ones who had had the idea).
1. Introduction
The two most compelling problems facing the IP Internet are IP
address depletion and scaling in routing. Long-term and short-term
solutions to these problems are being developed. The short-term
solution is CIDR (Classless InterDomain Routing) [2]. The long-term
solutions consist of various proposals for new internet protocols
with larger addresses.
Until the long-term solutions are ready an easy way to hold down the
demand for IP addresses is through address reuse. This solution takes
advantage of the fact that a very small percentage of hosts in a stub
domain are communicating outside of the domain at any given time. (A
stub domain is a domain, such as a corporate network, that only
handles traffic originated or destined to hosts in the domain).
Indeed, many (if not most) hosts never communicate outside of their
stub domain. Because of this, only a subset of the IP addresses
inside a stub domain, need be translated into IP addresses that are
globally unique when outside communications is required.
This solution has the disadvantage of taking away the end-to-end
significance of an IP address, and making up for it with increased
state in the network. There are various work-arounds that minimize
the potential pitfalls of this. Indeed, connection-oriented protocols
are essentially doing address reuse at every hop.
The huge advantage of this approach is that it can be installed
incrementally, without changes to either hosts or routers. (A few
unusual applications may require changes). As such, this solution can
be implemented and experimented with quickly. If nothing else, this
solution can serve to provide temporarily relief while other, more
complex and far-reaching solutions are worked out.
2. Overview of NAT
The design presented in this memo is called NAT, for Network Address
Translator. NAT is a router function that can be configured as shown
in figure 1. Only the stub border router requires modifications.
NAT's basic operation is as follows. The addresses inside a stub
domain can be reused by any other stub domain. For instance, a single
Class A address could be used by many stub domains. At each exit
point between a stub domain and backbone, NAT is installed. If there
is more than one exit point it is of great importance that each NAT
has the same translation table.
\ | / . /
+---------------+ WAN . +-----------------+/
|Regional Router|----------------------|Stub Router w/NAT|---
+---------------+ . +-----------------+\
. | \
. | LAN
. ---------------
Stub border
Figure 1: NAT Configuration
For instance, in the example of figure 2, both stubs A and B
internally use class A address 10.0.0.0. Stub A's NAT is assigned the
class C address 198.76.29.0, and Stub B's NAT is assigned the class C
address 198.76.28.0. The class C addresses are globally unique no
other NAT boxes can use them.
\ | /
+---------------+
|Regional Router|
+---------------+
WAN | | WAN
| |
Stub A .............|.... ....|............ Stub B
| |
{s=198.76.29.7,^ | | v{s=198.76.29.7,
d=198.76.28.4}^ | | v d=198.76.28.4}
+-----------------+ +-----------------+
|Stub Router w/NAT| |Stub Router w/NAT|
+-----------------+ +-----------------+
| |
| LAN LAN |
------------- -------------
| |
{s=10.33.96.5, ^ | | v{s=198.76.29.7,
d=198.76.28.4}^ +--+ +--+ v d=10.81.13.22}
|--| |--|
/____\ /____\
10.33.96.5 10.81.13.22
Figure 2: Basic NAT Operation
When stub A host 10.33.96.5 wishes to send a packet to stub B host
10.81.13.22, it uses the globally unique address 198.76.28.4 as
destination, and sends the packet to it's primary router. The stub
router has a static route for net 198.76.0.0 so the packet is
forwarded to the WAN-link. However, NAT translates the source address
10.33.96.5 of the IP header with the globally unique 198.76.29.7
before the package is forwarded. Likewise, IP packets on the return
path go through similar address translations.
Notice that this requires no changes to hosts or routers. For
instance, as far as the stub A host is concerned, 198.76.28.4 is the
address used by the host in stub B. The address translations are
completely transparent.
Of course, this is just a simple example. There are numerous issues
to be explored. In the next section, we discuss various aspects of
NAT.
3. Various Aspects of NAT
3.1 Address Spaces
Partitioning of Reusable and Non-reusable Addresses
For NAT to operate properly, it is necessary to partition the IP
address space into two parts - the reusable addresses used internal
to stub domains, and the globally unique addresses. We call the
reusable address local addresses, and the globally unique addresses
global addresses. Any given address must either be a local address or
a global address. There is no overlap.
The problem with overlap is the following. Say a host in stub A
wished to send packets to a host in stub B, but the local addresses
of stub B overlapped the local addressees of stub A. In this case,
the routers in stub A would not be able to distinguish the global
address of stub B from its own local addresses.
Initial Assignment of Local and Global Addresses
A single class A address should be allocated for local networks. (See
RFC1597 [3].) This address could then be used for internets with no
connection to the Internet. NAT then provides an easy way to change
an experimental network to a "real" network by translating the
experimental addresses to globally unique Internet addresses.
Existing stubs which have unique addresses assigned internally, but
are running out of them, can change addresses subnet by subnet to
local addresses. The freed adresses can then be used by NAT for
external communications.
3.2 Routing Across NAT
The router running NAT should never advertise the local networks to
the backbone. Only the networks with global addresses may be known
outside the stub. However, global information that NAT receives from
the stub border router can be advertised in the stub the usual way.
Private Networks that Span Backbones
In many cases, a private network (such as a corporate network) will
be spread over different locations and will use a public backbone for
communications between those locations. In this case, it is not
desirable to do address translation, both because large numbers of
hosts may want to communicate across the backbone, thus requiring
large address tables, and because there will be more applications
that depend on configured addresses, as opposed to going to a name
server. We call such a private network a backbone-partitioned stub.
Backbone-partitioned stubs should behave as though they were a non-
partitioned stub. That is, the routers in all partitions should
maintain routes to the local address spaces of all partitions. Of
course, the (public) backbones do not maintain routes to any local
addresses. Therefore, the border routers must tunnel through the
backbones using encapsulation. To do this, each NAT box will set
aside one global address for tunneling. When a NAT box x in stub
partition X wishes to deliver a packet to stub partition Y, it will
encapsulate the packet in an IP header with destination address set
to the global address of NAT box y that has been reserved for
encapsulation. When NAT box y receives a packet with that destination
address, it decapsulates the IP header and routes the packet
internally.
3.3 Header Manipulations
In addition to modifying the IP address, NAT must modify the IP
checksum and the TCP checksum. Remember, TCP's checksum also covers a
pseudo header which contains the source and destination address. NAT
must also look out for ICMP and FTP and modify the places where the
IP address appears. There are undoubtedly other places, where
modifications must be done. Hopefully, most such applications will be
discovered during experimentation with NAT.
The checksum modifications to IP and TCP are simple and efficient.
Since both use a one's complement sum, it is sufficient to calculate
the arithmetic difference between the before-translation and after-
translation addresses and add this to the checksum. The only tricky
part is determining whether the addition resulted in a wrap-around
(in either the positive or negative direction) of the checksum. If
so, 1 must be added or subtracted to satisfy the one's complement
arithmetic. Sample code (in C) for this is as follows:
void checksumadjust(unsigned char *chksum, unsigned char *optr,
int olen, unsigned char *nptr, int nlen)
/* assuming: unsigned char is 8 bits, long is 32 bits.
- chksum points to the chksum in the packet
- optr points to the old data in the packet
- nptr points to the new data in the packet
*/
{
long x, old, new;
x=chksum[0]*256+chksum[1];
x=~x;
while (olen) {
if (olen==1) {
old=optr[0]*256+optr[1];
x-=old & 0xff00;
if (x<=0) { x--; x&=0xffff; }
break;
}
else {
old=optr[0]*256+optr[1]; optr+=2;
x-=old & 0xffff;
if (x<=0) { x--; x&=0xffff; }
olen-=2;
}
}
while (nlen) {
if (nlen==1) {
new=nptr[0]*256+nptr[1];
x+=new & 0xff00;
if (x & 0x10000) { x++; x&=0xffff; }
break;
}
else {
new=nptr[0]*256+nptr[1]; nptr+=2;
x+=new & 0xffff;
if (x & 0x10000) { x++; x&=0xffff; }
nlen-=2;
}
}
x=~x;
chksum[0]=x/256; chksum[1]=x & 0xff;
}
The arguments to the File Transfer Protocol (FTP) PORT command
include an IP address (in ASCII!). If the IP address in the PORT
command is local to the stub domain, then NAT must substitute this.
Because the address is encoded in ASCII, this may result in a change
in the size of the packet (for instance 10.18.177.42 is 12 ASCII
characters, while 193.45.228.137 is 14 ASCII characters). If the new
size is the same as the previous, only the TCP checksum needs
adjustment (again). If the new size is less than the previous, ASCII
zeroes may be inserted, but this is not guaranteed to work. If the
new size is larger than the previous, TCP sequence numbers must be
changed too.
A special table is used to correct the TCP sequence and acknowledge
numbers with source port FTP or destination port FTP. The table
entries should have source, destination, source port, destination
port, initial sequence number, delta for sequence numbers and a
timestamp. New entries are created only when FTP PORT commands are
seen. The initial sequence numbers are used to find out if the
sequence number of a packet is before or after the last FTP PORT
command (delta may be increased for every FTP PORT command). Sequence
numbers are incremented and acknowledge numbers are decremented. If
the FIN bit is set in one of the packets, the associated entry may be
deleted soon after (1 minute should be safe). Entries that have not
been used for e.g. 24 hours should be safe to delete too.
The sequence number adjustment must be coded carefully, not to harm
performance for TCP in general. Of course, if the FTP session is
encrypted, the PORT command will fail.
If an ICMP message is passed through NAT, it may require two address
modifications and three checksum modifications. This is because most
ICMP messages contain part of the original IP packet in the body.
Therefore, for NAT to be completely transparent to the host, the IP
address of the IP header embedded in the data part of the ICMP packet
must be modified, the checksum field of the same IP header must
correspondingly be modified, and the ICMP header checksum must be
modified to reflect the changes to the IP header and checksum in the
ICMP body. Furthermore, the normal IP header must also be modified as
already described.
It is not entirely clear if the IP header information in the ICMP
part of the body really need to be modified. This depends on whether
or not any host code actually looks at this IP header information.
Indeed, it may be useful to provide the exact header seen by the
router or host that issued the ICMP message to aid in debugging. In
any event, no modifications are needed for the Echo and Timestamp
messages, and NAT should never need to handle a Redirect message.
SNMP messages could be modified, but it is even more dubious than for
ICMP messages that it will be necessary.
Applications with IP-address Content
Any application that carries (and uses) the IP address inside the
application will not work through NAT unless NAT knows of such
instances and does the appropriate translation. It is not possible or
even necessarily desirable for NAT to know of all such applications.
And, if encryption is used then it is impossible for NAT to make the
translation.
It may be possible for such systems to avoid using NAT, if the hosts
in which they run are assigned global addresses. Whether or not this
can work depends on the capability of the intra-domain routing
algorithm and the internal topology. This is because the global
address must be advertised in the intra-domain routing algorithm.
With a low-feature routing algorithm like RIP, the host may require
its own class C address space, that must not only be advertised
internally but externally as well (thus hurting global scaling). With
a high-feature routing algorithm like OSPF, the host address can be
passed around individually, and can come from the NAT table.
Privacy, Security, and Debugging Considerations
Unfortunately, NAT reduces the number of options for providing
security. With NAT, nothing that carries an IP address or information
derived from an IP address (such as the TCP-header checksum) can be
encrypted. While most application-level encryption should be ok, this
prevents encryption of the TCP header.
On the other hand, NAT itself can be seen as providing a kind of
privacy mechanism. This comes from the fact that machines on the
backbone cannot monitor which hosts are sending and receiving traffic
(assuming of course that the application data is encrypted).
The same characteristic that enhances privacy potentially makes
debugging problems (including security violations) more difficult. If
a host is abusing the Internet is some way (such as trying to attack
another machine or even sending large amounts of junk mail or
something) it is more difficult to pinpoint the source of the trouble
because the IP address of the host is hidden.
4. Conclusions
NAT may be a good short term solution to the address depletion and
scaling problems. This is because it requires very few changes and
can be installed incrementally. NAT has several negative
characteristics that make it inappropriate as a long term solution,
and may make it inappropriate even as a short term solution. Only
implementation and experimentation will determine its
appropriateness.
The negative characteristics are:
1. It requires a sparse end-to-end traffic matrix. Otherwise, the NAT
tables will be large, thus giving lower performance. While the
expectation is that end-to-end traffic matrices are indeed sparse,
experience with NAT will determine whether or not they are. In any
event, future applications may require a rich traffic matrix (for
instance, distributed resource discovery), thus making long-term use
of NAT unattractive.
2. It increases the probability of mis-addressing.
3. It breaks certain applications (or at least makes them more difficult
to run).
4. It hides the identity of hosts. While this has the benefit of
privacy, it is generally a negative effect.
5. Problems with SNMP, DNS, ... you name it.
Current Implementations
Paul and Tony implemented an experimental prototype of NAT on public
domain KA9Q TCP/IP software [1]. This implementation manipulates
addresses and IP checksums.
Kjeld implemented NAT in a Cray Communications IP-router. The
implementation was tested with Telnet and FTP. This implementation
manipulates addresses, IP checksums, TCP sequence/acknowledge numbers
and FTP PORT commands.
The prototypes has demonstrated that IP addresses can be translated
transparently to hosts within the limitations described in this
paper.
REFERENCES
[1] Karn, P., "KA9Q", anonymous FTP from ucsd.edu
(hamradio/packet/ka9q/docs).
[2] Fuller, V., Li, T., and J. Yu, "Classless Inter-Domain Routing
(CIDR) an Address Assignment and Aggregation Strategy", RFC1519,
BARRNet, cisco, Merit, OARnet, September 1993.
[3] Rekhter, Y., Moskowitz, B., Karrenberg, D., and G. de Groot,
"Address Allocation for Private Internets", RFC1597, T.J. Watson
Research Center, IBM Corp., Chrysler Corp., RIPE NCC, March 1994.
Security Considerations
Security issues are not discussed in this memo.
Authors' Addresses
Kjeld Borch Egevang
Cray Communications
Smedeholm 12-14
DK-2730 Herlev
Denmark
Phone: +45 44 53 01 00
EMail: kbe@craycom.dk
Paul Francis
NTT Software Lab
3-9-11 Midori-cho Musashino-shi
Tokyo 180 Japan
Phone: +81-422-59-3843
Fax +81-422-59-3765
re: 简单封装的串口通信类 isabc 2008-01-08 16:58
查询当前的超时设置应调用GetCommTimeouts函数,该函数会填充一个COMMTIMEOUTS结构。调用SetCommTimeouts可以用某一个COMMTIMEOUTS结构的内容来设置超时。
读写串口的超时有两种:间隔超时和总超时。间隔超时是指在接收时两个字符之间的最大时延。总超时是指读写操作总共花费的最大时间。写操作只支持总超时,而读操作两种超时均支持。用COMMTIMEOUTS结构可以规定读写操作的超时。
COMMTIMEOUTS结构的定义为: typedef struct _COMMTIMEOUTS {
DWORD ReadIntervalTimeout; //读间隔超时
DWORD ReadTotalTimeoutMultiplier; //读时间系数
DWORD ReadTotalTimeoutConstant; //读时间常量
DWORD WriteTotalTimeoutMultiplier; // 写时间系数
DWORD WriteTotalTimeoutConstant; //写时间常量
} COMMTIMEOUTS,*LPCOMMTIMEOUTS;
COMMTIMEOUTS结构的成员都以毫秒为单位。总超时的计算公式是:
总超时=时间系数×要求读/写的字符数+时间常量
例如,要读入10个字符,那么读操作的总超时的计算公式为:
读总超时=ReadTotalTimeoutMultiplier×10+ReadTotalTimeoutConstant
可以看出:间隔超时和总超时的设置是不相关的,这可以方便通信程序灵活地设置各种超时。
如果所有写超时参数均为0,那么就不使用写超时。如果ReadIntervalTimeout为0,那么就不使用读间隔超时。如果ReadTotalTimeoutMultiplier 和 ReadTotalTimeoutConstant 都为0,则不使用读总超时。如果读间隔超时被设置成MAXDWORD并且读时间系数和读时间常量都为0,那么在读一次输入缓冲区的内容后读操作就立即返回,而不管是否读入了要求的字符。
在用重叠方式读写串口时,虽然ReadFile和WriteFile在完成操作以前就可能返回,但超时仍然是起作用的。在这种情况下,超时规定的是操作的完成时间,而不是ReadFile和WriteFile的返回时间。
配置串口的示例代码: SetupComm(hCom,1024,1024); //输入缓冲区和输出缓冲区的大小都是1024
COMMTIMEOUTS TimeOuts;
//设定读超时
TimeOuts.ReadIntervalTimeout=1000;
TimeOuts.ReadTotalTimeoutMultiplier=500;
TimeOuts.ReadTotalTimeoutConstant=5000;
//设定写超时
TimeOuts.WriteTotalTimeoutMultiplier=500;
TimeOuts.WriteTotalTimeoutConstant=2000;
SetCommTimeouts(hCom,&TimeOuts); //设置超时
re: 简单封装的串口通信类 isabc 2008-01-08 10:09
HANDLE CreateEvent(
LPSECURITY_ATTRIBUTES lpEventAttributes,
// 指定对象的安全描述符,一般设为NULL (安全属性结构如下)
BOOL bManualReset, // 指定是否人工重置
BOOL bInitialState, // 返回的句柄是否可继承
LPCTSTR lpName // 对象的名字,用于多进程间共享对象
);
返回的为event对象的句柄
安全属性结构
typedef struct _SECURITY_ATTRIBUTES {
DWORD nLength;
LPVOID lpSecurityDescriptor;
BOOL bInheritHandle;
} SECURITY_ATTRIBUTES, *PSECURITY_ATTRIBUTES;
从网上整理的文章,同样,这只是为了我增加理解记忆而做到得笔记,
不存在利用价值,纯粹是学习和记忆.抄袭也好学习也好只是让人明
白道理.主要干活的还是自己的程序.
I/O设备处理必然让主程序停下来干等I/O的完成,
对这个问题有
方法一:使用另一个线程进行I/O。这个方案可行,但是麻烦。
方法二:使用overlapped I/O。
正如书上所说:“overlapped I/O是WIN32的一项技术,
你可以要求操作系统为你传送数据,并且在传送完毕时通知你。
这项技术使你的程序在I/O进行过程中仍然能够继续处理事务。
事实上,操作系统内部正是以线程来I/O完成overlapped I/O。
你可以获得线程的所有利益,而不需付出什么痛苦的代价”。
怎样使用overlapped I/O:
进行I/O操作时,指定overlapped方式
使用CreateFile (),将其第6个参数指定为FILE_FLAG_OVERLAPPED,
就是准备使用overlapped的方式构造或打开文件;
如果采用 overlapped,那么ReadFile()、WriteFile()的第5个参数必须提供一个指针,
指向一个OVERLAPPED结构。 OVERLAPPED用于记录了当前正在操作的文件一些相关信息。
//功能:从指定文件的1500位置读入300个字节
int main()
{
BOOL rc;
HANDLE hFile;
DWORD numread;
OVERLAPPED overlap;
char buf[512];
char szPath=”x:\\xxxx\xxxx”;
//检查系统,确定是否支持overlapped,(NT以上操作系统支持OVERLAPPED)
CheckOsVersion();
// 以overlapped的方式打开文件
hFile = CreateFile( szPath,
GENERIC_READ,
FILE_SHARE_READ|FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
NULL
);
// OVERLAPPED结构实始化为0
memset(&overlap, 0, sizeof(overlap));
//指定文件位置是1500;
overlap.Offset = 1500;
rc = ReadFile(hFile,buf,300,&numread,&overlap);
//因为是overlapped操作,ReadFile会将读文件请求放入读队列之后立即返回(false),
//而不会等到文件读完才返回(true)
if (rc)
{
//文件真是被读完了,rc为true
// 或当数据被放入cache中,或操作系统认为它可以很快速地取得数据,rc为true
}
else
{
if (GetLastError() == ERROR_IO_PENDING)
{//当错误是ERROR_IO_PENDING,那意味着读文件的操作还在进行中
//等候,直到文件读完
WaitForSingleObject(hFile, INFINITE);
rc = GetOverlappedResult(hFile,&overlap,&numread,FALSE);
//上面二条语句完成的功能与下面一条语句的功能等价:
// GetOverlappedResult(hFile,&overlap,&numread,TRUE);
}
else
{
//出错了
}
}
CloseHandle(hFile);
return EXIT_SUCCESS;
}
在实际工作中,若有几个操作同一个文件时,
怎么办?我们可以利用OVERLAPPED结构中提供的event来解决上面遇到的问题。
注意,你所使用的event对象必须是一个MANUAL型的;否则,可能产生竞争条件。
原因见书P159。
int main()
{
int i;
BOOL rc;
char szPath=”x:\\xxxx\xxxx”;
// 以overlapped的方式打开文件
ghFile = CreateFile( szPath,
GENERIC_READ,
FILE_SHARE_READ|FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
NULL
);
for (i=0; i<MAX_REQUESTS; i++)
{
//将同一文件按几个部分按overlapped方式同时读
//注意看QueueRequest函数是如何运做的,每次读16384个块
QueueRequest(i, i*16384, READ_SIZE);
}
// 等候所有操作结束;
//隐含条件:当一个操作完成时,其对应的event对象会被激活
WaitForMultipleObjects(MAX_REQUESTS, ghEvents, TRUE, INFINITE);
// 收尾操作
for (i=0; i<MAX_REQUESTS; i++)
{
DWORD dwNumread;
rc = GetOverlappedResult(
ghFile,
&gOverlapped[i],
&dwNumread,
FALSE
);
CloseHandle(gOverlapped[i].hEvent);
}
CloseHandle(ghFile);
return EXIT_SUCCESS;
}
//当读操作完成以后,gOverlapped[nIndex].hEvent会系统被激发
int QueueRequest(int nIndex, DWORD dwLocation, DWORD dwAmount)
{
//构造一个MANUAL型的event对象
ghEvents[nIndex] = CreateEvent(NULL, TRUE, FALSE, NULL);
//将此event对象置入OVERLAPPED结构
gOverlapped[nIndex].hEvent = ghEvents[nIndex];
gOverlapped[nIndex].Offset = dwLocation;
for (i=0; i<MAX_TRY_COUNT; i++)
{
//文件ghFile唯一
rc = ReadFile(ghFile, gBuffers[nIndex],&dwNumread,&gOverlapped[nIndex]);
if (rc)
return TRUE;
err = GetLastError();
if (err == ERROR_IO_PENDING)
{
//当错误是ERROR_IO_PENDING,那意味着读文件的操作还在进行中
return TRUE;
}
// 处理一些可恢复的错误
if ( err == ERROR_INVALID_USER_BUFFER ||
err == ERROR_NOT_ENOUGH_QUOTA ||
err == ERROR_NOT_ENOUGH_MEMORY )
{
sleep(50);
continue;//重试
}
// 如果GetLastError()返回的不是以上列出的错误,放弃
break;
}
return -1;
}
re: 简单封装的串口通信类 isabc 2008-01-07 21:11
在C语言中格式化字符串可以使用printf
但是在WINDOWS编程设计中却行不通了,但是却有变通的方法
那就是用 wsprintf这个函数 它的格式如下:
wsprintf(缓冲区,格式,要格式化的值);
第一个参数是字符缓冲区,后面是格式字符串,wsprintf不是将格式化结果写到标准输出,而是将其写入缓冲区中,该函数返回该字符串的长度。
比如我们想通过MessageBox来输出一个整形变量的值,可以用以下代码实现:
char szBuffer[100];
ing number=100;
wsprintf(szBuffer, “%d”,number);
MessgaeBox(NULL,szBrffer,TEXT(“格式化字符串”),0);
这个函数除了将内容格式化输出到第一个参数所提供的字符串缓冲区以外,其它功能与printf函数相同。