星期日, 十一月 11, 2007

MFC中常用类,宏,函数介绍

常用类

CRect:用来表示矩形的类,拥有四个成员变量:top left bottom right。分别表是左上角和右下角的坐标。可以通过以下的方法构造:
CRect( int l, int t, int r, int b ); 指明四个坐标
CRect( const RECT& srcRect ); 由RECT结构构造
CRect( LPCRECT lpSrcRect ); 由RECT结构构造
CRect( POINT point, SIZE size ); 有左上角坐标和尺寸构造
CRect( POINT topLeft, POINT bottomRight ); 有两点坐标构造。下面介绍几个成员函数:
int Width( ) const; 得到宽度
int Height( ) const; 得到高度
CSize Size( ) const; 得到尺寸
CPoint& TopLeft( ); 得到左上角坐标
CPoint& BottomRight( ); 得到右下角坐标
CPoint CenterPoint( ) const; 得当中心坐标
此外矩形可以和点(CPoint)相加进行位移,和另一个矩形相加得到“并”操作后的矩形。
CPoint:用来表示一个点的坐标,有两个成员变量:x y。 可以和另一个点相加。
CString:用来表示可变长度的字符串。使用CString可不指明内存大小,CString会根据需要自行分配。 下面介绍几个成员函数:
GetLength 得到字符串长度
GetAt 得到指定位置处的字符
operator + 相当于strcat
void Format( LPCTSTR lpszFormat, ... ); 相当于sprintf
Find 查找指定字符,字符串
Compare 比较
CompareNoCase 不区分大小写比较
MakeUpper 改为小写
MakeLower 改为大写
CStringArray:用来表示可变长度的字符串数组。数组中每一个元素为CString对象的实例。下面介绍几个成员函数:
Add 增加CString
RemoveAt 删除指定位置CString对象
RemoveAll 删除数组中所有CString对象
GetAt 得到指定位置的CString对象
SetAt 修改指定位置的CString对象
InsertAt 在某一位置插入CString对象

常用宏

RGB
TRACE
ASSERT
VERIFY

常用函数

CWindApp* AfxGetApp();
HINSTANCE AfxGetInstanceHandle( );
HINSTANCE AfxGetResourceHandle( );
int AfxMessageBox( LPCTSTR lpszText, UINT nType = MB_OK, UINT nIDHelp = 0 );用于弹出一个消息框。

VC快捷键

F1: 帮助

Ctrl+O :Open
Ctrl+P :Print
Ctrl+N :New
Ctrl+Shift+F2 :清除所有书签
F2 :上一个书签
Shift+F2 :上一个书签
Alt+F2 :编辑书签
Ctrl+F2 :添加/删除一个书签
F12 :Goto definition
Shift+F12 :Goto reference
Ctrl+'Num+' :Displays the next symbol definition or reference
Ctrl+'Num-' :Displays the previous symbol definition or reference
Ctrl+J/K :寻找上一个/下一个预编译条件
Ctrl+Shift+J/K :寻找上一个/下一个预编译条件并将这一块选定
Ctrl+End :文档尾
Ctrl+Shift+End :选定从当前位置到文档尾
Ctrl+Home :文档头
Ctrl+Shift+Home :选定从当前位置到文档头
Ctrl+B/Alt+F9 :编辑断点
Alt+F3/Ctrl+F :查找
F3 :查找下一个
Shift+F3 :查找上一个
Ctrl+]/Ctrl+E :寻找下一半括弧
Ctrl+Shift+] :寻找下一半括弧并选定括弧之间的部分(包括括弧)
Ctrl+Shift+E :寻找下一半括弧并选定括弧之间的部分(包括括弧)
F4 :寻找下一个错误/警告位置
Shift+F4 :寻找上一个错误/警告位置
Shift+Home :选定从当前位置到行首
Shift+End :选定从当前位置到行尾
Ctrl+L :剪切当前行
Ctrl+Shift+L :删除当前行
Alt+Shift+T :交换当前行和上一行
Ctrl+Alt+T :Brings up the completion list box
Shift+PageDown :选定从当前位置到下一页当前位置
Shift+PageUp :选定从当前位置到上一页当前位置
Ctrl+Shift+Space:显示函数参数的Tooltip
Ctrl+Z/Alt+Backspace :Undo
Ctrl+Shift+Z/Ctrl+Y :Redo
F8 :当前位置变成选定区域的头/尾(再移动光标或者点鼠标就会选定)
Ctrl+Shift+F8 :当前位置变成矩形选定区域的头/尾(再移动光标或者点鼠标就会选定)
Alt+F8 :自动格式重排
Ctrl+G :Goto
Ctlr+X/Shift+Del:Cut
Ctrl+C/Ctrl+Ins :Copy
Ctrl+V/Shift+Ins:Paste
Ctrl+U :将选定区域转换成小写
Ctrl+Shift+U :将选定区域转换成大写
Ctrl+F8 :当前行变成选定区域的头/尾(再移动上下光标或者点鼠标就会选定多行)
Ctrl+Shift+L :删除从当前位置到行尾
Ctrl+Shift+8 :将所有Tab变成`或者还原
Ctrl+T :显示变量类型
Ctrl+↑ :向上滚屏
Ctrl+↓ :向下滚屏
Ctrl+Del :删除当前单词的后半截(以光标为分割)
Ctrl+Backspace :删除当前单词的前半截(以光标为分割)
Ctrl+← :移到前一个单词
Ctrl+→ :移到后一个单词
Ctrl+Shift+← :选定当前位置到前一个单词
Ctrl+Shift+→ :选定当前位置到后一个单词
Ctrl+Shift+T :将本单词和上一个单词互换


Alt+0 :Workspace Window
Alt+2 :Output Window
Alt+3 :Watch Window
Alt+4 :Variables Window
Alt+5 :Registers Window
Alt+6 :Memory Window
Alt+7 :CallStack Window
Alt+8 :Disassembly Window
Ctrl+W :ClassWizard
Alt+Enter :属性

Alt+F7 :Project Settings

F7 :Build
Ctrl+F7 :Compile
Ctrl+F5 :Run
Ctrl+Break :Stops the build
F5 :Go
Ctrl+F10 :Run to cursor
F11 :step into
Alt+F10 :Apply codes changes
Ctrl+F9 :Enable/Disable a breakpoint
Alt+F11 :将 Memory Window 切换到下一种显示模式
Alt+Shift+F11 :将 Memory Window 切换到上一种显示模式
Ctrl+Shift+F9 :去掉所有断点
Ctrl+Shift+F5 :Restarts the program
Ctrl+Shift+F10 :将当前行设为下一条指令执行的行
Alt+Num* :滚动到当前指令
Shift+F11 :跳出当前函数
F9 :断点
F10 :step over
Shift+F5 :停止 Debugging
Ctrl+F11 :Switches between the source view and the disassembly view for this instruction
Alt+F12 :Queries on the selected object or current context

Alt+F6 :Toggles the docking feature for the window on/off
Shift+Esc :隐藏窗口



Ctrl+Shift+G :?
Ctrl+* :打开string table
Ctrl+Space :?
Ctrl+F3 :向下查找下一个
Ctrl+Shift+F3 :查找上一个
Ctrl+D :查找
Ctrl+I :向下查找下一个
Ctrl+Shift+I :查找上一个
F6 :?Activates the next pane
Shift+F6 :?Activates the previous pane
Ctrl+M :?Detects duplicate mnemonics in the resource
Alt +O : 头文件与cpp文件的交互显示

VC快捷键

F1: 帮助

Ctrl+O :Open
Ctrl+P :Print
Ctrl+N :New
Ctrl+Shift+F2 :清除所有书签
F2 :上一个书签
Shift+F2 :上一个书签
Alt+F2 :编辑书签
Ctrl+F2 :添加/删除一个书签
F12 :Goto definition
Shift+F12 :Goto reference
Ctrl+'Num+' :Displays the next symbol definition or reference
Ctrl+'Num-' :Displays the previous symbol definition or reference
Ctrl+J/K :寻找上一个/下一个预编译条件
Ctrl+Shift+J/K :寻找上一个/下一个预编译条件并将这一块选定
Ctrl+End :文档尾
Ctrl+Shift+End :选定从当前位置到文档尾
Ctrl+Home :文档头
Ctrl+Shift+Home :选定从当前位置到文档头
Ctrl+B/Alt+F9 :编辑断点
Alt+F3/Ctrl+F :查找
F3 :查找下一个
Shift+F3 :查找上一个
Ctrl+]/Ctrl+E :寻找下一半括弧
Ctrl+Shift+] :寻找下一半括弧并选定括弧之间的部分(包括括弧)
Ctrl+Shift+E :寻找下一半括弧并选定括弧之间的部分(包括括弧)
F4 :寻找下一个错误/警告位置
Shift+F4 :寻找上一个错误/警告位置
Shift+Home :选定从当前位置到行首
Shift+End :选定从当前位置到行尾
Ctrl+L :剪切当前行
Ctrl+Shift+L :删除当前行
Alt+Shift+T :交换当前行和上一行
Ctrl+Alt+T :Brings up the completion list box
Shift+PageDown :选定从当前位置到下一页当前位置
Shift+PageUp :选定从当前位置到上一页当前位置
Ctrl+Shift+Space:显示函数参数的Tooltip
Ctrl+Z/Alt+Backspace :Undo
Ctrl+Shift+Z/Ctrl+Y :Redo
F8 :当前位置变成选定区域的头/尾(再移动光标或者点鼠标就会选定)
Ctrl+Shift+F8 :当前位置变成矩形选定区域的头/尾(再移动光标或者点鼠标就会选定)
Alt+F8 :自动格式重排
Ctrl+G :Goto
Ctlr+X/Shift+Del:Cut
Ctrl+C/Ctrl+Ins :Copy
Ctrl+V/Shift+Ins:Paste
Ctrl+U :将选定区域转换成小写
Ctrl+Shift+U :将选定区域转换成大写
Ctrl+F8 :当前行变成选定区域的头/尾(再移动上下光标或者点鼠标就会选定多行)
Ctrl+Shift+L :删除从当前位置到行尾
Ctrl+Shift+8 :将所有Tab变成`或者还原
Ctrl+T :显示变量类型
Ctrl+↑ :向上滚屏
Ctrl+↓ :向下滚屏
Ctrl+Del :删除当前单词的后半截(以光标为分割)
Ctrl+Backspace :删除当前单词的前半截(以光标为分割)
Ctrl+← :移到前一个单词
Ctrl+→ :移到后一个单词
Ctrl+Shift+← :选定当前位置到前一个单词
Ctrl+Shift+→ :选定当前位置到后一个单词
Ctrl+Shift+T :将本单词和上一个单词互换


Alt+0 :Workspace Window
Alt+2 :Output Window
Alt+3 :Watch Window
Alt+4 :Variables Window
Alt+5 :Registers Window
Alt+6 :Memory Window
Alt+7 :CallStack Window
Alt+8 :Disassembly Window
Ctrl+W :ClassWizard
Alt+Enter :属性

Alt+F7 :Project Settings

F7 :Build
Ctrl+F7 :Compile
Ctrl+F5 :Run
Ctrl+Break :Stops the build
F5 :Go
Ctrl+F10 :Run to cursor
F11 :step into
Alt+F10 :Apply codes changes
Ctrl+F9 :Enable/Disable a breakpoint
Alt+F11 :将 Memory Window 切换到下一种显示模式
Alt+Shift+F11 :将 Memory Window 切换到上一种显示模式
Ctrl+Shift+F9 :去掉所有断点
Ctrl+Shift+F5 :Restarts the program
Ctrl+Shift+F10 :将当前行设为下一条指令执行的行
Alt+Num* :滚动到当前指令
Shift+F11 :跳出当前函数
F9 :断点
F10 :step over
Shift+F5 :停止 Debugging
Ctrl+F11 :Switches between the source view and the disassembly view for this instruction
Alt+F12 :Queries on the selected object or current context

Alt+F6 :Toggles the docking feature for the window on/off
Shift+Esc :隐藏窗口



Ctrl+Shift+G :?
Ctrl+* :打开string table
Ctrl+Space :?
Ctrl+F3 :向下查找下一个
Ctrl+Shift+F3 :查找上一个
Ctrl+D :查找
Ctrl+I :向下查找下一个
Ctrl+Shift+I :查找上一个
F6 :?Activates the next pane
Shift+F6 :?Activates the previous pane
Ctrl+M :?Detects duplicate mnemonics in the resource
Alt +O : 头文件与cpp文件的交互显示

C++ builder快捷键大全

Clipboard control (default)
Ctrl+Ins EditCopy
Shift+Del EditCut
Shift+Ins EditPaste

Ctrl+C EditCopy
Ctrl+V EditPaste
Ctrl+X EditCut



--------------------------------------------------------------------------------


Debugger (default, classic, Brief, Epsilon, and Visual Studio)
Breakpoint view

Ctrl+V View Source
Ctrl+S Edit Source
Ctrl+E Edit Breakpoint
Enter Edit Breakpoint
Ctrl+D Delete Breakpoint
Del Delete Breakpoint
Ctrl+A Add Breakpoint
Ins Add Breakpoint
Ctrl+N Enable Breakpoint

Call stack view

Ctrl+V View Source
Ctrl+S Edit Source
Space View Source (Epsilon only)
Ctrl+Enter Edit Source (Epsilon only)

Message view

Ctrl+V View Source
Space View Source
Ctrl+S Edit Source
Ctrl+Enter Edit Source

Watch view

Ctrl+E Edit Watch
Enter Edit Watch
Ctrl+A Add Watch
Ins Add Watch
Ctrl+D Delete Watch
Del Delete Watch



--------------------------------------------------------------------------------


Editor (default)

Shortcut Action or command

F1 HelpTopic Search
Ctrl+F1 HelpTopic Search
F3 SearchSearch Again

Ctrl+E SearchIncremental Search
Ctrl+F SearchFind
Ctrl+I Inserts a tab character
Ctrl+j Templates pop-up menu
Ctrl+N Inserts a new line
Ctrl+P Causes next character to be interpreted as an ASCII sequence
Ctrl+R SearchReplace
Ctrl+S FileSave
Ctrl+T Deletes a word

Ctrl+Y Deletes a line
Ctrl+Z EditUndo
Ctrl+ Code Completion pop-up window

Ctrl+Shift+I Indents block
Ctrl+Shift+U Outdents block
Ctrl+Shift+Y Deletes to the end of a line
Ctrl+Shift+Z EditRedo
Ctrl+Shift+ Code Parameters pop-up window

Alt+[ Finds the matching delimiter (forward)
Alt+] Finds the matching delimiter (backward)

End Moves to the end of a line
Home Moves to the start of a line
Enter Inserts a carriage return

Ins Turns insert mode on/off
Del Deletes the character to the right of the cursor
Backspace Deletes the character to the left of the cursor
Tab Inserts a tab
Space Inserts a blank space
Left Arrow Moves the cursor left one column, accounting for the autoindent setting
Right Arrow Moves the cursor right one column, accounting for the autoindent setting
Up Arrow Moves up one line
Down Arrow Moves down one line

Page Up Moves up one page
Page Down Moves down one page

Ctrl+Left Arrow Moves one word left
Ctrl+Right Arrow Moves one word right
Ctrl+Tab Moves to the next code page (or file)
Ctrl+Shift+Tab Moves to the previous code page (or file)
Ctrl+Backspace Deletes the word to the right of the cursor
Ctrl+Home Moves to the top of a file
Ctrl+End Moves to the end of a file
Ctrl+Del Deletes a currently selected block

Ctrl+Space Inserts a blank space
Ctrl+PgDn Moves to the bottom of a screen
Ctrl+PgUp Moves to the top of a screen
Ctrl+Up Arrow Scrolls up one line
Ctrl+Down Arrow Scrolls down one line
Ctrl+Enter Opens file at cursor

Shift+Tab Moves the cursor to the left one tab position
Shift+Backspace Deletes the character to the left of the cursor
Shift+Left Arrow Selects the character to the left of the cursor

Shift+Right Arrow Selects the character to the right of the cursor
Shift+Up Arrow Moves the cursor up one line and selects from the left of the starting cursor position
Shift+Down Arrow Moves the cursor down one line and selects from the right of the starting cursor position
Shift+PgUp Moves the cursor up one screen and selects from the left of the starting cursor position
Shift+PgDn Moves the cursor down one line and selects from the right of the starting cursor position

Shift+End Selects from the cursor position to the end of the current line
Shift+Home Selects from the cursor position to the start of the current line
Shift+Space Inserts a blank space
Shift+Enter Inserts a new line with a carriage return

Ctrl+Shift+Left Arrow Selects the word to the left of the cursor
Ctrl+Shift+Right Arrow Selects the word to the right of the cursor
Ctrl+Shift+Home Selects from the cursor position to the start of the current file

Ctrl+Shift+End Selects from the cursor position to the end of the current file
Ctrl+Shift+PgDn Selects from the cursor position to the bottom of the screen
Ctrl+Shift+PgUp Selects from the cursor position to the top of the screen
Ctrl+Shift+Tab Moves to the previous page

Alt+Backspace EditUndo
Alt+Shift+Backspace EditRedo
Alt+Shift+Left Arrow Selects the column to the left of the cursor

Alt+Shift+Right Arrow Selects the column to the right of the cursor
Alt+Shift+Up Arrow Moves the cursor up one line and selects the column from the left of the starting cursor position
Alt+Shift+Down Arrow Moves the cursor down one line and selects the column from the left of the starting cursor position
Alt+Shift+Page Up Moves the cursor up one screen and selects the column from the left of the starting cursor position
Alt+Shift+Page Down Moves the cursor down one line and selects the column from the right of the starting cursor position

Alt+Shift+End Selects the column from the cursor position to the end of the current line
Alt+Shift+Home Selects the column from the cursor position to the start of the current line

Ctrl+Alt+Shift+Left Arrow Selects the column to the left of the cursor
Ctrl+Alt+Shift+Right Arrow Selects the column to the right of the cursor
Ctrl+Alt+Shift+Home Selects the column from the cursor position to the start of the current file
Ctrl+Alt+Shift+End Selects the column from the cursor position to the end of the current file

Ctrl+Alt+Shift+Page Up Selects the column from the cursor position to the bottom of the screen
Ctrl+Alt+Shift+Page Down Selects the column from the cursor position to the top of the screen



--------------------------------------------------------------------------------

Block commands (default and classic)
Shortcut Action or command

Ctrl+K+B Marks the beginning of a block
Ctrl+K+C Copies a selected block
Ctrl+K+H Hides/shows a selected block
Ctrl+K+I Indents a block by the amount specified in the Block Indent combo box on the General page of the Editor Options dialog box.
Ctrl+K+K Marks the end of a block
Ctrl+K+L Marks the current line as a block
Ctrl+K+N Changes a block to uppercase
Ctrl+K+O Changes a block to lowercase

Ctrl+K+P Prints selected block
Ctrl+K+R Reads a block from a file
Ctrl+K+T Marks a word as a block
Ctrl+K+U Outdents a block by the amount specified in the Block Indent combo box on the General page of the Editor Options dialog box.
Ctrl+K+V Moves a selected block
Ctrl+K+W Writes a selected block to a file
Ctrl+K+Y Deletes a selected block

Ctrl+O+C Marks a column block
Ctrl+O+I Marks an inclusive block

Ctrl+O+K Marks a non-inclusive block
Ctrl+O+L Marks a line as a block

Ctrl+Q+B Moves to the beginning of a block
Ctrl+Q+K Moves to the end of a block



--------------------------------------------------------------------------------


Bookmark operations (default, classic, and Visual Studio)
Shortcut Action

Ctrl+K+0 Sets bookmark 0
Ctrl+K+1 Sets bookmark 1
Ctrl+K+2 Sets bookmark 2
Ctrl+K+3 Sets bookmark 3
Ctrl+K+4 Sets bookmark 4
Ctrl+K+5 Sets bookmark 5
Ctrl+K+6 Sets bookmark 6
Ctrl+K+7 Sets bookmark 7
Ctrl+K+8 Sets bookmark 8
Ctrl+K+9 Sets bookmark 9

Ctrl+K+Ctrl+0 Sets bookmark 0
Ctrl+K+Ctrl+1 Sets bookmark 1
Ctrl+K+Ctrl+2 Sets bookmark 2

Ctrl+K+Ctrl+3 Sets bookmark 3
Ctrl+K+Ctrl+4 Sets bookmark 4
Ctrl+K+Ctrl+5 Sets bookmark 5
Ctrl+K+Ctrl+6 Sets bookmark 6
Ctrl+K+Ctrl+7 Sets bookmark 7
Ctrl+K+Ctrl+8 Sets bookmark 8
Ctrl+K+Ctrl+9 Sets bookmark 9

Ctrl+Q+0 Goes to bookmark 0
Ctrl+Q+1 Goes to bookmark 1
Ctrl+Q+2 Goes to bookmark 2
Ctrl+Q+3 Goes to bookmark 3
Ctrl+Q+4 Goes to bookmark 4
Ctrl+Q+5 Goes to bookmark 5

Ctrl+Q+6 Goes to bookmark 6
Ctrl+Q+7 Goes to bookmark 7
Ctrl+Q+8 Goes to bookmark 8
Ctrl+Q+9 Goes to bookmark 9

Ctrl+Q+Ctrl+0 Goes to bookmark 0
Ctrl+Q+Ctrl+1 Goes to bookmark 1
Ctrl+Q+Ctrl+2 Goes to bookmark 2
Ctrl+Q+Ctrl+3 Goes to bookmark 3
Ctrl+Q+Ctrl+4 Goes to bookmark 4
Ctrl+Q+Ctrl+5 Goes to bookmark 5
Ctrl+Q+Ctrl+6 Goes to bookmark 6
Ctrl+Q+Ctrl+7 Goes to bookmark 7

Ctrl+Q+Ctrl+8 Goes to bookmark 8
Ctrl+Q+Ctrl+9 Goes to bookmark 9



--------------------------------------------------------------------------------


Cursor movement (default and classic)
Shortcut Action

Ctrl+Q+B Moves to the beginning of a block
Ctrl+Q+C Moves to end of a file
Ctrl+Q+D Moves to the end of a line
Ctrl+Q+E Moves to the top of the window
Ctrl+Q+K Moves to the end of a block
Ctrl+Q+P Moves to previous position
Ctrl+Q+R Moves to the beginning of a file
Ctrl+Q+S Moves to the beginning of a line
Ctrl+Q+T Moves to the top of the window
Ctrl+Q+U Moves to the bottom of the window

Ctrl+Q+X Moves to the bottom of the window



--------------------------------------------------------------------------------


Miscellaneous commands (default and classic)
Shortcut Action or command

Ctrl+K+D Accesses the menu bar
Ctrl+K+E Changes a word to lowercase
Ctrl+K+F Changes a word to uppercase
Ctrl+K+S FileSave (default and classic only)

Ctrl+Q+A SearchReplace
Ctrl+Q+F SearchFind
Ctrl+Q+Y Deletes to the end of a line
Ctrl+Q+[ Finds the matching delimiter (forward)
Ctrl+Q+Ctrl+[ Finds the matching delimiter (forward)
Ctrl+Q+] Finds the matching delimiter (backward)

Ctrl+Q+Ctrl+] Finds the matching delimiter (backward)

Ctrl+O+A Open file at cursor
Ctrl+O+G SearchGo to line number
Ctrl+O+O Inserts compiler options and directives
Ctrl+O+U Toggles case



--------------------------------------------------------------------------------


system
Shortcut Action or command

F1 Displays context-sensitive Help
F4 RunGo to Cursor
F5 RunToggle Breakpoint
Ctrl+F6 Open Source/Header file
F7 RunTrace Into
F8 RunStep Over
F9 RunRun
F11 ViewObject Inspector
F12 ViewToggle Form/Unit


Alt+0 ViewWindow List
Alt+F2 ViewDebug WindowsCPU
Alt+F7 Displays previous error in Message view
Alt+F8 Displays next error in Message view
Alt+F10 Displays a context menu
Alt+F11 FileInclude Unit Hdr
Alt+F12 Displays the Code editor

Ctrl+F1 HelpTopic Search
Ctrl+F2 RunProgram Reset
Ctrl+F3 ViewDebug WindowsCall Stack
Ctrl+F4 Closes current file
Ctrl+F5 Add Watch at Cursor

Ctrl+F6 Displays header file in Code editor

Ctrl+F7 Evaluate/Modify
Ctrl+F9 ProjectMake project

Ctrl+F11 FileOpen Project

Ctrl+F12 ViewUnits


Ctrl+D Descends item (replaces Inspector window)
Ctrl+E ViewClassExplorer
Ctrl+N Opens a new Inspector window
Ctrl+S Incremental search
Ctrl+T Displays the Type Cast dialog

Shift+F7 RunTrace To Next Source Line
Shift+F11 ProjectAdd To Project
Shift+F12 ViewForms

Ctrl+Shift+P Plays back a key macro
Ctrl+Shift+R Records a key macro

Ctrl+K+D Accesses the menu bar
Ctrl+K+S FileSave

用OLE操作Excel

本文档部分资料来自互联网,大部分是ccrun(老妖)在Excel中通过录制宏-->察看宏代码-->转为CB代码而来.本文档不断更新中.欢迎大家关注.

要在应用程序中控制Excel的运行,首先必须在编制自动化客户程序时包含Comobj.hpp
#include "Comobj.hpp"

C++ Builder把Excel自动化对象的功能包装在下面的四个Ole Object Class函数中,应用人员可以很方便地进行调用。
设置对象属性:void OlePropertySet(属性名,参数……);
获得对象属性:Variant OlePropertyGet(属性名,参数……);
调用对象方法:1) Variant OleFunction(函数名,参数……);
2) void OleProcedure(过程名,参数……);

在程序中可以用宏定义来节省时间:

#define PG OlePropertyGet
#define PS OlePropertySet
#define FN OleFunction
#define PR OleProcedure

举例:
ExcelApp.OlePropertyGet("workbooks").OleFunction("Add");
可写为
ExcelApp.PG("workbooks").FN("Add");

C++ Builder中使用OLE控制Excel2000,必须掌握Excel2000的自动化对象及Microsoft Word Visual Basic帮助文件中的关于Excel的对象、方法和属性。对象是一个Excel元素,属性是对象的一个特性或操作的一个方面,方法是对象可以进行的动作。
首先定义以下几个变量:
Variant ExcelApp,Workbook1,Sheet1,Range1;

1、Excel中常用的对象是:Application,Workbooks,Worksheets等。

★创建应用对象★
Variant ExcelApp;
ExcelApp = Variant::CreateObject ("Excel.Application");
或者
ExcelApp = CreateOleObject ("Excel.Application");

★创建工作簿对象★
Variant WorkBook1;
WorkBook1 = ExcelApp.PG("ActiveWorkBook");

★创建工作表对象★
Variant Sheet1;
Sheet1 = WorkBook1.PG("ActiveSheet");

★创建区域对象★
Variant Range;
Range = Sheet1.PG("Range","A1:A10");
或者使用
Excel.Exec(PropertyGet("Range")<<"A1:C1").Exec(Procedure("Select"));

2、常用的属性操作:

★使Excel程序不可见★
ExcelApp.PS("Visible", (Variant)false);

★新建EXCEL文件★

◎ 新建系统模板的工作簿
ExcelApp.PG("workbooks").FN("Add") //默认工作簿
ExcelApp.PG("workbooks").FN("Add", 1) //单工作表
ExcelApp.PG("workbooks").FN("Add", 2) //图表
ExcelApp.PG("workbooks").FN("Add", 3) //宏表
ExcelApp.PG("workbooks").FN("Add", 4) //国际通用宏表
ExcelApp.PG("workbooks").FN("Add", 5) //与默认的相同
ExcelApp.PG("workbooks").FN("Add", 6) //工作簿且只有一个表
或者使用ExcelApp的Exec方法
Excel.Exec(PropertyGet("Workbooks")).Exec(Procedure("Add"));
◎ 新建自己创建的模板的工作簿
ExcelApp.PG("workbooks").FN("Add", "C:\\Temp\\result.xlt");

★打开工作簿★
ExcelApp.PG("workbooks").FN("open", "路径名.xls")

★保存工作簿★
WorkBook1.FN("Save"); //保存工作簿
WorkBook1.FN("SaveAs", "文件名");//工作簿保存为,路径注意用"\\"

★退出EXCEL★
ExcelApp.FN ("Quit");
ExcelApp = Unassigned;
或者
ExcelApp.Exec(Procedure("Quit"));

★操作工作表★

◎ 选择选择工作表中第一个工作表
Workbook1.PG("Sheets", 1).PR("Select");
Sheet1 = Workbook1.PG("ActiveSheet");

◎ 重命名工作表
Sheet1.PS("Name", "Sheet的新名字");

◎ 当前工作簿中的工作表总数
// 本文转自 C++Builder 研究 - http://www.ccrun.com/article.asp?i=529&d=0iezy5
int nSheetCount=Workbook1.PG("Sheets").PG("Count");

★操作行和列★

◎ 获取当前工作表中有多少行和多少列:
Sheet1.PG("UsedRange").PG("Columns").PG("Count"); //列数
Sheet1.PG("UsedRange").PG("Rows").PG("Count"); //行数

◎ 设置列宽
ExcelApp.PG("Columns", 1).PS("ColumnWidth", 22);
或者
Range = ExcelApp.PG("Cells", 1, 3);
Range.PS("ColumnWidth", 22);

◎ 设置行高
ExcelApp.PG("Rows", 2).PS("RowHeight", 25);
或者
Range = ExcelApp.PG("Cells", 2, 1);
Range.PS("RowHeight", 25);

◎ 在工作表最前面插入一行
Sheet1.PG("Rows", 1).PR("Insert");

◎ 删除一行
ExcelApp.PG("Rows", 2).PR("Delete"); //将第2行删除

// 本文作者:ccrun ,如转载请保证本文档的完整性,并注明出处。
// 欢迎光临 C++ Builder 研究 www.ccrun.com
// 摘自:http://www.ccrun.com/doc/go.asp?id=529

★操作单元格★

◎ 设置单元格字体
Sheet1.PG("Cells", 1, 1).PG("Font").PS("Name", "隶书"); //字体
Sheet1.PG("Cells", 2, 3).PG("Font").PS("size", 28); //大小

◎ 设置所选区域字体
Range.PG("Cells").PG("Font").PS("Size", 28);
Range.PG("Cells").PG("Font").PS("Color", RGB(0, 0, 255));
其中参数的设置:
Font Name : "隶书" //字体名称
Size : 12 //字体大小
Color : RGB(*,*,*) //颜色
Underline : true/false //下划线
Italic: true/false //斜体

◎ 设置单元格格式为小数百分比
Sheet1.PG("Cells", 1, 1).PS("NumberFormatLocal", "0.00%");

◎ 设定单元格的垂直对齐方式
Range = ExcelApp.PG("Cells", 3, 4);
// 1=靠上 2=居中 3=靠下对齐 4=两端对齐 5=分散对齐
Range.PS("VerticalAlignment", 2);

◎ 设定单元格的文本为自动换行
Range = ExcelApp.PG("Cells", 3, 4);
Range.PS("WrapText", true);

★单元格的合并★

◎ Range = Sheet1.PG("Range", "A1:A2"); //A1和A2单元格合并
String strRange = "A" + IntToStr(j) + ":" + "C" + IntToStr(j); //比如:A1:C5
Range1=Sheet1.PG("Range", strRange.c_str()); //可以用变量控制单元格合并
Range1.FN("Merge", false);

★读写单元格★

◎ 指定单元格赋值
String strValue = "abcdefg";
Sheet1.PG("Cells", 3, 6).PS("Value", strValue.c_str());
Sheet1.PG("Cells", j, 1).PS("Value", "总记录:" + String(j-6));
或者使用
Excel.Exec(PropertyGet("Cells")<<1<<3).Exec(PropertySet("Value")<<15);

◎ 所选区域单元格赋值
Range.PG("Cells").PS("Value", 10);

◎ 所选区域行赋值
Range.PG("Rows",1).PS("Value", 1234);

◎ 工作表列赋值
Sheet1.PG("Columns",1).PS("Value", 1234);

◎ 读取取值语句:
String strValue = Sheet1.PG("Cells", 3, 5).PG("Value");

★窗口属性★

◎ 显示属性
ExcelApp.PS("Windowstate", 3); //最大化显示
1---------xlNormal //正常显示
2---------xlMinimized //最小化显示
3---------xlMaximized //最大化显示

◎ 状态栏属性
ExcelApp.PS("StatusBar", "您好,请您稍等。正在查询!");
ExcelApp.PS("StatusBar", false); //还原成默认值

◎ 标题属性:
ExcelApp.PS("Caption", "查询系统");

3、操作图表

★添加图表

Variant Chart;
Chart = ExcelApp.Exec(PropertyGet("Charts")).Exec(Function("Add"));
ExcelApp.Exec(PropertySet("Visible") << true);
Chart.Exec(PropertySet("Type") << -4100);

★滚动图表

for(int nRotate=5; nRotate <= 180; nRotate += 5)
{
Chart.Exec(PropertySet("Rotation") << nRotate);
}
for (int nRotate = 175; nRotate >= 0; nRotate -= 5)
{
Chart.Exec(PropertySet("Rotation") << nRotate);
}

另外,为保证程序能正常运行,需要在程序中判断目标机器是否安装了Office;
try
{
ExcelApp = Variant::CreateObject ("Excel.Application");
}
catch(...)
{
ShowMessage("运行Excel出错,请确认安装了Office");
return;
}


#include "comobj.hpp"
//---------------------------------------------------------------------------
// 对指定Excel文件中的指定列进行排序
// strExcelFileName : excel文件名
// nCol : 指定的列号
// nSortStyle : 1:升序,2:降序
void SortExcelColumn(String strExcelFileName, int nCol, int nSortStyle)
{
Variant vExcelApp, vWorkbook, vRange;
vExcelApp = Variant::CreateObject("Excel.Application");
vExcelApp.OlePropertySet("Visible", false);
vExcelApp.OlePropertyGet("WorkBooks").OleProcedure("Open", strExcelFileName.c_str());
vWorkbook = vExcelApp.OlePropertyGet("ActiveWorkbook");
vExcelApp.OlePropertyGet("Columns", nCol).OleProcedure("Select");
vExcelApp.OlePropertyGet("ActiveSheet").OlePropertyGet("Cells", 1, nCol).OleProcedure("Select");
vRange = vExcelApp.OlePropertyGet("Selection");
vRange.Exec(Function("Sort")<<vExcelApp.OlePropertyGet("Selection")<<nSortStyle);
vWorkbook.OleProcedure("Save");
vWorkbook.OleProcedure("Close");
vExcelApp.OleFunction("Quit");
vWorkbook = Unassigned;
vExcelApp = Unassigned;
ShowMessage("ok");
}

void __fastcall TForm1::Button1Click(TObject *Sender)
{
// 对C:\123\123.xls文件中第一个Sheet的第四列进行升序排序
SortExcelColumn("C:\\123\\123.xls", 4, 1);
}
//---------------------------------------------------------------------------

星期三, 十月 24, 2007

关于C++程序中的内存划分介绍

C++中,内存分成5个区,他们分别是堆、栈、自由存储区、全局/静态存储区和常量存储区。
  栈,就是那些由编译器在需要的时候分配,在不需要的时候自动清除的变量的存储区。里面的变量通常是局部变量、函数参数等。
  堆,就是那些由new分配的内存块,他们的释放编译器不去管,由我们的应用程序去控制,一般一个new就要对应一个delete。如果程序员没有释放掉,那么在程序结束后,操作系统会自动回收。
  自由存储区,就是那些由malloc等分配的内存块,他和堆是十分相似的,不过它是用free来结束自己的生命的。
  全局/静态存储区,全局变量和静态变量被分配到同一块内存中,在以前的C语言中,全局变量又分为初始化的和未初始化的,在C++里面没有这个区分了,他们共同占用同一块内存区。
  常量存储区,这是一块比较特殊的存储区,他们里面存放的是常量,不允许修改(当然,你要通过非正当手段也可以修改,而且方法很多)

C++ builder 的文件读写操作总结

在编程的过程中,文件的操作是一个经常用到的问题,在C++Builder中,可以使用多种方法对文件操作,下面我就按以下几个部分对此作详细介绍,就是:
  1、基于C的文件操作;
  2、基于C++的文件操作;
  3、基于WINAPI的文件操作;
  4、基于BCB库的文件操作;
  5、特殊文件的操作。
  1. 基于C的文件操作
  在ANSI C中,对文件的操作分为两种方式,即流式文件操作和I/O文件操作,下面就分别介绍之。
  1)流式文件操作
  这种方式的文件操作有一个重要的结构FILE,FILE在stdio.h中定义如下:
  
以下是引用片段:typedef struct {   int level; /* fill/empty level of buffer */   unsigned flags; /* File status flags */   char fd; /* File descriptor */   unsigned char hold; /* Ungetc char if no buffer */   int bsize; /* Buffer size */   unsigned char _FAR *buffer; /* Data transfer buffer */   unsigned char _FAR *curp; /* Current active pointer */   unsigned istemp; /* Temporary file indicator */   short token; /* Used for validity checking */   } FILE; /* This is the FILE object */
  FILE这个结构包含了文件操作的基本属性,对文件的操作都要通过这个结构的指针来进行,此种文件操作常用的函数如下:
函数 功能
  fopen() 打开流
  fclose() 关闭流
  fputc() 写一个字符到流中
  fgetc() 从流中读一个字符
  fseek() 在流中定位到指定的字符
  fputs() 写字符串到流
  fgets() 从流中读一行或指定个字符
  fprintf() 按格式输出到流
  fscanf() 从流中按格式读取
  feof() 到达文件尾时返回真值
  ferror() 发生错误时返回其值
  rewind() 复位文件定位器到文件开始处
  remove() 删除文件
  fread() 从流中读指定个数的字符
  fwrite() 向流中写指定个数的字符
  tmpfile() 生成一个临时文件流
  tmpnam() 生成一个唯一的文件名
下面就介绍一下这些函数
  1.fopen()
  fopen的原型是:FILE *fopen(const char *filename,const char *mode),fopen实现三个功能:为使用而打开一个流,把一个文件和此流相连接,给此流返回一个FILR指针。
  参数filename指向要打开的文件名,mode表示打开状态的字符串,其取值如下:
  字符串 含义
  "r" 以只读方式打开文件
  "w" 以只写方式打开文件
  "a" 以追加方式打开文件
  "r+" 以读/写方式打开文件,如无文件出错
  "w+" 以读/写方式打开文件,如无文件生成新文件
  一个文件可以以文本模式或二进制模式打开,这两种的区别是:在文本模式中回车被当成一个字符'\n',而二进制模式认为它是两个字符0x0D,0x0A;如果在文件中读到0x1B,文本模式会认为这是文件结束符,也就是二进制模型不会对文件进行处理,而文本方式会按一定的方式对数据作相应的转换。
  系统默认的是以文本模式打开,可以修改全部变量_fmode的值来修改这个设置,例如_fmode=O_TEXT;就设置默认打开方式为文本模式;而_fmode=O_BINARY;则设置默认打开方式是二进制模式。
  我们也可以在模式字符串中指定打开的模式,如"rb"表示以二进制模式打开只读文件,"w+t"或"wt+"表示以文本模式打开读/写文件。
  此函数返回一个FILE指针,所以申明一个FILE指针后不用初始化,而是用fopen()来返回一个指针并与一个特定的文件相连,如果成败,返回NULL。
  例:
  
以下是引用片段:FILE *fp;   if(fp=fopen("123.456","wb"))   puts("打开文件成功");   else   puts("打开文件成败");  2.fclose()
  fclose()的功能就是关闭用fopen()打开的文件,其原型是:int fclose(FILE *fp);如果成功,返回0,失败返回EOF。
  在程序结束时一定要记得关闭打开的文件,不然可能会造成数据丢失的情况,我以前就经常犯这样的错误。
  例:fclose(fp);
  3.fputc()
  向流写一个字符,原型是int fputc(int c, FILE *stream); 成功返回这个字符,失败返回EOF。
  例:fputc('X',fp);
  4.fgetc()
  从流中读一个字符,原型是int fputc(FILE *stream); 成功返回这个字符,失败返回EOF。
  例:char ch1=fgetc(fp);
  5. fseek()
  此函数一般用于二进制模式打开的文件中,功能是定位到流中指定的位置,原型是int fseek(FILE *stream, long offset, int whence);如果成功返回0,参数offset是移动的字符数,whence是移动的基准,取值是:
  符号常量 值 基准位置
  SEEK_SET 0 文件开头
  SEEK_CUR 1 当前读写的位置
  SEEK_END 2 文件尾部
  例:fseek(fp,1234L,SEEK_CUR);//把读写位置从当前位置向后移动1234字节(L后缀表示长整数)
  fseek(fp,0L,2);//把读写位置移动到文件尾
  6.fputs()
  写一个字符串到流中,原型int fputs(const char *s, FILE *stream);
  例:fputs("I Love You",fp);
  7.fgets()
  从流中读一行或指定个字符,原型是char *fgets(char *s, int n, FILE *stream); 从流中读取n-1个字符,除非读完一行,参数s是来接收字符串,如果成功则返回s的指针,否则返回NULL。
  例:如果一个文件的当前位置的文本如下:
  Love ,I Have
  But ……..
  如果用
  fgets(str1,4,file1);
  则执行后str1="Lov",读取了4-1=3个字符,而如果用
  fgets(str1,23,file1);
  则执行str="Love ,I Have",读取了一行(不包括行尾的'\n')。
  8.fprintf()
  按格式输入到流,其原型是int fprintf(FILE *stream, const char *format[, argument, …]);其用法和printf()相同,不过不是写到控制台,而是写到流罢了。
  例:fprintf(fp,"%2d%s",4,"Hahaha");
  9.fscanf()
  从流中按格式读取,其原型是int fscanf(FILE *stream, const char *format[, address, …]);其用法和scanf()相同,不过不是从控制台读取,而是从流读取罢了。
  例:fscanf(fp,"%d%d" ,&x,&y);
  10.feof()
  检测是否已到文件尾,是返回真,否则返回0,其原型是int feof(FILE *stream);
  例:if(feof(fp))printf("已到文件尾");
  11.ferror()
  原型是int ferror(FILE *stream);返回流最近的错误代码,可用clearerr()来清除它,clearerr()的原型是void clearerr(FILE *stream);
  例:printf("%d",ferror(fp));
  12.rewind()
  把当前的读写位置回到文件开始,原型是void rewind(FILE *stream);其实本函数相当于fseek(fp,0L,SEEK_SET);
  例:rewind(fp);
  12.remove()
  删除文件,原型是int remove(const char *filename); 参数就是要删除的文件名,成功返回0。
  例:remove("c:\\io.sys");
  13.fread()
  从流中读指定个数的字符,原型是size_t fread(void *ptr, size_t size, size_t n, FILE *stream);参数ptr是保存读取的数据,void*的指针可用任何类型的指针来替换,如char*、int *等等来替换;size是每块的字节数;n是读取的块数,如果成功,返回实际读取的块数(不是字节数),本函数一般用于二进制模式打开的文件中。
  例:
  
以下是引用片段:char x[4230];   FILE *file1=fopen("c:\\msdos.sys","r");   fread(x,200,12 ,file1);//共读取200*12=2400个字节  14.fwrite()
  与fread对应,向流中写指定的数据,原型是size_t fwrite(const void *ptr, size_t size, size_t n, FILE *stream);参数ptr是要写入的数据指针,void*的指针可用任何类型的指针来替换,如char*、int *等等来替换;size是每块的字节数;n是要写的块数,如果成功,返回实际写入的块数(不是字节数),本函数一般用于二进制模式打开的文件中。
  例:
  
以下是引用片段:  char x[]="I Love You";   fwire(x, 6,12,fp);//写入6*12=72字节   将把"I Love"写到流fp中12次,共72字节  15.tmpfile()
  其原型是FILE *tmpfile(void); 生成一个临时文件,以"w+b"的模式打开,并返回这个临时流的指针,如果失败返回NULL。在程序结束时,这个文件会被自动删除。
  例:FILE *fp=tmpfile();
  16.tmpnam();
  其原型为char *tmpnam(char *s); 生成一个唯一的文件名,其实tmpfile()就调用了此函数,参数s用来保存得到的文件名,并返回这个指针,如果失败,返回NULL。
  例:tmpnam(str1);
2 )直接I/O文件操作
  这是C提供的另一种文件操作,它是通过直接存/取文件来完成对文件的处理,而上篇所说流式文件操作是通过缓冲区来进行;流式文件操作是围绕一个FILE指针来进行,而此类文件操作是围绕一个文件的“句柄”来进行,什么是句柄呢?它是一个整数,是系统用来标识一个文件(在WINDOWS中,句柄的概念扩展到所有设备资源的标识)的唯一的记号。此类文件操作常用的函数如下表,这些函数及其所用的一些符号在io.h和fcntl.h中定义,在使用时要加入相应的头文件。
  函数 说明
  open() 打开一个文件并返回它的句柄
  close() 关闭一个句柄
  lseek() 定位到文件的指定位置
  read() 块读文件
  write() 块写文件
  eof() 测试文件是否结束
  filelength() 取得文件长度
  rename() 重命名文件
  chsize() 改变文件长度
  下面就对这些函数一一说明:
  1.open()
  打开一个文件并返回它的句柄,如果失败,将返回一个小于0的值,原型是int open(const char *path, int access [, unsigned mode]); 参数path是要打开的文件名,access是打开的模式,mode是可选项。表示文件的属性,主要用于UNIX系统中,在DOS/WINDOWS这个参数没有意义。其中文件的打开模式如下表。
  符号 含义 符号 含义 符号 含义
  O_RDONLY 只读方式 O_WRONLY 只写方式 O_RDWR 读/写方式
  O_NDELAY 用于UNIX系统 O_APPEND 追加方式 O_CREAT 如果文件不存在就创建
  O_TRUNC 把文件长度截为0 O_EXCL 和O_CREAT连用,如果文件存在返回错误 O_BINARY 二进制方式
  O_TEXT 文本方式
  对于多个要求,可以用""运算符来连接,如O_APPENDO_TEXT表示以文本模式和追加方式打开文件。
  例:int handle=open("c:\\msdos.sys",O_BINARYO_CREATO_WRITE)
  2.close()
  关闭一个句柄,原型是int close(int handle);如果成功返回0。
  例:close(handle)
  3.lseek()
  定位到指定的位置,原型是:long lseek(int handle, long offset, int fromwhere);参数offset是移动的量,fromwhere是移动的基准位置,取值和前面讲的fseek()一样,SEEK_SET:文件首部;SEEK_CUR:文件当前位置;SEEK_END:文件尾。此函数返回执行后文件新的存取位置。
  例:
  lseek(handle,-1234L,SEEK_CUR);//把存取位置从当前位置向前移动1234个字节。
  x=lseek(hnd1,0L,SEEK_END);//把存取位置移动到文件尾,x=文件尾的位置即文件长度
  4.read()
  从文件读取一块,原型是int read(int handle, void *buf, unsigned len);参数buf保存读出的数据,len是读取的字节。函数返回实际读出的字节。
  例:char x[200];read(hnd1,x,200);
  5.write()
  写一块数据到文件中,原型是int write(int handle, void *buf, unsigned len);参数的含义同read(),返回实际写入的字节。
  例:char x[]="I Love You";write(handle,x,strlen(x));
  7.eof()
  类似feof(),测试文件是否结束,是返回1,否则返回0;原型是:int eof(int handle);
  例:while(!eof(handle1)){……};
  8.filelength()
  返回文件长度,原型是long filelength(int handle);相当于lseek(handle,0L,SEEK_END)
  例:long x=filelength(handle);
  9.rename()
  重命名文件,原型是int rename(const char *oldname, const char *newname); 参数oldname是旧文件名,newname是新文件名。成功返回0
  例:rename("c:\\config.sys","c:\\config.w40");
  10.chsize();
  改变文件长度,原型是int chsize(int handle, long size);参数size表示文件新的长度,成功返回0,否则返回-1,如果指定的长度小于文件长度,则文件被截短;如果指定的长度大于文件长度,则在文件后面补'\0'。
  例:chsize(handle,0x12345);
  如果熟悉汇编可能会发现这种方式和汇编语言的DOS功能调用句柄式文件操作很像,比如open()就像DOS服务的3CH号功能调用,其实这种操作还有两种类型的函数就是直接用DOS功能来完成的,如_open(),_dos_open()等等。有兴趣可自已查询BCB的帮助。
  同流式文件操作相同,这种也提供了Unicode字符操作的函数,如_wopen()等等,用于9X/NT下的宽字符编程,有兴趣可自已查询BCB的帮助。
  另外,此种操作还有lock(),unlock(),locking()等用于多用户操作的函数,但在BCB中用得并不多,我就不介绍了,但如果要用C来写CGI,这些就必要的常识了,如果你有这方面的要求,那就得自已好好看帮助了。
在C++中,有一个stream这个类,所有的I/O都以这个“流”类为基础的,包括我们要认识的文件I/O,stream这个类有两个重要的运算符:
  1、插入器(<<)
  向流输出数据。比如说系统有一个默认的标准输出流(cout),一般情况下就是指的显示器,所以,cout<<"Write Stdout"<<'\n';就表示把字符串"Write Stdout"和换行字符('\n')输出到标准输出流。
  2、析取器(>>)
  从流中输入数据。比如说系统有一个默认的标准输入流(cin),一般情况下就是指的键盘,所以,cin>>x;就表示从标准输入流中读取一个指定类型(即变量x的类型)的数据。
  在C++中,对文件的操作是通过stream的子类fstream(file stream)来实现的,所以,要用这种方式操作文件,就必须加入头文件fstream.h。下面就把此类的文件操作过程一一道来。
  1. 打开文件
  在fstream类中,有一个成员函数open(),就是用来打开文件的,其原型是:
  void open(const char* filename,int mode,int access);
  参数:
  filename:  要打开的文件名
  mode:    要打开文件的方式
  access:   打开文件的属性
  打开文件的方式在类ios(是所有流式I/O类的基类)中定义,常用的值如下:
  ios::app:   以追加的方式打开文件
  ios::ate:   文件打开后定位到文件尾,ios:app就包含有此属性
  ios::binary:  以二进制方式打开文件,缺省的方式是文本方式。两种方式的区别见前文
  ios::in:    文件以输入方式打开
  ios::out:   文件以输出方式打开
  ios::nocreate: 不建立文件,所以文件不存在时打开失败
  ios::noreplace:不覆盖文件,所以打开文件时如果文件存在失败
  ios::trunc:  如果文件存在,把文件长度设为0
  可以用“或”把以上属性连接起来,如ios::outios::binary
  打开文件的属性取值是:
  0:普通文件,打开访问
  1:只读文件
  2:隐含文件
  4:系统文件
  可以用“或”或者“+”把以上属性连接起来 ,如3或12就是以只读和隐含属性打开文件。
  例如:以二进制输入方式打开文件c:\config.sys
  fstream file1;
  file1.open("c:\\config.sys",ios::binaryios::in,0);
  如果open函数只有文件名一个参数,则是以读/写普通文件打开,即:
  file1.open("c:\\config.sys");<=>file1.open("c:\\config.sys",ios::inios::out,0);
  另外,fstream还有和open()一样的构造函数,对于上例,在定义的时侯就可以打开文件了:
  fstream file1("c:\\config.sys");
  特别提出的是,fstream有两个子类:ifstream(input file stream)和ofstream(outpu file stream),ifstream默认以输入方式打开文件,而ofstream默认以输出方式打开文件。
  ifstream file2("c:\\pdos.def");//以输入方式打开文件
  ofstream file3("c:\\x.123");//以输出方式打开文件
  所以,在实际应用中,根据需要的不同,选择不同的类来定义:如果想以输入方式打开,就用ifstream来定义;如果想以输出方式打开,就用ofstream来定义;如果想以输入/输出方式来打开,就用fstream来定义。
  2. 关闭文件
  打开的文件使用完成后一定要关闭,fstream提供了成员函数close()来完成此操作,如:file1.close();就把file1相连的文件关闭。
3. 读写文件
  读写文件分为文本文件和二进制文件的读取,对于文本文件的读取比较简单,用插入器和析取器就可以了;而对于二进制的读取就要复杂些,下要就详细的介绍这两种方式
  1. 文本文件的读写
  文本文件的读写很简单:用插入器(<<)向文件输出;用析取器(>>)从文件输入。假设file1是以输入方式打开,file2以输出打开。示例如下:
 
以下是引用片段: file2<<"I Love You";//向文件写入字符串"I Love You"   int I;   file1>>I;//从文件输入一个整数值。  这种方式还有一种简单的格式化能力,比如可以指定输出为16进制等等,具体的格式有以下一些
  操纵符 功能 输入/输出
  dec 格式化为十进制数值数据 输入和输出
  endl 输出一个换行符并刷新此流 输出
  ends 输出一个空字符 输出
  hex 格式化为十六进制数值数据 输入和输出
  oct 格式化为八进制数值数据 输入和输出
  setpxecision(int p) 设置浮点数的精度位数 输出
  比如要把123当作十六进制输出:file1<
  2. 二进制文件的读写
  ①put()
  put()函数向流写入一个字符,其原型是ofstream &put(char ch),使用也比较简单,如file1.put('c');就是向流写一个字符'c'。
  ②get()
  get()函数比较灵活,有3种常用的重载形式:
  一种就是和put()对应的形式:ifstream &get(char &ch);功能是从流中读取一个字符,结果保存在引用ch中,如果到文件尾,返回空字符。如file2.get(x);表示从文件中读取一个字符,并把读取的字符保存在x中。
  另一种重载形式的原型是: int get();这种形式是从流中返回一个字符,如果到达文件尾,返回EOF,如x=file2.get();和上例功能是一样的。
  还有一种形式的原型是:ifstream &get(char *buf,int num,char delim='\n');这种形式把字符读入由 buf 指向的数组,直到读入了 num 个字符或遇到了由 delim 指定的字符,如果没使用 delim 这个参数,将使用缺省值换行符'\n'。例如:
  file2.get(str1,127,'A');//从文件中读取字符到字符串str1,当遇到字符'A'或读取了127个字符时终止。
  ③读写数据块
  要读写二进制数据块,使用成员函数read()和write()成员函数,它们原型如下:
  read(unsigned char *buf,int num);
  write(const unsigned char *buf,int num);
  read()从文件中读取 num 个字符到 buf 指向的缓存中,如果在还未读入 num 个字符时就到了文件尾,可以用成员函数 int gcount();来取得实际读取的字符数;而 write() 从buf 指向的缓存写 num 个字符到文件中,值得注意的是缓存的类型是 unsigned char *,有时可能需要类型转换。
  例:
  
以下是引用片段:  unsigned char str1[]="I Love You";   int n[5];   ifstream in("xxx.xxx");   ofstream out("yyy.yyy");   out.write(str1,strlen(str1));//把字符串str1全部写到yyy.yyy中   in.read((unsigned char*)n,sizeof(n));//从xxx.xxx中读取指定个整数,注意类型转换   in.close();out.close();  4. 检测EOF
  成员函数eof()用来检测是否到达文件尾,如果到达文件尾返回非0值,否则返回0。原型是int eof();
  例:  if(in.eof())ShowMessage("已经到达文件尾!");
  5. 文件定位
  和C的文件操作方式不同的是,C++ I/O系统管理两个与一个文件相联系的指针。一个是读指针,它说明输入操作在文件中的位置;另一个是写指针,它下次写操作的位置。每次执行输入或输出时,相应的指针自动变化。所以,C++的文件定位分为读位置和写位置的定位,对应的成员函数是 seekg()和 seekp(),seekg()是设置读位置,seekp是设置写位置。它们最通用的形式如下:
  istream &seekg(streamoff offset,seek_dir origin);
  ostream &seekp(streamoff offset,seek_dir origin);
  streamoff定义于 iostream.h 中,定义有偏移量 offset 所能取得的最大值,seek_dir 表示移动的基准位置,是一个有以下值的枚举:
  ios::beg:  文件开头
  ios::cur:  文件当前位置
  ios::end:  文件结尾
  这两个函数一般用于二进制文件,因为文本文件会因为系统对字符的解释而可能与预想的值不同。
  例:
  file1.seekg(1234,ios::cur);//把文件的读指针从当前位置向后移1234个字节
  file2.seekp(1234,ios::beg);//把文件的写指针从文件开头向后移1234个字节
  有了这些知识,我们就可以完成对文件的操作了,当然,还有好多的成员函数我没介绍,但有这些我们已经能完成大多数的需要了,这种文件操作方式是我比较喜欢的一种方法,比C的方法灵活,又比BCB函数和WINAPI函数具有通用性。
  下一次,我将介绍BCB提供的文件操作的库函数。
  在BCB中也提供了文件操作的函数,这些函数的功能和前面所介绍的大致相同,但这类函数和BCB关系紧密,能使用BCB中的AnsiString等数据类型,在BCB中用这种方式的文件操作是最方便的,下面我就把这种文件操作详细介绍。
  在BCB提供的这组文件操作函数中,可分为三种类型,就是:1、文件名函数,2、文件管理函数;3、文件I/O函数。
  1. 文件名函数
  文件名函数可以对文件的名称、所在子目录、驱动器和扩展名等进行操作。下表列出这些函数及其功能。
  函数 说明
  ExpandFileName() 返回文件的全路径(含驱动器、路径)
  ExtractFileExt() 从文件名中抽取扩展名
  ExtractFileName() 从文件名中抽取不含路径的文件名
  ExtractFilePath() 从文件名中抽取路径名
  ExtractFileDir() 从文件名中抽取目录名
下面就把这些函数作一一介绍:
  ⑴ExpandFileName()
  原型:extern PACKAGE AnsiString __fastcall ExpandFileName(const AnsiString FileName);
  功能:返回文件的全路径(含驱动器、路径)
  参数:FileName:要处理的文件名
  例:ShowMessage(ExpandFileName(Application->ExeName));//显示你的程序文件名,如C:\MyBCB\Sample1.EXE
  ⑵ExtractFileExt()
  原型:extern PACKAGE AnsiString __fastcall ExtractFileExt(const AnsiString FileName);
  功能:从文件名中抽取扩展名
  参数:FileName:要处理的文件名(全路径)
  例:ShowMessage(ExtractFileExt(Application->ExeName));//显示".exe"
  ⑶ExtractFileName()
  原型:extern PACKAGE AnsiString __fastcall ExtractFileName(const AnsiString FileName);
  功能:从文件名中抽取不含路径的文件名
  参数:FileName:要处理的文件名
  例:ShowMessage(ExtractFileExt("c:\\Winnt\\SOL.EXE"));//显示"SOL.EXE"
  ⑷ExtractFilePath()
  原型:extern PACKAGE AnsiString __fastcall ExtractFilePath(const AnsiString FileName);
  功能:从文件名中抽取路径名
  参数:FileName:要处理的文件名
  例:ShowMessage(ExtractFilePath("Winnt\\SOL.EXE"));//显示"Winnt\"
  ⑸ExtractFileDir()
  原型:extern PACKAGE AnsiString __fastcall ExtractFileDir(const AnsiString FileName);
  功能:从文件名中抽取目录名(和上个函数不同,不包括最后的"\")
  参数:FileName:要处理的文件名
  例:ShowMessage(ExtractFileDir("Winnt\\SOL.EXE"));//显示"Winnt",注意和上个函数的区别
  ⑹ExtractFileDrive()
  原型:extern PACKAGE AnsiString __fastcall ExtractFileDrive(const AnsiString FileName);
  功能:从文件名中抽取驱动器名
  参数:FileName:要处理的文件名
  例:ShowMessage(ExtractFileDrive("c:\\Winnt\\SOL.EXE"));//显示"c:"
  ⑺ChangeFileExt()
  原型:extern PACKAGE System::AnsiString __fastcall ChangeFileExt(const System::AnsiString FileName, const System::AnsiString Extension);
  功能:更改文件名的扩展名,不是对真正的文件进行改名,只是对文件名这个字符串进行处理
  参数:FileName:要改名的文件名,Extension:新的扩展名
  例:ShowMessage(ChangeFileExt("c:\\Winnt\\SOL.EXE",".OOO"));//显示"c:\winnt\SOL.OOO"
  ⑻ExpandUNCFileName()
  原型:extern PACKAGE AnsiString __fastcall ExpandUNCFileName(const AnsiString FileName);
  功能:返回含有网络驱动器的文件全路径,格式为:\\机器名\共享名\文件名
  参数:FileName:要处理的文件名
  例:ShowMessage(ExpandUNCFileName("F:\\Winnt\\SOL.EXE"));/*如果F:是映射的网络驱动器\\NT40\WINNT,则显示"\\NT40\WINNT\SOL.EXE"*/
  ⑼ExtractRelativePath()
  原型:extern PACKAGE AnsiString __fastcall ExtractRelativePath(const AnsiString BaseName, const AnsiString DestName);
  功能:从文件名中抽取相对路径信息,如"..\sss\ss.asd"这种形式
  参数:BaseName:基准文件名;DestName:目标文件名
  例:ShowMessage(ExtractRelativePath("D:\\Source\\c\\1.123","D:\\Source\\Asm\\dz.asm"));/*显示"..\asm\dz.asm"*/
  ⑽ExtractShortPathName()
  原型:extern PACKAGE AnsiString __fastcall ExtractShortPathName(const AnsiString FileName);
  功能:把文件名转换为DOS的8、3格式
  参数:FileName:要处理的文件名
  例:ShowMessage(ExtractShortPathName("E:\\Program Files\\Dual Wheel Mouse\\4dmain.exe"));/*显示"E:\Progra~1\dualwh~1\4dmain.exe"*/
  ⑾MatchesMask()
  原型:extern PACKAGE bool __fastcall MatchesMask(const AnsiString Filename, const AnsiString Mask);
  功能:检查文件是否与指定的文件名格式匹配
  参数:FileName:要处理的文件名;Mask:文件名格式,支持通配符
  例:ShowMessage(MatchesMask("Lxf.exe","*.?x?));//显示"true"
  2. 文件管理函数
  这类函数包括设置和读取驱动器、子目录和文件的有关的各种操作,下表列出这类操作常用的函数及其功能。
  函数 功能
  CreateDir() 创建新的子目录
  DeleteFile() 删除文件
  DirectoryExists() 判断目录是否存在
  DiskFree() 获取磁盘剩余空间
  DiskSize() 获取磁盘容量
  FileExists() 判断文件是否存在
  FileGetAttr() 获取文件属性
  FileGetDate() 获取文件日期
  GetCurrentDir() 获取当前目录
  RemoveDir() 删除目录
  SetCurrentDir() 设置当前目录
  ExtractFileDrive() 从文件名中抽取驱动器名
  ChangeFileExt() 改变文件的扩展名
  ExpandUNCFileName() 返回含有网络驱动器的文件全路径
  ExtractRelativePath() 从文件名中抽取相对路径信息
  ExtractShortPathName() 把文件名转化为DOS的8·3格式
  MatchesMask() 检查文件是否与指定的文件名格式匹配
下面就把这些函数作一一介绍:
  ⑴ExpandFileName()
  原型:extern PACKAGE AnsiString __fastcall ExpandFileName(const AnsiString FileName);
  功能:返回文件的全路径(含驱动器、路径)
  参数:FileName:要处理的文件名
  例:ShowMessage(ExpandFileName(Application->ExeName));//显示你的程序文件名,如C:\MyBCB\Sample1.EXE
  ⑵ExtractFileExt()
  原型:extern PACKAGE AnsiString __fastcall ExtractFileExt(const AnsiString FileName);
  功能:从文件名中抽取扩展名
  参数:FileName:要处理的文件名(全路径)
  例:ShowMessage(ExtractFileExt(Application->ExeName));//显示".exe"
  ⑶ExtractFileName()
  原型:extern PACKAGE AnsiString __fastcall ExtractFileName(const AnsiString FileName);
  功能:从文件名中抽取不含路径的文件名
  参数:FileName:要处理的文件名
  例:ShowMessage(ExtractFileExt("c:\\Winnt\\SOL.EXE"));//显示"SOL.EXE"
  ⑷ExtractFilePath()
  原型:extern PACKAGE AnsiString __fastcall ExtractFilePath(const AnsiString FileName);
  功能:从文件名中抽取路径名
  参数:FileName:要处理的文件名
  例:ShowMessage(ExtractFilePath("Winnt\\SOL.EXE"));//显示"Winnt\"
  ⑸ExtractFileDir()
  原型:extern PACKAGE AnsiString __fastcall ExtractFileDir(const AnsiString FileName);
  功能:从文件名中抽取目录名(和上个函数不同,不包括最后的"\")
  参数:FileName:要处理的文件名
  例:ShowMessage(ExtractFileDir("Winnt\\SOL.EXE"));//显示"Winnt",注意和上个函数的区别
  ⑹ExtractFileDrive()
  原型:extern PACKAGE AnsiString __fastcall ExtractFileDrive(const AnsiString FileName);
  功能:从文件名中抽取驱动器名
  参数:FileName:要处理的文件名
  例:ShowMessage(ExtractFileDrive("c:\\Winnt\\SOL.EXE"));//显示"c:"
  ⑺ChangeFileExt()
  原型:extern PACKAGE System::AnsiString __fastcall ChangeFileExt(const System::AnsiString FileName, const System::AnsiString Extension);
  功能:更改文件名的扩展名,不是对真正的文件进行改名,只是对文件名这个字符串进行处理
  参数:FileName:要改名的文件名,Extension:新的扩展名
  例:ShowMessage(ChangeFileExt("c:\\Winnt\\SOL.EXE",".OOO"));//显示"c:\winnt\SOL.OOO"
  ⑻ExpandUNCFileName()
  原型:extern PACKAGE AnsiString __fastcall ExpandUNCFileName(const AnsiString FileName);
  功能:返回含有网络驱动器的文件全路径,格式为:\\机器名\共享名\文件名
  参数:FileName:要处理的文件名
  例:ShowMessage(ExpandUNCFileName("F:\\Winnt\\SOL.EXE"));/*如果F:是映射的网络驱动器\\NT40\WINNT,则显示"\\NT40\WINNT\SOL.EXE"*/
  ⑼ExtractRelativePath()
  原型:extern PACKAGE AnsiString __fastcall ExtractRelativePath(const AnsiString BaseName, const AnsiString DestName);
  功能:从文件名中抽取相对路径信息,如"..\sss\ss.asd"这种形式
  参数:BaseName:基准文件名;DestName:目标文件名
  例:ShowMessage(ExtractRelativePath("D:\\Source\\c\\1.123","D:\\Source\\Asm\\dz.asm"));/*显示"..\asm\dz.asm"*/
  ⑽ExtractShortPathName()
  原型:extern PACKAGE AnsiString __fastcall ExtractShortPathName(const AnsiString FileName);
  功能:把文件名转换为DOS的8、3格式
  参数:FileName:要处理的文件名
  例:ShowMessage(ExtractShortPathName("E:\\Program Files\\Dual Wheel Mouse\\4dmain.exe"));/*显示"E:\Progra~1\dualwh~1\4dmain.exe"*/
  ⑾MatchesMask()
  原型:extern PACKAGE bool __fastcall MatchesMask(const AnsiString Filename, const AnsiString Mask);
  功能:检查文件是否与指定的文件名格式匹配
  参数:FileName:要处理的文件名;Mask:文件名格式,支持通配符
  例:ShowMessage(MatchesMask("Lxf.exe","*.?x?));//显示"true"
  2. 文件管理函数
  这类函数包括设置和读取驱动器、子目录和文件的有关的各种操作,下表列出这类操作常用的函数及其功能。
  函数 功能
  CreateDir() 创建新的子目录
  DeleteFile() 删除文件
  DirectoryExists() 判断目录是否存在
  DiskFree() 获取磁盘剩余空间
  DiskSize() 获取磁盘容量
  FileExists() 判断文件是否存在
  FileGetAttr() 获取文件属性
  FileGetDate() 获取文件日期
  GetCurrentDir() 获取当前目录
  RemoveDir() 删除目录
  SetCurrentDir() 设置当前目录
下面就把这些函数作一一介绍:
  ⑴CreateDir()
  原型:extern PACKAGE bool __fastcall CreateDir(const System::AnsiString Dir);
  功能:建立子目录,如果成功返回true,否则返回false
  参数:Dir:要建立的子目录的名字
  例:Create("ASM");//在当前目录下建立一个名为ASM的子目录
  ⑵DeleteFile()
  原型:extern PACKAGE bool __fastcall DeleteFile(const System::AnsiString FileName);
  功能:删除文件,如果成功返回true,否则返回false
  参数:FileName:要删除的文件名
  例:if(OpenDialog1->Execute())DeleteFile(OpenDialog1->FileName);
  ⑶DirectoryExists()
  原型:extern PACKAGE bool __fastcall DirectoryExists(const System:: AnsiString Name);
  功能:检测目录是否存在,如果存在返回true,否则返回false
  参数:Name:要检测的目录名
  例:if(!DirectoryExists("ASM"))CreateDir("ASM");//如果ASM这个目录不存在则创建之
  ⑷DiskFree()
  原型:extern PACKAGE __int64 __fastcall DiskFree(Byte Drive);
  功能:检测磁盘剩余空间,返回值以字节为单位,如果指定的磁盘无效,返回-1
  参数:Drive:磁盘的代号,0表示当前盘, 1=A,2=B,3=C 以此类推
  例:ShowMessage(DiskFree(0));//显示当前盘的剩余空间
  ⑸DiskSize()
  原型:extern PACKAGE __int64 __fastcall DiskSize(Byte Drive);
  功能:检测磁盘容量,返回值以字节为单位,如果指定的磁盘无效,返回-1
  参数:Drive:磁盘的代号,0表示当前盘, 1=A,2=B,3=C 以此类推
  例:ShowMessage(DiskFree(0));//显示当前盘的容量
  ⑹FileExists()
  原型:extern PACKAGE bool __fastcall FileExists(const AnsiString FileName);
  功能:检测文件是否存在,如果存在返回true,否则返回false
  参数:FileName:要检测的文件名
  例:if(FileExists("AAA.ASM"))DeleteFile("AAA.ASM");
  ⑺FileGetAttr()
  原型:extern PACKAGE int __fastcall FileGetAttr(const AnsiString FileName);
  功能:取得文件属性,如果出错返回-1
  返回值如下表,如果返回$00000006表示是一个具有隐含和系统属性的文件(4+2)
  常量 值 含义
  faReadOnly $00000001 只读文件
  faHidden $00000002 隐含文件
  faSysFile $00000004 系统文件
  faVolumeID $00000008 卷标
  faDirectory $00000010 目录
  faArchive $00000020 归档文件
  例:if(FileGetAttr("LLL.TXT")&0x2)ShowMessage("这是一个有隐含属性的文件");
  与此对应的有FileSetAttr() ,请自已查阅帮助系统
  ⑻FileGetDate()
  原型:extern PACKAGE int __fastcall FileGetDate(int Handle);
  功能:返回文件的建立时间到1970-1-1日0时的秒数
  参数:Handle:用FileOpen()打开的文件句柄。
  例:
  int i=FileOpen("C:\\autoexec.bat",fmOpenRead);
  ShowMessage(FileGetDate(i));
  FileClose(i);
  与此对应的有FileSetDate(),请自已查阅帮助系统
  ⑼GetCurrentDir()
  原型:extern PACKAGE AnsiString __fastcall GetCurrentDir();
  功能:取得当前的目录名
  例:ShowMessage(GetCurrentDir());
  ⑽RemoveDir()
  原型:extern PACKAGE bool __fastcall RemoveDir(const AnsiString Dir);
  功能:删除目录,如果成功返回true,否则返回false
  参数:Dir:要删除的目录名
  例:if(DiectoryExists("ASM"))RemoveDir("ASM");
  ⑾SetCurrentDir()
  原型:extern PACKAGE bool __fastcall SetCurrentDir(const AnsiString Dir);
  功能:设置当前目录,如果成功返回true,否则返回false
  参数:Dir:要切换到的目录名
  例:SetCurrentDir("C:\\WINDOWS");
3. 文件I/O函数
  这类函数完成对文件的读写相关的操作,这种类型的操作和C的基于I/O文件操作类似,下表列出这类操作常用的函数及其功能。
  FileOpen() 打开文件
  FileClose() 关闭文件
  FileRead() 读文件
  FileSeek() 文件定位
  FileWrite() 写文件
  FileCreate() 创建文件
  下面就对这些函数作详细介绍。
  ⑴FileOpen()
  原型:extern PACKAGE int __fastcall FileOpen(const AnsiString FileName, int Mode);
  功能:打开文件,如果成功返回其句柄,否则返回-1
  参数:FileName:要打开的文件名;Mode:打开的方式,取值如下表,可用"或"("")运算符连接。
  常量 值 说明
  fmOpenRead 0 以只读属性打开
  fmOpenWrite 1 以只写属性打开
  fmOpenReadWrite 2 以读/写属性打开
  fmShareCompat 0 兼容FCB方式(汇编中有相应的DOS功能调用,感兴趣自已查阅相关资料)
  fmShareExclusive 16 共享方式:以独占方式打开,在关闭以前,别人不能访问
  fmShareDenyWrite 32 共享方式:拒绝写访问
  fmShareDenyRead 48 共享方式:拒绝读访问
  fmShareDenyNone 64 共享方式:无限制,允许读写
  例:int i=FileOpen("C:\\WINDOWS\\Win.ini",fmOpenReadWritefmShareExclusive);
  ⑵FileClose()
  原型:extern PACKAGE void __fastcall FileClose(int Handle);
  功能:关闭打开的句柄。
  参数:Handle:要关闭的句柄
  例:FileClose(i);
  ⑶FileRead()
  原型:extern PACKAGE int __fastcall FileRead(int Handle, void *Buffer, int Count);
  功能:读文件,返回实际读取的字节数,句柄必须首先由FileOpen或FileCreate创建。
  参数:Handle:要读取的句柄;Buffer:存放读取的数据的缓冲区;Count:想读取的字节数
  例:char str[400];FileRead(hnd1,str,400);
  ⑷FileSeek()
  原型:extern PACKAGE int __fastcall FileSeek(int Handle, int Offset, int Origin);
  功能:移动文件读取指针,成功返回文件指针的位置,失败返回-1
  参数:Handle:相关联的句柄;Offset:移动的量;Orgin:移动的基准,0=文件头,1=当前位置,2=文件尾。
  例:ShowMessage(FileSeek(hnd1,0,2));//取得文件的长度
  ⑸FileWrite()
  原型:extern PACKAGE int __fastcall FileWrite(int Handle, const void *Buffer, int Count);
  功能:写文件,返回实际写入的字节数,句柄必须首先由FileOpen或FileCreate创建。
  参数:Handle:要写入的句柄;Buffer:存放写入数据的缓冲区;Count:想写入的字节数
  例:char str[]="I Love You";FileWrite(hnd1,str,strlen(str));
  ⑹FileCreate()
  原型:extern PACKAGE int __fastcall FileCreate(const AnsiString FileName);
  功能:创建文件。成功返回其句柄,否则返回-1
  参数:FileName:要创建的文件名
  例:if(!FileExists("KC.C"))hnd1=FileCreate("KC.C");

星期一, 九月 03, 2007

C Builder中如何应用消息

标准的BCB程序使用Application->Run()进入消息循环,在Application的ProcessMessage方法中,使用PeekMessage方法从消息队列中提取消息,并将此消息从消息队列中移除。然后ProcessMessage方法检查是否存在Application->OnMessage方法。存在则转入此方法处理消息。之后再将处理过的消息分发给程序中的各个对象。至此,WndProc方法收到消息,并进行处理。如果有无法处理的交给重载的Dispatch方法来处理。要是还不能处理的话,再交给父类的Dispatch方法处理。最后Dispatch方法实际上将消息转入DefaultHandler方法来处理。(嘿嘿,实际上,你一样可以重载DefaultHandler方法来处理消息,但是太晚了一点,我想没有人愿意最后一个处理消息吧)。

1.TApplication的OnMessage事件的应用
在C++Builder开发的应用程序中,任何窗体接收到一个Windows消息都会触发一次OnMessage事件,所以,可以通过相应TApplication对象的OnMessage事件来捕获任何发送给本程序的Windows消息。


OnMessage的事件的处理函数原型如下:
typedef void __fastcall (__closure *TMessageEvent ) (tagMsg &Msg,bool &Handled );
这个处理函数有两个参数,其中参数Msg表示的是被截获的消息,而参数Handled则用来指示本消息是否已经处理完成。在程序中可以通过设置参数Handled为true,以避免后续的过程处理这个消息,反之把Handled设为false则允许后继过程继续处理这个消息。
需要注意的是,OnMessage事件仅仅接受发送到消息队列的消息,而直接通过API函数SendMessage()发送给窗口函数的消息将不会被截获。另外,当程序运行的时候,OnMessage事件被触发的频率有可能非常高,所以这个事件的处理函数代码执行时间将直接影响到整个程序的运行效率。

2.利用消息映射截获消息
C++Builder的VCL提供了对大多数Windows消息的处理机制,对于一般的应用程序是足够了。但是,VCL也不是无所不包的。有的情况下,程序需要处理那些VCL处理没有处理的Windows消息,或者程序需要屏蔽某些特定的消息时,则就需要程序员自己捕获Windows消息。
为此C++Builder提供了一种消息映射机制,通过消息映射程序能将特定的Windows消息与对应的处理函数联系起来,当窗口捕获到这个消息时就会自动调用对应的处理函数。
使用消息映射有一下几个步骤:
(1) 消息映射表,把某些消息的处理权交给自定义的消息处理函数。
这样的消息映射列表应该位于一个组件类的定义中,它以一个没有参数的BEGIN_MESSAGE_MAP 宏开始,以END_MESSAGE_MAP宏结束。END_MESSAGE_MAP宏的唯一参数应该是组件的父类的名字。通常情况下,这个所谓的父类指的就是TForm。在宏BEGIN_MESSAGE_MAP和END_MESSAGE_MAP之间插入一个或者是多个MESSAGE_HANDLER 宏。
MESSAGE_HANDLER宏将一个消息句柄和一个消息处理函数联系在一起。
MESSAGE_HANDLER宏有三个参数:Windows消息名、消息结构体名和对应的消息处理函数名。其中,消息结构体名既可以是通用的消息结构体TMessage,也可以是特定的消息结构体,比如TWMMouse。
在使用消息映射的时候要注意以下两点:
a.一个窗口类定义中只能有一个消息映射表。
b.消息映射必须位于它所引用的所有消息处理函数声明的后面。
(2) 在窗口类中声明消息处理函数
这里的消息处理函数名和参数都必须和对应的MESSAGE_HANDLER宏一致。
一个典型的消息处理函数的声明如下:
void __fastcall 消息处理函数名(消息结构体名 &Message);
例如:
void __fastcall WMNchitTest(TMessage &message);
(3) 实现消息处理函数
消息处理函数的编制和普通的函数没什么太大的差异,唯一不同的是,通常在此函数的最后要加上一条语句 TForm::Dispatch(&Message),以完成VCL对于消息的默认处理。如果没有这一句,消息将会被完全拦截;在某些情况下,VCL可能会因为得不到消息而无法工作。

3.重载WndProc()函数
在某些情况下,程序需要捕获或者屏蔽某些特定的消息,这时可以用前面介绍的消息映射的方法。当然,这种方法也不是唯一的,也可以通过重载窗口函数WndProc()来实现。因为系统将在调用函数Dispatch()派发消息之前调用窗口函数WndProc(),所以,可以通过重载函数WndProc()得到一个在分派消息之前过滤消息的机会。
这个消息处理的窗口函数的原型如下:
virtual void __fastcall WndProc(TMessage &Message);
例如:(详细请看NowCan的例子)
void __fastcall TForm1::WndProc(TMessage &Message)
{
PCOPYDATASTRUCT pMyCDS;
if(Message.Msg==g_MyMsg)
{
ShowMessage("收到注册消息,wParam="+IntToStr(Message.WParam)+" lParam="+IntToStr(Message.LParam));
Message.Result=0;//消息处理的结果,当然在本例中没有意义。
}
else if(Message.Msg==g_MyMsg1)
{
Application->MessageBoxA((char *)Message.LParam,"收到发送方的字符串",MB_OK);
}
else if(Message.Msg==WM_COPYDATA)
{
pMyCDS = (PCOPYDATASTRUCT)Message.LParam;
Application->MessageBoxA((char *)pMyCDS->lpData,"收到发送方的字符串",MB_OK);
}

TForm::WndProc(Message);//其他的消息继续传递下去
}
乍看起来,这和重载Dispatch方法好象差不多。但实际上还是有差别的。差别就在先后次序上,消息是先交给WndProc来处理,最后才调用Dispatch方法的。这样,重载WndProc方法可以比重载Dispatch方法更早一点点得到消息并处理消息。

4.Application->HookMainWindow方法
如果您打算使用Application->OnMessage来捕获所有发送至您的应用程序的消息的话,您大概要失望了。它无法捕获使用SendMessage直接发送给窗口的消息,因为这不通过消息队列。您也许会说我可以直接重载TApplication的WndProc方法。呵呵,不可以。因为TApplication的WndProc方法被Borland申明为静态的,从而无法重载。显而易见,这么做的原因很可能是Borland担心其所带来的副作用。那该如何是好呢?查看TApplication的WndProc的pascal源码可以看到:
procedure TApplication.WndProc(var Message: TMessage);
... // 节约篇幅,此处与主题无关代码略去
begin
try
Message.Result := 0;
for I := 0 to FWindowHooks.Count - 1 do
if TWindowHook(FWindowHooks[I]^)(Message) then Exit;
... // 节约篇幅,此处与主题无关代码略去
WndProc方法一开始先调用HookMainWindow挂钩的自定义消息处理方法,然后再调用缺省过程处理消息。这样使用HookMainWindow就可以在WndProc中间接加入自己的消息处理方法。使用这个方法响应SendMessage发送来的消息很管用。最后提醒一下,使用HookMainWindow挂钩之后一定要对应的调用UnhookMainWindow卸载钩子程序。给个例子:

void __fastcall TForm1::FormCreate(TObject *Sender)
{
Application->HookMainWindow(AppHookFunc);
}
//---------------------------------------------------------------------------
bool __fastcall TForm1::AppHookFunc(TMessage &Message)
{
bool Handled ;
switch (Message.Msg)
{
case WM_CLOSE:
mrYes==MessageDlg("Really Close??", mtWarning, TMsgDlgButtons() << mbYes break;
}
return Handled;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormDestroy(TObject *Sender)
{
Application->UnhookMainWindow(AppHookFunc);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
SendMessage(Application->Handle,WM_CLOSE,0,0);
}
//---------------------------------------------------------------------------

5.自己发送消息
应用程序也可以像Windows系统一样在窗口或者是组件之间发送消息。C++Builder为此提供了几种途径:使用函数TControl::Perform()或者API函数SendMessage()和PostMessage()向特定的窗体发送消息,或者是使用函数TWinControl::Broadcast()和API函数BroadcastSystemMessage()广播消息。


Perform()函数的作用就是将指定的消息传递给TControl的WndProc过程,适用于所有由TControl类派生的对象,Perform()原型如下:
int __fastcall Perform(unsigned Msg, int WParam, int LParam);
要等到消息处理之后才返回。


在同一个应用程序的不同窗体和控件之间使用函数Perform()是非常便捷的。但是这个函数是TControl类的成员函数。也就是说,使用它时,程序必须知道这个接受消息的控件的实例。而在许多情况下程序并不知道这个接受消息的窗体的实例而只是知道这个窗体的句柄,比如,在不同应用程序的窗体之间发送消息就属于这种情况。这时,函数Perform()显然无法使用,取而代之的应该是函数SendMessage()和PostMessage()。


函数SendMessage()和PostMessage()的功能基本上一样,它们都可以用来向一个特定的窗口句柄发送消息。主要的区别是,函数SendMessage()直接把一个消息发送给窗口函数,等消息被处理之后才返回;而函数PostMessage()则只是把消息发送到消息队列,然后就立刻返回。
这两个函数的原型声明分别如下:
LRESULT SendMessage(HWND hWnd,UINRT Msg,WPARAM,wParam,LPARAM,lParam);
BOOL PostMessage(HWND hWnd,UINT Msg,WPARAM,wParam,LPARAM,lParam);
可以看到,这两个函数参数同函数Perform()十分类似,只是增加了一个hWnd参数用以表示目标窗口的句柄。


Broadcast()和BroadcastSystemMessage()
函数Broadcast()适用于所有由TWinControl类派生的对象,它可以向窗体上的所有子控件广播消息。其函数原型如下:
void __fastcall Broadcast(void *Message);
可以看到,这个函数只有一个Message参数,它指向被广播的TMessage类型的消息结构体。
函数Broadcast()只能向C++Builder应用程序中的指定窗体上的所有子控件广播消息,如果要向系统中其他应用程序或者窗体广播消息,函数Broadcast()就无能为力了。这时可以使用API函数BroadcastSystemMessage(),这个函数可以向任意的应用程序或者组件广播消息。其函数原型如下:
long BroadcastSystemMessage(
DWORD dwFlags,
LPWORD lpdwRecipients,
UINT uiMessage,
WPAREM wParam,
LPARAM lParam
);

API技巧集

API技巧集(一)- -




一、拖动无标题窗体:

包含头文件:

#include $#@60;winuser.h$#@62;

在窗体或组件的 OnMouseDown 事件中加入以下代码:

if(Button == mbLeft)
{
ReleaseCapture();
SendMessage( Handle, WM_NCLBUTTONDOWN, HTCAPTION, 0);
}

二、弹出和关闭光驱:

包含头文件:

#include $#@60;mmsystem.h$#@62;

在窗体的OnCreate事件中加入:

mciSendString("open cdaudio alias cd wait shareable",0,0,0);

1、要弹出光驱时使用:

mciSendString("set cd door open",0,0,0);

2、要关闭光驱时使用:

mciSendString("set cd door closed",0,0,0);

三、提取图标:

包含头文件:

#include $#@60;shellapi.h$#@62;

例子:

TIcon *Icon = new TIcon();
AnsiString FileName = "C:\\WINDOWS\\SYSTEM\\SHELL32.DLL";
int TotalIcon;

//得到文件SHELL32.DLL的总图标数
TotalIcon = (int)ExtractIcon(Form1->Handle,FileName.c_str(), -1);

//提取第一个图标,0为第一个,1为第二个,类推...
Icon->Handle = ExtractIcon( Form1->Handle, FileName.c_str(), 0);

//保存图标
Icon->SaveToFile("C:\\1.ICO");

四、设置顶端窗口(永在上面):

包含头文件:

#include $#@60;winuser.h$#@62;

1、设置顶层窗口

SetWindowPos( Handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE||SWP_NOSIZE);

2、取消顶层窗口

SetWindowPos( Handle, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE||SWP_NOSIZE);


API技巧集 (二)

  (一)不规则窗口

  Windows提供的只是标准的矩形窗口,要想建立一个不规则的窗口就需要调用API函数来实现。建立一个不规则的窗口,一般是先用创建区域的API函数建立一个不规则的区域,再用API函数SetWindowRgn改变窗口的区域。这些API函数在C++ Builder中包含在头文件wingdi.h和winuser.h里面,因此,要使用这些API函数就要先在程序头部加上包含头文件的语句:

include $#@60;wingdi.h$#@62;

include $#@60;winuser.h$#@62;

  SetWindowRgn函数能改变一个窗口的区域,该函数有三个参数,第一个参数hWnd是欲设置区域的窗口句柄,第二个参数hRgn是欲设置的区域,第三个参数bRedraw一般设为true,即立即重画窗口。

  用来创建区域的API函数有多个,最常用的有三个:

  1、CreateRectRgn函数,用来创建一个由X1、Y1和X2、Y2坐标点确定的矩形区域。当坐标点X1和Y1相等、X2和Y2也相等的时候,创建的是一个正方形。

  例子:

//创建长方形

HRGN hRect=CreateRectRgn(0,0,400,200);

SetWindowRgn(Handle,hRect,true);

//创建正方形

HRGN hRect=CreateRectRgn(0,0,300,300);

SetWindowRgn(Handle,hRect,true);

  2、CreateEllipticRgn函数,用来创建一个由X1、Y1和X2、Y2坐标点确定的矩形所内切的椭圆。同样,X1、Y1和X2、Y2坐标点所确定的矩形为正方形时,创建的就是一个圆形。

  例子:

//创建椭圆

HRGN hElliptic=CreateEllipticRgn(0,0,400,250);

SetWindowRgn(Handle,hElliptic,true);

//创建圆形

HRGN hElliptic=CreateEllipticRgn(0,0,400,400);

SetWindowRgn(Handle,hElliptic,true);

  3、CombineRgn函数,能将两个区域组合为一个新区域,它有四个参数,第一个参数hrgnDest保存合并后的新区域,第二个参数hrgnSrc1、三个参数hrgnSrc2为欲合并的两个区域,第四个参数fnCombineMode是区域组合的方式,它的值是为下面组合方式之一:

  组合方式 说明

RGN_AND 建立两个区域的交集

RGN_COPY 建立hrgnSrc1的拷贝

RGN_DIFF 建立两个区域不相交的部分

RGN 建立两个区域的并集

RGN_XOR 建立除两个区域并集之外的部分

  例子:

//创建一个圆形和长方形交集的组合形状

HRGN hRect=CreateRectRgn(0,0,300,300);

HRGN hElliptic=CreateEllipticRgn(0,0,400,250);

CombineRgn(hRect,hRect,hElliptic,RGN_OR);

SetWindowRgn(Handle,hRect,true);

  当需要将窗口还原为标准Windows矩形窗口时,只要将SetWindowRgn函数的hRgn参数设为0就行了,如:

SetWindowRgn(Handle,0,true);


API技巧集 (二)



  (二)得到系统声卡的个数

  当我们编写一个多媒体程序(如播放器)的时候,有时需要检测一下计算机中是否安装了声卡,如果没有装声卡程序则会终止运行。

  在这里,我们就要使用API函数waveOutGetNumDevs,调用这个函数可返回系统中安装了的声卡的个数。在C++ Builder 5.0中,它被包含在头文件“mmsystem.h”里面。

  例子:

  1、首先在程序头部加入包含头文件的代码:

#include $#@60;mmsystem.h$#@62;

  2、在窗体的OnCreate事件中加入下面的代码:

int Num;

//得到声卡的个数

Num=waveOutGetNumDevs();

if(Num)

ShowMessage("你有安装了"+IntToStr(Num)+"块声卡");

else

{

ShowMessage("你没有安装声卡!\n程序终止运行!");

Close();

}

  3、编译运行程序。

API技巧集 (二)


  (三)获得、设置鼠标双击的间隔时间

  在指定间隔的时间内,连续两次鼠标单击操作称为双击,双击间隔的时间可以在控制面板中的鼠标属性里面改变。若要在自编的应用程序中能获得或设置鼠标双击的间隔时间,我们只需使用Windows的两个API函数GetDoubleClickTime和SetDoubleClickTime。调用GetDoubleClickTime可以返回鼠标双击的间隔时间,而使用SetDoubleClickTime则可以设置鼠标双击间隔的时间。

  下面让我们来做一个获得和设置鼠标双击间隔时间的简单的程序:

  首先,在Borland C++ Builder 5.0 中新建一个工程,往窗体Form1中添加两个Button组件,把它们的Caption属性分别改为“获取双击间隔时间”和“设置双击间隔时间”,再添加一个Edit组件,将Edit1的Text属性改为“200”,添加一个Label组件,把Caption属性改为“毫秒”。

  然后,双击按钮Button1,在它的OnClick(单击)事件中加入下面的代码:

//返回鼠标双击间隔时间

ShowMessage("鼠标双击间隔时间为"+IntToStr(GetDoubleClickTime())+"毫秒");

  再双击按钮Button2,也在它的OnClick事件中加入代码:

//设置鼠标双击间隔时间

SetDoubleClickTime(StrToInt(Edit1-$#@62;Text));

  最后,按F9编译运行一下程序。点击窗口中的“获取双击间隔时间”按钮就会弹出一个显示当前系统鼠标双击间隔的时间,若要设置鼠标双击间隔的时间,只要改变文本框中的数值,比如300吧,再点击“设置双击间隔时间”按钮就可以了。需要注意的是,鼠标双击间隔时间的单位是毫秒,设置的值越小,间隔的时间就越小,双击的速度就越快,系统默认的是400毫秒,可不要设得太小了,否则“我的电脑”会打不开的(你双击的速度不够快,^_^)。





 API技巧集 (二)



  (四)启动控制面板控制台应用程序

  在控制面板里有许多的控制面板项目,这些项目就是控制台应用程序,它们都是标准的DLL(动态链接库)文件,我们经常需要通过它们来对Windows进行配置。rundll32.exe就是专门用来调用DLL文件的程序,在C++ Builder编程中,我们可以通过使用API函数WinExec运行外部程序rundll32.exe调用DLL来实现启动控制面板的控制台应用程序。下面是收集的一些调用DLL启动控制台应用程序的例子:

  1、打开控制面板  

WinExec("rundll32.exe shell32.dll,Control_RunDLL",SW_SHOWNORMAL);

  2、打开方式对话框

WinExec("rundll32.exe shell32.dll,OpenAs_RunDLL "c:\\autoexec.bat"",SW_SHOWNORMAL);

  3、添加Modem

WinExec("rundll32.exe shell32.dll,Control_RunDLL modem.cpl,,add",SW_SHOWNORMAL);

  4、添加打印机

WinExec("rundll32.exe shell32.dll,SHHelpShortcuts_RunDLL AddPrinter",SW_SHOWNORMAL);

  5、复制磁盘

WinExec("rundll32.exe diskcopy.dll,DiskCopyRunDll",SW_SHOWNORMAL);

  6、鼠标

WinExec("rundll32.exe shell32.dll,Control_RunDLL main.cpl",SW_SHOWNORMAL);

  7、网络

WinExec("rundll32.exe shell32.dll,Control_RunDLL netcpl.cpl",SW_SHOWNORMAL);

  8、密码

WinExec("rundll32.exe shell32.dll,Control_RunDLL password.cpl",SW_SHOWNORMAL);

  9、游戏控制器

WinExec("rundll32.exe shell32.dll,Control_RunDLL joy.cpl",SW_SHOWNORMAL);

  10、日期/时间

WinExec("rundll32.exe shell32.dll,Control_RunDLL timedate.cpl",SW_SHOWNORMAL);

  11、Internet 属性
WinExec("rundll32.exe shell32.dll,Control_RunDLL inetcpl.cpl",SW_SHOWNORMAL);

  12、添加/删除程序

//安装/卸载

WinExec("rundll32.exe shell32.dll,Control_RunDLL appwiz.cpl,,1",SW_SHOWNORMAL);

//Windows 安装

WinExec("rundll32.exe shell32.dll,Control_RunDLL appwiz.cpl,,2",SW_SHOWNORMAL);

//启动盘

WinExec("rundll32.exe shell32.dll,Control_RunDLL appwiz.cpl,,3",SW_SHOWNORMAL);

  13、区域设置

//区域设置

WinExec("rundll32.exe shell32.dll,Control_RunDLL intl.cpl,,0",SW_SHOWNORMAL);

//数字

WinExec("rundll32.exe shell32.dll,Control_RunDLL intl.cpl,,1",SW_SHOWNORMAL);

//货币

WinExec("rundll32.exe shell32.dll,Control_RunDLL intl.cpl,,2",SW_SHOWNORMAL);

//时间

WinExec("rundll32.exe shell32.dll,Control_RunDLL intl.cpl,,3",SW_SHOWNORMAL);

//日期

WinExec("rundll32.exe shell32.dll,Control_RunDLL intl.cpl,,4",SW_SHOWNORMAL);

  14、辅助选项

//键盘

WinExec("rundll32.exe shell32.dll,Control_RunDLL access.cpl,,1",SW_SHOWNORMAL);

//声音

WinExec("rundll32.exe shell32.dll,Control_RunDLL access.cpl,,2",SW_SHOWNORMAL);

//显示

WinExec("rundll32.exe shell32.dll,Control_RunDLL access.cpl,,3",SW_SHOWNORMAL);

//鼠标

WinExec("rundll32.exe shell32.dll,Control_RunDLL access.cpl,,4",SW_SHOWNORMAL);

//常规

WinExec("rundll32.exe shell32.dll,Control_RunDLL access.cpl,,5",SW_SHOWNORMAL);

  15、多媒体

//音频

WinExec("rundll32.exe shell32.dll,Control_RunDLL mmsys.cpl,,0",SW_SHOWNORMAL);

//视频

WinExec("rundll32.exe shell32.dll,Control_RunDLL mmsys.cpl,,1",SW_SHOWNORMAL);

//MIDI

WinExec("rundll32.exe shell32.dll,Control_RunDLL mmsys.cpl,,2",SW_SHOWNORMAL);

//CD 音乐

WinExec("rundll32.exe shell32.dll,Control_RunDLL mmsys.cpl,,3",SW_SHOWNORMAL);

//设备

WinExec("rundll32.exe shell32.dll,Control_RunDLL mmsys.cpl,,4",SW_SHOWNORMAL);

  16、系统

//常规

WinExec("rundll32.exe shell32.dll,Control_RunDLL sysdm.cpl,,0",SW_SHOWNORMAL);

//设备管理器

WinExec("rundll32.exe shell32.dll,Control_RunDLL sysdm.cpl,,1",SW_SHOWNORMAL);

//硬件配置文件

WinExec("rundll32.exe shell32.dll,Control_RunDLL sysdm.cpl,,2",SW_SHOWNORMAL);

//性能

WinExec("rundll32.exe shell32.dll,Control_RunDLL sysdm.cpl,,3",SW_SHOWNORMAL);

  17、显示器

//背景

WinExec("rundll32.exe shell32.dll,Control_RunDLL desk.cpl,,0",SW_SHOWNORMAL);

//屏幕保护

WinExec("rundll32.exe shell32.dll,Control_RunDLL desk.cpl,,1",SW_SHOWNORMAL);

//外观

WinExec("rundll32.exe shell32.dll,Control_RunDLL desk.cpl,,2",SW_SHOWNORMAL);

//设置

WinExec("rundll32.exe shell32.dll,Control_RunDLL desk.cpl,,3",SW_SHOWNORMAL);  

  这些例子在Windows 98和Windows 2000中都可以使用通过,前提是在控制面板中安装了该项目。


API技巧集(三)

  (一)闪烁程序的标题栏

  在某些专业的应用程序中,当程序需要提醒用户或要引起用户的注意时,就不停地闪烁程序的标题栏。要实现这个功能,只需要一个Timer组件和使用一个API函数--FlashWindow。

  使用API函数FlashWindow可以闪烁显示指定窗口,让窗口在活动与非活动的状态之间切换,它有两个参数:hwnd和bInvert,头文件为“winuser.h”。其中,参数hwnd为要闪烁的窗口句柄,参数bInvert是一个bool变量,设为true时,程序窗口标题栏从活动切换到非活动状态、或反向切换,当设为false时,窗口标题栏还原为最初的状态。如果配合一个时间组件(Timer组件),以一定的时间间隔执行语句:

FlashWindow(Form1-$#@62;Handle,true);

程序窗口的标题栏就在活动、非活动的状态之间不停地切换。若把hwnd指定成为应用程序的句柄(Application-$#@62;Handel),将会闪烁程序在任务栏上的标题栏。

  下面就让我们来做一个闪烁窗口标题栏和任务栏上标题栏的程序。

  首先,在Form1中添加三个按钮Button1、Button2和Button3,把它们的属性分别为“闪烁窗口标题栏”、“闪烁任务标题栏”和“停止闪烁”,再加入两个时间组件Timer1和Timer2,将两个Timer组件的Enabled属性都设为false,将Interval属性都设为为500(即半秒),改变这个属性的值可以修改闪烁的频率。

  然后,双击Timer1,在OnTimer事件中加入:

FlashWindow(Form1-$#@62;Handle,true);

  双击Timer2,在OnTimer事件中加入:

FlashWindow(Application-$#@62;Handel,true);

  双击Button1,在Button1的OnClick事件中加入:

Timer1-$#@62;Enabled=true;

  双击Button2,在Button2的OnClick事件中加入:

Timer2-$#@62;Enabled=true;

  最后,双击Button3,在Button3的OnClick事件中加入:

Timer1-$#@62;Enabled=false;

Timer2-$#@62;Enabled=false;

FlashWindow(Form1-$#@62;Handle,false);

FlashWindow(Application-$#@62;Handel,false);

  这样,一个简单的例子就完成了。按F9编译运行程序,你就可闪烁窗口标题栏或是闪烁任务栏上? 题栏了。


  (二)拖动无标题窗体

  现在的Windows应用程序,大都使用了图形化的界面、不规则窗口技术,使得程序界面更加漂亮了。但是,使用界面一般要先把窗体的标题栏去掉(在BCB中,将窗体的BorderStyle属性设为bsNone,就可以把窗体的标题栏去掉),这样就不能使用原来的标题栏了,出现了窗口不能移动的问题。没有标题栏怎样用鼠标拖动窗体呢?我们可以使用Windows的API函数SendMessage来解决这个问题。

  首先,新建一个工程,把窗体的BorderStyle属性设为bsNone去掉窗体的标题栏,按F12键切换到代码编辑窗口,在头部加入包含头文件"winuser.h"的代码:

#include $#@60;winuser.h$#@62;

  然后,在窗体的 OnMouseDown 事件中加入下面的代码:

if(Button == mbLeft)//判断是否按了鼠标左键

{

ReleaseCapture();//释放鼠标操作

SendMessage( Handle, WM_NCLBUTTONDOWN, HTCAPTION, 0);

}

  这样,用鼠标左键点住窗口拖动,就可以实现拖动没有标题的窗口了。也可以在窗体上添加组件,然后在该组件的 OnMouseDown 事件中加入上面的代码,这样也可以点住这个组件拖动窗口。你还可以把SendMessage函数的第一个参数修改为这个组件的句柄,如:往窗体添加一个Button组件,在它的 OnMouseDown 事件中加入上面的代码,其中把SendMessage那行语句改为:

SendMessage( Button1-$#@62;Handle, WM_NCLBUTTONDOWN, HTCAPTION, 0);

这样就可以在程序运行时,用鼠标在窗口的范围内移动Button1了。

  (三)隐藏程序在任务栏的图标

  使用API函数ShowWindow可以隐藏一个程序在任务栏的图标,它被包含在头文件“winuser.h”里面。

  1、隐藏任务栏图标的代码就是:

ShowWindow(Application-$#@62;Handle, SW_HIDE);

  2、要重新显示的时候就使用:

ShowWindow(Application-$#@62;Handle, SW_SHOW);

  但是,如果将程序最小化后,在任务栏的图标就会重新出现。若要在程序还原最小化后,程序在任务栏的图标重新被隐藏起来,可以在窗体的OnPaint事件中加入隐藏程序在任务栏的图标的代码,这样,程序只有在最小化时任务栏才会出现图标,当程序还原最小化时图标又会重新被隐藏起来。


API技巧集(三)




  (四)重启、关闭Windows

  当用户修改了Windows里面的一些设置,Windows经常会提问是否要重新启动计算机,当用户点Yes的时候,计算机将会自动重启。这个就是API函数ExitWindowsEx的一个典型的应用。

  ExitWindowsEx,顾名思义就是退出Windows的函数,它有两个参数,第一个是退出Windows的选项,常用的有:EWX_REBOOT(重新启动计算机),EWX_SHUTDOWN(关闭计算机),EWX_LOGOFF(注销当前用户),第二个参数系统保留没有使用,可设为0。

  在自编的程序中(如:注册表修改程序),当用户修改了某项设置需要重新启动计算机的时候,就要使用EWX_REBOOT选项重启计算机。如:

ExitWindowsEx(EWX_REBOOT,0);

  使用WX_SHUTDOWN选项,可以实现关机。如:

ExitWindowsEx(EWX_SHUTDOWN,0);

  当需要注销的时候,就使用EWX_LOGOFF选项。如:

ExitWindowsEx(EWX_LOGOFF,0);


api技巧集(四)



函数名:

  SetWindowPos

头文件:

  winuser.h

函数原型:

  BOOL SetWindowPos
  (
  HWND hWnd, //窗口句柄
  HWND hWndInsertAfter, //排列顺序的句柄
  int X, //水平坐标
  int Y, //垂直坐标
  int cx, //宽
  int cy, //高
  UINT uFlags //窗口定位标识
  );

说明:

  这个函数能改变窗口的大小、位置和设置子窗口、弹出窗口或顶层窗口的排列顺序。
  返回值:

  BOOL,如果返回值非零表示成功,返回零表示失败。错误信息请参看GetLastError函数。

参数表:

  参数 类型及说明
  hwnd HWND,欲定位的窗口句柄
  hWndInsertAfter HWND,置于hwnd前面的窗口句柄。这个参数必须是窗口的句柄或是下面的值之一:   HWND_BOTTOM 将窗口置于其它所有窗口的底部
  HWND_NOTOPMOST 将窗口置于其它所有窗口的顶部,并位于任何最顶部窗口的后面。如果这个窗口非顶部窗口,这个标记对该窗口并不产生影响
  HWND_TOP 将窗口置于它所有窗口的顶部
  HWND_TOPMOST 将窗口置于其它所有窗口的顶部,并位于任何最顶部窗口的前面。即使这个窗口不是活动窗口,也维持最顶部状态

x: 
 
  int,指定窗口新的X坐标

Y:  

  int,指定窗口新的Y坐标

cx:  

  int,指定窗口新的宽度

cy:  

  int,指定窗口新的高度

wFlags:

  UINT,指定窗口状态和位置的标记。这个参数使用下面值的组合: SWP_DRAWFRAME 围绕窗口画一个框
  SWP_FRAMECHANGED 发送一条WM_NCCALCSIZE消息进入窗口,即使窗口的大小没有发生改变。如果不指定这个参数,消息WM_NCCALCSIZE只有在窗口大小发生改变时才发送
  SWP_HIDEWINDOW 隐藏窗口
  SWP_NOACTIVATE 不激活窗口
  SWP_NOCOPYBITS 屏蔽客户区域
  SWP_NOMOVE 保持当前位置(X和Y参数将被忽略)
  SWP_NOOWNERZORDER 不改变所有窗口的位置和排列顺序
  SWP_NOREDRAW 窗口不自动重画
  SWP_NOREPOSITION 与SWP_NOOWNERZORDER标记相同 r>   SWP_NOSENDCHANGING 防止这个窗口接受WM_WINDOWPOSCHANGING消息
  SWP_NOSIZE 保持当前大小(cx和cy会被忽略)
  SWP_NOZORDER 保持窗口在列表的当前位置(hWndInsertAfter将被忽略)
  SWP_SHOWWINDOW 显示窗口


备注:

  如果设置了SWP_SHOWWINDOW或SWP_HIDEWINDOW标记,这个窗口不发生移动或改变大小。窗口成为最顶级窗口后,它的所有子窗口也会进入最顶级。一旦将其设为非最顶级,则它的所有子窗口也会转为非最顶级。

相关函数:

  MoveWindow,SetActiveWindow,SetForegroundWindow

例子:

  //设置顶层窗口
  SetWindowPos( Handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE||SWP_NOSIZE);

  //取消顶层窗口
  SetWindowPos( Handle, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE||SWP_NOSIZE);



api技巧集(四)




超级链接效果

  在很多共享软件的关于对话框里有一些模仿网页的超级链接,如主页URL或E-Mail之类的,当鼠标移到它上面的时候,文字变成红色的,当鼠标离开时,文字又变回原来的蓝色,如果用鼠标点击这个链接则会弹出浏览器窗口打开指定的URL或是运行默认的E-Mail程序撰写新邮件,就和真的超链接一样。你是不是也想在你的程序里做一个呢?其实,我们只要调用API函数ShellExecute和在鼠标移动时改变一下文字的颜色,就可以在自己的程序中出现这种效果。

  首先新建一个工程,在窗体Form1上添加两个Label组件,它们的Name属性使用默认的Label1和Label2。

  然后在Form1的OnCreate事件中加入代码:

Label1-$#@62;Cursor=crHandPoint;

Label2-$#@62;Cursor=crHandPoint;

Label1-$#@62;Font-$#@62;Color =clBlue;

Label2-$#@62;Font-$#@62;Color =clBlue;

Label1-$#@62;Caption="主页:初学者之家网站";

Label2-$#@62;Caption="E-Mail:fdlweb@sina.com";

  再在Label1的OnClick(单击)事件中加入:

//蓝色的字请改成自己的主页地址

ShellExecute(Handle,NULL,"http://fdlweb.myrice.com/",NULL,NULL,SW_SHOWNORMAL);

  在OnMouseMove事件中加入:

Label1-$#@62;Font-$#@62;Color=clRed;

  在Label2的OnClick事件中加入:

//蓝色的字请改成自己邮箱地址

ShellExecute(Handle,NULL,"mailto:fdlweb@sina.com",NULL,NULL,SW_SHOWNORMAL);

  在OnMouseMove事件中加入:

Label2-$#@62;Font-$#@62;Color=clRed;

  最后在Form1的OnMouseMove事件中加入:

Label1-$#@62;Font-$#@62;Color=clBlue;

Label2-$#@62;Font-$#@62;Color=clBlue;

  代码输入完了,按F9编译运行程序就看到效果了。



拷贝屏幕

  BitBlt函数可以将一幅位图从一个设备场景拷贝到另一个设备场景,这个函数经常用在抓图程序和游戏编程方面,也可以用来做基于桌面的屏幕保护程序。下面让我们用BitBlt函数来做一个虚假桌面的程序:

  首先,添加一个Image组件到窗体中,将窗体Form1的BorderStyle属性设为:bsNone。

  接着在窗体的OnCreate事件加入程序代码:

Left=0;

Top=0;

Width=Screen-$#@62;Width;

Height=Screen-$#@62;Height;

Image1-$#@62;Left=0;

Image1-$#@62;Top=0;

Image1-$#@62;Width=Screen-$#@62;Width;

Image1-$#@62;Height=Screen-$#@62;Height;

//这句代码就是将桌面拷贝到组件Image1中来存放,

// 其中GetDC(0)返回桌面设备的句柄(HDC)

BitBlt(Image1-$#@62;Canvas-$#@62;Handle,0,0,Screen-$#@62;Width,Screen-$#@62;Height,GetDC(0),0,0,SRCCOPY);

  按F9运行,一个假的桌面就出来了,在这个“桌面”上怎么按鼠标都没有反应,可以用来捉弄人喔!。有些桌面的小游戏也是这么干的,你可以在这个程序的基础上加上更多的功能,如在窗体上加上Label组件和Timer组件,用Timer组件来控制Label组件在窗体上移动,再在窗体Form1的OnKeyDown事件和Image1的OnMouseDown事件中加入关闭窗口的代码“Close();”,最后将编译了的程序的扩展名改为scr,这就成了一个文字在桌面上乱动的屏幕保护程序了。






取得磁盘总空间和剩余空间

  要取得磁盘总空间和剩余空间,最简单直接的方法是调用API函数 GetDiskFreeSpace。

  GetDiskFreeSpace函数有5个参数,第一个参数是要判断可用空间的驱动器名,第二个参数是一个存放每簇扇区数的变量,第三个参数是一个存放每扇区字节数的变量,第四个参数是存放剩余簇数的变量,第五个参数是存放总簇数的变量。套用相应计算磁盘空间的公式即可得出指定驱动器的总空间或剩余空间。

磁盘总空间和剩余空间的计算公式分别为:

  磁盘上剩余空间(字节) = 簇的扇区数 * 扇区的字节数 * 剩余簇数

  磁盘上总空间(字节) = 簇的扇区数 * 扇区的字节数 * 总簇数

下面就是取得C盘的总空间和剩余空间的例子:

unsigned long Sectors,Bytes,Free,Total;

GetDiskFreeSpace("C:\\",&Sectors,&Bytes,&Free,&Total);

//可用空间(单位:MB)

int FreeKB = Bytes * Sectors * Free / 1024;

//总空间(单位:MB)

int TotalKB = Bytes * Sectors * Total / 1024;

ShowMessage("C盘的可用空间有:" + IntToStr(FreeKB) + "MB,总空间有:" + IntToStr(TotalKB) +"MB");



api技巧集(五)

提取图标


  调用API函数ExtractIcon可以提取出在程序文件中的图标,它的头文件是shellapi.h,原型为:

HICON ExtractIcon
(
HINSTANCE hInst, //实例句柄
LPCTSTR lpszExeFileName, //要提取图标的那个程序的文件名
UINT nIconIndex //要提取的图标的索引
);

  调用该函数时,参数hInst一般设为当前应用程序的实例句柄,如:Form1-$#@62;Handle。

  参数lpszExeFileName为需要提取图标的程序文件的完整路径,这个程序文件可以是EXE文件、DLL文件、ICO文件等,只要是包含有图标资源的文件一般都可以提取图标。

  当参数nIconIndex指定一个图标的索引可以返回指向图标的句柄,如指定的文件中不存在图标,则返回零,当参数nIconIndex设为-1,函数返回文件的图标总数。

  函数返回的句柄可以赋给一个用TIcon类声明的变量,再使用该变量的SaveToFile方法就可以把图标保存出来。

例子:

TIcon *Icon = new TIcon();
AnsiString FileName = "C:\\WINDOWS\\SYSTEM\\SHELL32.DLL";
int TotalIcon;
//得到文件SHELL32.DLL的总图标数
TotalIcon = (int)ExtractIcon(Form1->Handle,FileName.c_str(), -1);
//提取第一个图标,0为第一个,1为第二个,类推...
Icon->Handle = ExtractIcon( Form1->Handle, FileName.c_str(), 0);
//保存图标
Icon->SaveToFile("C:\\1.ICO");
  下面给出一个完整的图标提取程序源码。

  这个程序需要四个按钮控件(Button)、四个文本标签控件(Label)、两个文本框控件(Edit)、一个水平滚动条控件(ScrollBar)、一个打开文件对话框控件(OpenDialog)、一个保存文件对话框控件(SaveDialog)和一个图片控件(Image),还有一个Panel控件是装饰用的。界面如图所示:

             

  把各个控件排列好,再把四个Label控件的Caption属性修改一个,最后输入程序代码,运行程序,一个提取图标的程序就出来了,你以后也就不会为没有图标资源可用而发愁了。

程序清单(Unit1.cpp):
//--------------------------------------- ----------------------
#include $#@60;vcl.h$#@62;
#pragma hdrstop
#include "Unit1.h"
//----------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
AnsiString FileName;
TIcon *Icon = new TIcon();
int TotalIcon;
//----------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}

//----------------------------------------------------------------

void __fastcall TForm1::FormCreate(TObject *Sender)
{

Caption="图标小偷 1.0";
Button1-$#@62;Caption="选择文件";
Button2-$#@62;Caption="保存图标";
Button3-$#@62;Caption="保存所有";
Button4-$#@62;Caption="退出";
Edit1-$#@62;Text=0;
Edit2-$#@62;Text=0;
Image1-$#@62;Width=32;
Image1-$#@62;Height=32;
OpenDialog1-$#@62;Filter="可执行文件(*.exe,*.dll)|*.exe;*.dll|图标文件(*.ico)|*.ico|所有文件(*.*)|*.*";
SaveDialog1-$#@62;Filter="图标文件|*.ico";
ScrollBar1-$#@62;Enabled=false;
Button2-$#@62;Enabled=false;
Button3-$#@62;Enabled=false;

}
//----------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{

if(OpenDialog1-$#@62;Execute())
{

TotalIcon = (int)ExtractIcon( Form1-$#@62;Handle, OpenDialog1-$#@62;FileName.c_str(), -1 );
if(TotalIcon$#@62;0)
{

if(TotalIcon$#@60;2)

ScrollBar1-$#@62;Enabled=false;

else

ScrollBar1-$#@62;Max=TotalIcon-1;

Button2-$#@62;Enabled=true;
Button3-$#@62;Enabled=true;
FileName = OpenDialog1-$#@62;FileName;
Edit1-$#@62;Text =TotalIcon;
Icon-$#@62;Handle = ExtractIcon( Form1-$#@62;Handle, FileName.c_str(), 0);
Image1-$#@62;Picture-$#@62;Icon=Icon;
Edit2-$#@62;Text=1;

}
else
{

ShowMessage("该文件没有图标");

}

}

}
//----------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{

if(SaveDialog1-$#@62;Execute())
{

//保存图标
Icon-$#@62;SaveToFile( SaveDialog1-$#@62;FileName);

}

}
//----------------------------------------------------------------
void __fastcall TForm1::Button3Click(TObject *Sender)
{

if(SaveDialog1-$#@62;Execute())
//提取所有的图标
for(int i=0;i$#@60;TotalIcon-1;i++)
{

Icon-$#@62;Handle = ExtractIcon( Form1-$#@62;Handle, FileName.c_str(), i);
Icon-$#@62;SaveToFile(SaveDialog1-$#@62;FileName+(AnsiString)i+".ico");

}

}
//----------------------------------------------------------------
void __fastcall TForm1::Button4Click(TObject *Sender)
{

Close();

}
//----------------------------------------------------------------
void __fastcall TForm1::ScrollBar1Change(TObject *Sender)
{

Edit2-$#@62;Text=ScrollBar1-$#@62;Position+1;
Icon-$#@62;Handle = ExtractIcon(Form1-$#@62;Handle, FileName.c_str(),ScrollBar1-$#@62;Position);
Image1-$#@62;Picture-$#@62;Icon=Icon;

}
//----------------------------------------------------------------

判断驱动器的类型


  使用API函数GetDriveType能判断一个驱动器的类型,该函数返回一个int型的值,当返回值为2时,是软盘;为3时,是硬盘;为4时,是网络映射盘;为5时,是光驱;为6时,是 RAM 磁盘;为其它值时,是非法的盘符。这个API函数包含在winbase.h头文件中,首先在程序头部加上语句:

include $#@60;winbase.h$#@62;

包含头文件,然后在程序中加入以下代码就可以判断驱动器的类型:

int drv;
//这里的"C:\\"为要判断的盘符
drv=GetDriveType("C:\\");
switch (drv) //判断drv的值
{
case 2 : //DRIVE_REMOVABLE

ShowMessage("软盘");
break;

case 3 : //DRIVE_FIXED

ShowMessage("硬盘");
break;

case 4 : //DRIVE_REMOTE

ShowMessage("网络映射盘");
break;

case 5 : //DRIVE_CDROM

ShowMessage("光驱");
break;

case 6 : //DRIVE_RAMDISK

ShowMessage("RAM 磁盘");
break;

default :

ShowMessage("这个磁盘不存在!");
break;

}

注:case语句后的数值也可以用注释后的常数替换。如2可用常数 DRIVE_REMOVABLE 来替换。


api技巧集(七)


窗口最小化、最大化和恢复

  通过调用API函数ShowWindow可以控制指定窗口的状态,如将窗口最小化、最大化或者是恢复原来的状态,等等。

  虽然通过窗口标题栏上的控制按钮也可以将窗口最小化、最大化或者是恢复,但ShowWindow函数能实现更多的功能,又如隐藏窗口、将窗口最小化到桌面等,这些是标准的控制按钮所做不到的。

  下面介绍一个ShowWindow函数的例子。这个例子演示了如何将一个窗口最小化到桌面或最小化到任务栏和最大化、恢复窗口原始状态。

  首先,在C++ Builder中新建一个工程,为了方便演示,工程需要两个窗口。添加第二个窗口Form2的方法是:选择“File”菜单下的“New Form”。添加了新窗口后,选择“File”菜单下的“Include Unit Hdr...”包含窗口Form2的头文件“Unit2.h”,或是直接在Form1的代码编辑窗口的头部加上“#include "Unit2.h"”语句。然后在Form1上放上四个按钮,它们的Caption属性分别为“最大化”、“最小化到桌面”、“恢复”和“最小化到任务栏并恢复”。

  接着,双击窗件Form1,在它的OnCreate事件中加入:

void __fastcall TForm1::FormCreate(TObject *Sender)

{

  //设置Form1为顶层窗口

Form1-$#@62;FormStyle=fsStayOnTop;

}

  双击按钮Button1,在它的OnClick事件中加入:

void __fastcall TForm1::Button1Click(TObject *Sender)

{

  //最大化

ShowWindow(Form2-$#@62;Handle, SW_MAXIMIZE);

}

双击按钮Button2,在它的OnClick事件中加入:


void __fastcall TForm1::Button2Click(TObject *Sender)

{ //最小化到桌面

ShowWindow(Form2-$#@62;Handle, SW_MINIMIZE);

}

双击按钮Button3,在它的OnClick事件中加入:

void __fastcall TForm1::Button3Click(TObject *Sender)

{

  //恢复最小化

ShowWindow(Form2-$#@62;Handle, SW_RESTORE);

}

{{??最??苤赵??蛹? 酸???蔑棠奴 ??锸◆ ?硌斯譬 ?拨霾蝌?棠 utton4腔OnClick岈璃?〔????别载陇?ㄛ?洁楼??跺??腔测钨ㄩ

void __fastcall TForm1::Button4Click(TObject *Sender)

{

  //最小化到任务栏

ShowWindow(Application-$#@62;Handle, SW_MINIMIZE);

  //延时1秒

Sleep(1000);

  //恢复最小化

ShowWindow(Application-$#@62;Handle, SW_RESTORE);

}

  最后,编译运行程序。

  获取磁盘序列号、卷标和文件系统类型

  使用API函数GetVolumeInformation,可以获取一个磁盘的有关信息,如磁盘的序列号、卷标、文件系统类型。有些软件就是利用磁盘的序列号来加密的。

  需要获取磁盘信息的时候,加入下面的代码就可以了:

  //定义长度为255的卷标字符串变量缓冲区:

AnsiString VolumeName=AnsiString::StringOfChar(" ", 255);

  //序列号

unsigned long SerialNumber;

  //定义长度为20的文件系统类型字符串缓冲区

AnsiString SystemName = AnsiString::StringOfChar(" ",20);

  //获取磁盘信息

GetVolumeInformation("C:\\", VolumeName.c_str(), 255, &SerialNumber, 0, 0, SystemName.c_str(), 20);

ShowMessage("C盘的卷标:" + Trim(VolumeName));

ShowMessage("C盘的序列号:" + IntToStr(SerialNumber));

ShowMessage("C盘的文件系统类型:" + Trim(SystemName));
  屏幕放大镜

  你一定用过Windows98自带的那个屏幕放大镜吧,你想不想自已做一个呢?其它,这个程序的关键是使用了API函数StretchBlt。

  调用API函数StretchBlt可以把一个设备中指定大小的位图从拷贝到另一个设备,在拷贝的过程中,还可以根据需要来缩放位图。

  下面是它的原型和参数说明:

BOOL StretchBlt

(

HDC hdcDest, //目标设备句柄

int nXOriginDest, //目标矩形左上角的X坐标

int nYOriginDest, //目标矩形左上角的Y坐标

int nWidthDest, //目标矩形的宽度

int nHeightDest, //目标矩形的高度

HDC hdcSrc, //源设备句柄

int nXOriginSrc, //源矩形左上角的X坐标

int nYOriginSrc, //源矩形左上角的Y坐标

int nWidthSrc, //源矩形的宽度

int nHeightSrc, //源矩形的高度

DWORD dwRop //光栅运算操作

);

  StretchBlt函数的头文件为“wingdi.h”。其中,它的dwRop参数有15种操作,最常用的就是拷贝运算SRCCOPY了。当源设备和目标设备指定的矩形大小不相等时,函数会根据源矩形和目标矩形的大小比例对位图进行放大或缩小操作后,拷贝到目标设备中。

  下面就是一个把屏幕上左上角坐标为0x0、宽和高都为100的矩形位图缩小2倍后拷贝到图片控件Image1中的例子:

StretchBlt(Image1-$#@62;Canvas-$#@62;Handle, 0, 0, 50, 50, GetDC(0), 0, 0, 100, 100, SRCCOPY);

  这句代码的GetDC(0)语句为取得桌面设备的句柄。

  如果不断地使用上面那句代码,把屏幕缩小放到Image1中,这就成一个“屏幕缩小镜”了。当然,缩小屏幕并没有什么实际的用处,我们只要把它改一下就可以做成“屏幕放大镜”了。

  要做这个“屏幕放大镜”,首先要运行Borland C Builder,在窗体Form1上放上一个图片控件Image1和一个时间控件Timer1。

双击窗体Form1,在它的OnCreate事件中加入代码:

void __fastcall TForm1::FormCreate(TObject *Sender)

{

Image1-$#@62;Width=200;

Image1-$#@62;Height=200;

Timer1-$#@62;Interval=10;
  //设置顶层窗口

SetWindowPos( Handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE||SWP_NOSIZE);

}

  双击时间控件Timer1,在它的OnTimer事件中加入以下代码:

void __fastcall TForm1::Timer1Timer(TObject *Sender)

{

int x,y;

POINT CurPos;

  //取得鼠标当前坐标

GetCursorPos(&CurPos);

  //保证拷贝的图象不在屏幕外

if(CurPos.x $#@62;Screen-$#@62;Width - 100)

x=Screen-$#@62;Width - 100;

else if(CurPos.x $#@60;50)

x=0;

else

x=CurPos.x-50;

if(CurPos.y $#@62;Screen-$#@62;Height-100)

y=Screen-$#@62;Height-100;

else if(CurPos.y $#@60;50)

y=0;

else

y=CurPos.y-50;

Caption="坐标:" + IntToStr(CurPos.x) + "," + IntToStr(CurPos.y);

Image1-$#@62;Canvas-$#@62;FillRect(Rect(0,0,200,200));
  //拷贝放大图象

StretchBlt(Image1-$#@62;Canvas-$#@62;Handle, 0, 0, 200, 200, GetDC(0), x, y, 100, 100, SRCCOPY);

}

  代码输入完了,按F9或点击运行按钮运行程序。怎么样?和Windows自带的那个差不多吧!

  需要注意的是:C++ Builder并象VB那样图片控件可以是非持久性的,在C++ Builder中,并不能直接不断地调用StretchBlt函数来得到连贯的图象,而是要先使用图片控件的FillRect方法填充图片框(相当于清空图片框),再调用StretchBlt函数才行。

  时间的延迟

  延迟在程序设计中非常有意义!比如,程序启动时的等待画面,又或者你需要等待一个过程的完成才能运行程序下面的代码,这时就要使用到时间的延迟了。

  但是在很多编程语言中一般都没有现成的延迟函数。在Dos的C时代,当程序需要延迟时,有不少人使用的是for循环:

for(int i=0;i$#@60;10000;i++);

  到现在也可能还有人在用吧。到了Win32时代,在系统的API函数库里已经提供有时间延迟的函数了,它就是Sleep函数。当然,在Windows编程中,你也可以使用Timer控件,但使用Sleep函数更方便、快捷。我们只需简单的调用一下Sleep函数,就可以实现时间的延迟。

  Sleep函数只有一个参数cMilliseconds,用来指定需要延迟的时间,它的单位是毫秒。让我们看下面的例子,请在一个按钮的单击(OnClick)事件中加入下面的代码:

Sleep(3000);//延迟三秒

ShowMessage("本对话框已经延迟了三秒!");

  这个例子演示了一个延时的对话框,单击了该按钮,本应立即弹出的对话框延迟了三秒钟的时间才弹出。

BCB6常见问题

1.先安装一些控件后,以后卸载,但编译后来的项目总提示找不到。。。,需要给一些lib,bpi指定路径?

解决方法:close掉工程,使用ultraedit打开.bpr文件,把你卸掉的一些*.bpi,*.lib从 ,中手工删除掉,保存。然后再打开编译就好了。

2.从旧版本cb项目中copy过来的文件,dfm格式以文本编辑器打开后是乱码?

cbuidler中打开,切换到设计视图,右键选中“Text DFM”,OK!

3.旧版本cb项目中的copy过来的Form,先执行FormCreate才执行构造函数?

使用ultraedit,执行批量替换: 选定你的代码目录录,对所有..dfm文件,执行

“OldCreateOrder = True” 替换为 “OldCreateOrder = False”

4. 加入到cc中的项目,打开时报错,提示“File Access Denied”或直接close你的cb6?

第一个问题是不应该把.res文件加入到cc,应该把该文件保存为私有; 第二种情况需要你把项目 .bpr,.bpf,.cpp三个文件先checkout,然后再打开,就没问题了!

5.使用TList时,使用delete 清除?

使用TList,一般我们都会 使用new ,添加指针类型到 TList中作为元素,因此在删除时,必须先delete每一个元素,再执行clear,然后在delte TList对象本身,如:

if (pSubExeList)
{
TSubExe* pSubExe=NULL;
for (int i = 0; i < pSubExeList->Count; i++)
{
pSubExe = (TSubExe*)pSubExeList->Items[i];
delete pSubExe;
}
pSubExeList->Clear();
delete pSubExeList;
pSubExeList = NULL;
}

虽然这是一个很简单的问题,但还是可以看到很多写的不正确的代码,:(

6.如果先生成了一个Form,后来需要把这个Form改为从另外一个基类Form继承?

方法是:1.修改类定义的方法,添加从基类继承;
2.修改构造函数,改为执行基类的构造函数;
3.点击Form,右键-》View As Text ,然后修改 第一个object为inherited

7.在cbuilder查找一个函数很麻烦?

建议使用gexperts工具,其中有一个功能 “Procedure List”,把这个菜单项拖到编辑区的右边,非常容易找函数,在代码量很多的情况下很方便。

另外这个工具还有个最常用的功能是:注释块和取消注释。写代码时没有这个东东真是累。

8.在实现自定义控件的时候或者动态构建界面的时候,需要写很多动态创建控件的代码。不知道怎么写或写起来太累?

有一个好方法,也是gexperts工具提供的,“Component to code”,先创建一个临时FOrm,把你想要动态创建的布局设计好,然后选中控件,点击“Component to code”,自动帮你生成了代码,你只需要copy过来,稍加整理就可以了。

9.特别多的头文件,到处都要添加include代码?

可以定义一个专门的.h 文件,把通常需要包含的所有include代码写在里面;以后用的时候就只用添加这一个.h 了。

10.几个常用的API函数:

找窗口:注意第一个是类名;第二个是窗口的Caption,返回窗口句柄

FindWindow(className,FormCaption)

动态启动另外一个可执行程序Exe,或者是打开文档:注意第四个参数,可用来传递程序的启动参数,参数之间以空格隔开,取参数。

ShellExecute (ParentFormHandle,"open",filename,startup arguments,default dir ,Show Mode)

取应用程序启动参数:

ParamCount() :取参数个数;

ParamStr(argument index):取参数,因为ParamStr(0)标识的是执行程序文件的名称,因此实际上第一个参数是ParamStr(1);

发送消息:

PostMessage(Target WIndow Handle,Message Type ID,Message content Ptr,LParam):使用PostMessage时,当第二个参数,即自定义的消息标识
SendMessage(Target WIndow Handle,Message Type ID,Message content Ptr,LParam):用于发送消息,但等待结果返回。



PostMessage在进程内部使用的时候,消息内容含有指针类型,可以被成功接收;如跨进程,则只能使用copydata类型, SendMessage方法进行消发送:

COPYDATASTRUCT data;
data.dwData = MsgFlag; //ת·¢ÏûÏ¢±êʶ
data.cbData = Msg.Length();
//memcpy(data.lpData,cMsg,strlen(cMsg));
data.lpData = Msg.c_str();

SendMessage(pExeWnd,WM_COPYDATA,(WPARAM)Application->Handle,(LPARAM)&data);

11.TImage控件可以使用.gif格式的图片?

刚开始用的时候,发现TImage控件可以支持.gif格式的图片;后来发现又不行了,觉得很奇怪。原来是因为把TeeChart7控件卸载了! 装了TeeChart后,TeeChart自己包含了GifImage.pas,经过编译安装后就可以让Timage在设计时加载Gif格式的图片了(不过还没试能不能显示动画)

12.TLabel控件需要内容纵向居中?

开始一直以为TLabel控件不能纵向居中,后来才发现lauout!很多控件都有layout属性,如果是内容布局的问题,就尝试设置一下layout!

13. 图标资源都是gif或者jpg格式的,不能在TImageList中使用?

这要借助于Acdsee工具,打开Acdsee,选中所有你的gif或是jpg格式的图片,右键“工具”……“转换文件格式”……选中你bmp或者ico,然后就可以加在imagelist中使用了!

或者使用Snagit工具,在snagit中有个“BatchConvertImages”更方便、好用。

14. delete Component的时候出现异常?

有的时候会犯一个简单的错误,如:

TFrame* pFrame;

void __fastcall TMainForm::CreateFrame()
{
pFrame = new TFrame(Application);
}

void __fastcall TMainForm::~TMainForm()
{
if(pFrame)
delete pFrame;
}

在执行析构的时候可能会导致异常。主要是因为构造的时候不应使用Application作为Owner,应该使用MainForm作为其Owner。所以在构造Component的时候一定要注意把哪个对象作为Owner,因为Owner负责对象流的保存及资源释放等。



第二部分

1、BCB 编辑快捷键

左/右移 块代码

选中 块代码
1 CTRL+ SHIFT+ I 是整片往右移,
2 CTRL+ SHIFT+ U 是整片文字往左移

2、得到执行程序的当前路径

ExtractFileDir(Application->ExeName);


3、循环中响应其它操作

在循环内加入Application->ProcessMessage()这一句。

4、向外部提供dll函数标准windows格式

extern "C" __declspec(dllexport) __stdcall __int32 Fun(__int32 n32_i);

5、从外部dll输入函数标准windows格式

extern "C" __declspec(dllimport) __stdcall __int32 Fun(__int32 n32_i);

6、对DLL的调试

RUN/PARAMETERS 中填上调用该DLL的 *.exe。

7、使用*.chm帮助文件

ShellExecute(NULL,NULL,帮助文件的路径,NULL,NULL,SW_SHOWNORMAL);


8、PB_C数据类型转换表

PB_C数据类型转换表 MICROSOFT PB(16Bit) PB(32Bit)
Bool Boolean Boolean
Byte, Char Char Char
Char* Ref string Ref String
Colorref Uint Ulong
Double Double Double
Dword Uint Ulong
Float N/A N/A
Handle Uint Ulong
Hdc Uint Ulong
Hfile Uint Ulong
Hinstance Uint Ulong
Hwnd Uint Ulong
Int Int Int
Long Long Long
Lparam Uint Ulong
Lpbyte Ref Int Ref Long
Lpcwstr Ref Blob Ref Blob (Unicode use ToUnicode())
Lpcvoid Ref String Ref String
Lpdword Ref Uint Ref Ulong
Lpfiletime Ref Time Ref Time
Lpint Ref Int Ref Long
Lpstr,Lpcstr Ref String Ref String
Lpvoid Ref Structstruct_inst Ref Struct struct_inst
Lpword Ref Int Ref Ulong
Mcierror Long Long
Pbyte Ref Int[#] Ref Long[#]
Short Int Int
Structure Ref Struct struct_inst Ref Struct Struct_inst
Uint Uint Uint
Void** SUBROUTINE SUBROUTINE
Word Int Long
Wparam Uint Ulong


9、使用CB内存漏洞工具

选中Progect/Option->CodeGuard

支持环境CG32.LIB/CG32.DLL

10、MFC基本运行库目录
mfc42.dll
MFC42D.DLL
MFCD42D.DLL
MFCN42D.DLL
MFCO42D.DLL
MSVCP60.DLL
MSVCP60D.DLL
MSVCRTD.DLL
NTDLL.DLL


11、数据库连接测试(ADO)

建一文件,*.udl,内容空。
双击,按照提示操作。


12、编译器设置

Project|Options

Compiler(编译)
"Full debug"(完全调试模式)
"Code optimization"(代码优化)

"debugging"(调试)
"Debug information"(调试信息)
"Line number information"(行数信息)
"Disable inline expansions"(禁用内联扩展)

"Pascal"标签

"Optimization"优化
"debugging"(调试)

"Linker"(链接)
"Create debug information"(生成调试信息)
"Don’t generate state files"(不要生成状态文件)
"Use dynamic RTL"(使用动态RTL)

"Directories/Conditionals"(路径/条件)

"Packages"(程序包)
"Build with runtime packages"(带运行时程序包编译)


Tools|Debugger Options
Integrated debugging"(集成调试器)

Project|Build All(彻底的编译)



13、设置RTL

C builder 有几种运行时库,多线程静态链接库,单线程静态链接库 以及动态的,含有

VCL的,下面介绍多线程静态链接库,单线程静态链接库 是没有VCL的,VCL中自动 包含多线程。

Use RTL multi-threaded static library 使用多线程静态链接库

到*.bpr 中,按下面的修改即可。



Use RTL single-threaded static library 使用单线程静态链接库

到*.bpr 中,按下面的修改即可。



14、CODEGUARD调试器

库文件CG32.LIB/CG32.DLL
一、编译 (Project/Option-> CodeGuard)
二、运行(Tools/CodeGuard Configuration)
文件为*.CGI
日志文件中,文件名为 *.CGI。用 View/Debug Window/CodeGuard Log察看或者记事本。

星期三, 八月 29, 2007

打造最快的数据导出到Excel文件

关键词:DBGrid,导出,Excel,快速,OLE,另存为xls文件,记录集导出为文件,记录集

在很多的数据库应用中我们都要用到将我们的数据导出到文件的功能,为了便于对导出数据的进一步操作,
导出为Excel可以操作的文件成为很多时候的首选。但是将数据导出并不是非常的方便,Excel并没有直接提供调用的接口,
所以对于数据导出到Excel文件存在以下几种方法:

1.导出为csv格式文件--逗号分隔符的文本文件(有的直接将csv文件的扩展名csv也直接改为了xls,Excel都可以直接打开)
优点:代码编写相对简单,导出速度快(方法正确的话^_^),不依赖Excel(即电脑上没有安装Excel对导出没有影响)
缺点:Excel打开此文件的时候遇到较长的数字组成的字符串(比如说身份证号银行账号)会把它当做数字,
并“智能”的截断或者科学计数;还有0043234这样的字符串也会被当做数字而丢掉了开头的“0”字符。
给使用带来不便;另外就是没有漂亮的格式控制,
如:列宽的调整、标题背景色,单元格合并等等。

2.导出为slk文件--Excel支持的符号链接文件(可以直接按照其格式用文本直接输出,我没有测试成功)
优点:同上,而且可以有简单的格式控制,可以设置列为文本类型,避免了身份证号码被截断的问题,
还可以有简单的背景色文字粗体等设置,导出速度快,不依赖Excel(但打开时还是需要excel的)
缺点:对于更加丰富的格式控制不支持,而且具体的格式不清楚,我曾经尝试写过输出到slk文件,
因为不熟悉格式,输出的文件用Excel打开时忽略一堆错误可以得到目标格式的数据,
但是这一堆的错误恐怕会把用户吓坏。

3.简单的导出为html文件(只输出为表格不加样式控制),将扩展名改为xls
优点:代码编写相对简单,导出速度快,不依赖Excel,格式控制丰富
缺点:不是真正的Excel文件,排序等等功能无法使用,仍存在长数字被“智能”处理的问题和“0043243”这样的字符串丢失开头的0的问题。
不过可以加样式表控制进行解决。


4.王光红的输出到带格式控制的HTML文件再利用Excel转存为xls文件。
这个是比较完美的处理方法了,但是并非如作者所说“彻底抛弃用OLE做EXCEL”,转存的过程还是OLE控制Excel的,
不过整个数据的输出过程没有用OLE控制Excel,我想作者所指的不用OLE也是这个意思。
优点:真正的Excel文件(xls格式),所以文本的格式控制可控性非常强,可以做出很好的效果来,
速度比OLE控制Excel一个字段一个字段的输出数据快多了。而且第一步的成果不需要Excel,可以到有Excel的电脑再进行转换。
缺点:没有明显的缺点,第二步依赖Excel

5.OLE控制Excel,直接将数据一个字段一个字段的输出到Excel
优点:同上。
缺点:依赖Excel,而且是所有方法中最慢的,不是一般的慢~~-_-#

6.俺写的快速OLE控制Excel导出数据(严格的说也属于第五种,)
优点:同上。而且很快
缺点:依赖Excel。

说明:OLE控制Excel导出数据慢就慢在多次的程序间通讯,要想加速就要尽量减少操作次数和耗时操作。
基于这样的考虑我将能改为用Range操作的步骤都用Range操作,
另外利用剪贴板输送数据到Excel,而不是一个字段一个字段的写入。
并且充分利用Excel本身的功能以提高效率。这样大大的提高了输出到Excel的速度。用代码说明我的想法如下:

#define PG OlePropertyGet
#define PS OlePropertySet
#define FN OleFunction
#define PR OleProcedure

String xls_coltag(int col_no)
{
//取excel的列标签,用于建立range
int num1,num2;
String col_caption;
num1=col_no/26;
num2=col_no%26;
if(num1>0)
col_caption = String(char(64 +num1))+String(char(64 +num2));
else
col_caption = char(64 +num2);
return col_caption;
}
//---------------------------------------------------------------------------
void __fastcall DBGrid2Excel(TDBGrid *dg, String strXlsFile)
{
if(!dg->DataSource->DataSet->Active) // 数据集没有打开就返回
return;
Variant vExcel, vSheet;
try
{
vExcel = Variant::CreateObject("Excel.Application");
}
catch(...)
{
MessageBox(NULL, "启动 Excel 出错, 可能是没有安装Excel.",
"发生错误", MB_OK | MB_ICONERROR);
return;
}

dg->DataSource->DataSet->DisableControls();
TStringList *sl=new TStringList();
AnsiString ln="",rng,col;
Variant Range;
int ln_no=0,row_cnt,col_cnt;
row_cnt=dg->DataSource->DataSet->RecordCount;
col_cnt=dg->Columns->Count;
//取列名
for(int i=0; i {
ln+=dg->Columns->Items[i]->Title->Caption +"\t";
//取列格式
switch (dg->DataSource->DataSet->Fields->Fields[i]->DataType)
{
case ftBCD:
case ftInteger:
case ftFloat:
case ftCurrency:
break;
default:
col=xls_coltag(i+1);
rng+=col+":"+col+",";
}
}
//要设置成文本的区域
rng=rng.SubString(1,rng.Length()-1); //去掉最后一个逗号
sl->Add(ln);
ln_no=dg->DataSource->DataSet->RecNo;//记录当前行号
dg->DataSource->DataSet->First();
//取明细数据
while (!dg->DataSource->DataSet->Eof)
{
ln="";
for(int j=0; j {
ln+=Trim(dg->DataSource->DataSet->Fields->Fields[j]->AsString) + "\t";
}
sl->Add(ln);
dg->DataSource->DataSet->Next();
}
dg->DataSource->DataSet->First();
dg->DataSource->DataSet->MoveBy(ln_no-1);
dg->DataSource->DataSet->EnableControls();
try
{
vExcel.PS("Visible",true); // 隐藏Excel界面
vExcel.PG("Workbooks").FN("Add", 1); // 新建一个工作表
vSheet = vExcel.PG("ActiveWorkbook").PG("Sheets", 1);
vSheet.PG("Range","A2").PS("Value","正在检索数据。请稍候..");
vExcel.PS("ScreenUpdating",false);
Range = vSheet.PG("Range",rng.c_str());
Range.PS("NumberFormatLocal","@");
//写报表标题
if(rpt_title!="")
{
vExcel.PG("Rows", 1).PS("RowHeight", 20);
vSheet.PG("Cells", 1, 1)
.PS("Value",rpt_title.c_str());
rng="A1:"+xls_coltag(col_cnt)+"1";
Range = vSheet.PG("Range",rng.c_str());
Range.FN("Merge", false);
Range.PS("HorizontalAlignment",-4108);
Range.PS("VerticalAlignment",-4108);
ln_no=2;
row_cnt++;
}
else
ln_no=1;
rng="A"+IntToStr(ln_no);
//----------------------------------------------------------------------------
// 作者:lvjack lvjack(at)sohu.com
// 发表于:http://blog.csdn.net/lvjack
//----------------------------------------------------------------------------
//将DBGrid中的数据粘贴入Excel表格
vExcel.Exec(PropertyGet("Range")< Clipboard()->SetTextBuf(sl->Text.c_str());
vExcel.PG("ActiveSheet").PR("Paste");
vSheet.PG("Cells", 1, 1).PR("Select"); //去除粘贴造成的选区
//设置边框
rng="A1:"+xls_coltag(col_cnt)+String(row_cnt+1);
Range = vSheet.PG("Range",rng.c_str());
Range.PG("Borders").PS("LineStyle",1);
//自动格式化表格
Range.FN("AutoFormat", 11, true, true, true, false, true, true);
// 设置列名单元格的背景色
/*
rng="A1:"+xls_coltag(col_cnt)+IntToStr(ln_no);
Range = vSheet.PG("Range",rng.c_str());
Range.PG("Font").PS("Bold",true);
Variant vInter = vSheet.PG("Range",rng.c_str()).PG("Interior");
vInter.PS("ColorIndex", 44); //橙色 45深橙色 15灰色
vInter.PS("Pattern", 1); // xlSolid
*/
vExcel.PG("ActiveWorkbook")
.FN("SaveAs", strXlsFile.c_str()); // 保存
}
__finally
{
vExcel.PS("ScreenUpdating",true);
//vExcel.PS("Visible", true);
vSheet = Unassigned;
vExcel = Unassigned;
delete sl;
}
}
//---------------------------------------------------------------------------

代码写完了,但是关于效率还有潜力可挖,下面是一些耗时操作的时间消耗统计,2000条记录,30多个字段,取程序运行三次的数据,时间单位毫秒。

CreateObject 641 453 297
取明细数据 1312 1235 1297
新建一个工作表 156 140 281
设置列格式 15 31 32
发送到剪贴板 47 31 0
Paste 234 235 266
设置边框 62 78 78
AutoFormat 1219 1500 1265
SaveAs 422 296 250

在准备明细数据这一步应该可以利用更好的方法提高速度,如果嫌AutoFormat那一步消耗时间多可以换为我代码中注释掉的那一块“设置列名单元格的背景色”这样处理效果会差些速度会提高一点。不过我觉得多花那一点时间值得,作出来的效果很不错,列宽背景色什么的都弄好了。

呵呵,这就是我工作中用到的一个功能,希望能够抛砖引玉,看到大虾提供效率更高的方法:)

补充,此文写作中得到妖哥的大力支持(www.ccrun.com)。另外写写报表标题的那一段和我的程序有关,直接删掉即可,替换为ln_no=1;
嘻嘻,另外学妖哥在代码中加了一段说明^_^!

--------------------------
2006.3.3 最新发现,可能更快的数据导入方式,来自TR的blog,呵呵我抛出的这块砖引出玉了,
惭愧的是发现TR老大早在2004年就已经提出了,我在2006拾人牙慧-_-#

不过让更多人知道好的方法总是不错的:)
TR的方法是利用了Excel的TExcelQueryTable,将SQL检索的数据直接送入了Excel,应该很快的,
看老大的测试数据也说明了这点,我还没有进行代码测试,不知道格式啊长数字这方面的问题怎么样,
根据使用Excel 的Query工具的经验应该是不错的,不过用Query时发生过一些SQL不能正确执行的问题不知有没有。
等着试试。TR@SOE的原作见http://borland.mblogger.cn/tr/posts/5722.aspx,示例代码转载如下:

Delphi代码
procedure TForm1.ExcelQryBtnClick(Sender: TObject);
var ConStr:OleVariant;
var R: Range;
var SQL: String;
var STick, ETick: integer;
begin
ConStr:='ODBC;DSN=bookodbc;UID="";PWD=""';
SQL:='select name, author, country from tbook';
R:=ExcelWorkSheet2.Range['a1', 'a1'];
ExcelWorkSheet2.Activate;
STick:=GetTickCount();
ExcelQueryTable1.ConnectTo(ExcelWorkSheet2.QueryTables.Add(ConStr, R, SQL) as _QueryTable);
ExcelQueryTable1.Refresh;
ETick:=GetTickCount();
ShowMessage(FloatToStr((ETick-STick)/1000.0)+' seconds');
end;
BCB代码
void __fastcall TForm1::Button4Click(TObject *Sender)
{
String ConStr;
String SQL;
int STick, ETick;
RangePtr R;
ExcelWorksheet2->Activate();
ConStr="ODBC;DSN=bookodbc;UID='';PWD=''";
SQL="select name, author, country from tbook";
R=ExcelWorksheet2->Get_Range("a1", "a1");
STick=GetTickCount();
ExcelQueryTable1->ConnectTo(ExcelWorksheet2->QueryTables->Add(ConStr, R, SQL));
ExcelQueryTable1->Refresh();
ETick=GetTickCount();
ShowMessage(FloatToStr((ETick-STick)/1000.0)+" seconds");
}