MFC如何定义mfc cstring char类型的数组

CString 标签_51CTO技术博客
搜索推荐文章
搜索原创文章
搜索近期文章
&&&&环境:win764位+vs2010一直在找,MFC不懂真没办法,顺便记祝。。。新建win32控制台应用程序中不能使用cstring类型,此时包含头文件#include&afxwin.h&,并在项目属性-&配置属性-&常规"项目默认值"-&"MFC的使用"中选择“在静态库中使用MFC”或者“在共享DLL中使用MF..
&&&&环境:vs2010+win764位如题:在MFC中CString转化成std::string的方法如下:std::CSstr=cstr.GetBuffer(0);//str使用...cstr.ReleaseBuffer();由于MFC中CString为ATL::CStringT&TCHAR,StrTraitMFC_DLL&TCHAR&&;当定义了_UNICODE宏时,TCHAR=wchar_t..
&&&&voidCServerSock::GetFileName()
inti=0;//例如文件路径如:D:\\fengyu\\zaitu.txt取得文件名:zaitu.txt
for(i=m_FileFullPath.GetLength();i&0;i--)
if('\\'==m_FileFullPath)//能够通过编译,但是运行时断言错误
//if('\'==m_FileFullPath)//无法通过编译如果这样
&&&&char*CXXXXXDlg::CStringToChar(CStringstr){ char*pChar=newchar[str.GetLength()+1]; for(inti=0;i&str.GetLength();i++) {
if((i+1)==str.GetLength())
pChar[i]=str.GetAt(i);
pChar[i+1]='\0';
pChar[i]=str.GetAt(i);
} } returnpC}..
&&&&CStringstr=&HeyLook&;char*pch=newchar[str.GetLength()+1];pch=str.GetBuffer(str.GetLength()+1);str.ReleaseBuffer();//调用GetBuffer后一定要调用ReleaseBuffercout&&pch&&..
&&&&下面的代码应该同时适用于多字节字符集和Unicode字符集,上代码://将CString转为std::string
stringCMyUtil::CString2string(constCString&cstr)
CStringAstra((TCHAR*)(LPCTSTR)(cstr));
stringstr((char*)(LPCSTR)(stra));
//将std::string转为CString..
&&&&转自:/page/M0/S530/530822.html昨天编译文件时出现了BuildingMFCapplicationwith/MD[d](CRTdllversion)requiresMFCshareddllversion~~~~的错误。在网上很容易找到了解决的方案,公布如下:对着你的项目点击右键,依次选择:属性、配置属性、常规,然后右边..
&&&&CString的构造函数CString();例:CStringcsSCString(constCString&stringSrc);例:CStringcsStr("ABCDEF中文123456");CStringcsStr2(csStr);CString(TCHARch,intnRepeat=1);例:CStringcsStr('a',5);//csStr="aaaaa"CString(LPCTSTRlpch,intnLength);例:CStringcsStr("abc..
&&&&CStringitem=(TCHAR*)(_bstr_t)m_pRecordset-&GetCollect("ENAME");即是(TCHAR*)(_bstr_t)强制转换。..
&&&&CStringitem=(TCHAR*)(_bstr_t)m_pRecordset-&GetCollect("ENAME");即是(TCHAR*)(_bstr_t)强制转换。..
&&&&CShanLingDlg*maindlg=(CShanLingDlg*)AfxGetApp()-&m_pMainW
intsel=maindlg-&m_MySearch.m_GridSearch.GetSelectionMark();
CStringm_FileS
m_FileSize=maindlg-&m_MySearch.m_GridSearch.GetItemText(sel,1);
filesize=atol(m_FileSize.GetBuffe..
&&&&方法一:char*p;CStringstr="hello";p=str.GetBuffer(str.GetLength());str.ReleaseBuffer();方法二:CStringstr="hello";charch[20];memcpy(ch,str,str.GetLength());注意:如果是声明一个char类型的数组,一定要初始化。否则后面未使用的字节为乱码。//拼接文件存放路径、文件名、..
&&页数 ( 1/4 )
Copyright&
版权所有 未经许可 请勿转载当前位置:
安装钩子,托管C++中的字符串以其它
安装钩子,托管C++中的字符串以其它
发布日期: 12:04
浏览次数:9140次
标  签:windows
文章评分:5.0
操  作:
称号:未设置简介:...
文章概要:
1、我想调用 SetWindowsHookEx 来设置 WH_CBT 钩子,但我了解到 MFC 也安装了这个钩子,也就是在一个线程中安装了两次 WH_CBT,这样做能行吗?
2、我正在将一个现有的 C++ 类库转换为托管扩展,以便能在 .NET 框架客户端使用它们。我的代码调用了 API 函数,这些函数需要当前运行模块的 HINSTANCE。我不想使用我的 DLL 的 HINSTANCE;我想让调用者提供 EXE 的 HINSTANCE,该 EXE 调用我的 DLL。我能将 HINSTANCE 声明为一个 IntPtr,但我的基于 .NET 的客户端如何让应用程序的 HINSTANCE 传递给我的函数?在 C# 中是如何做的?
3、我要如何将 MFC CString 转换为托管 C++ 中的 String?我有一个函数是这样的:
int ErrMsg::ErrorMessage(CString& msg) const
msg.LoadString(m_nErrId);
msg += _T("::Error");
return -1;
  我如何用托管 C++ 重写这个函数,并用 String 替换参数中的 CString?我不知道如何声明参数,如何处理 const,以及如何从资源文件中加载托管 String。我看了文档说 String 是不能被修改的,因为它们是不可变的,但我有想修改传递的字符串。
我想调用 SetWindowsHookEx 来设置 WH_CBT 钩子,但我了解到 MFC 也安装了这个钩子,也就是在一个线程中安装了两次 WH_CBT,这样做能行吗?
答案是肯定的。只要遵循正确的步骤,你可以安装几个相同类型的钩子。Windows 的钩子是被设计用于一系列类似子类化这样的操作。为了安装钩子,得调用 SetWindowsHookEx 函数,参数为钩子类型和指向钩子过程的指针。SetWindowsHookEx 返回一个指向旧钩子的句柄:
HHOOK hOldH // 全局
hOldHook = SetWindowsHookEx(WH_CBT, MyCbtProc, ...);
现在只要发生有钩子事件,Windows 便调用你的钩子过程。当你的过程处理完该事件,则应该用 CallNextHookEx 调用下一个钩子:
LRESULT CALLBACK
MyCbtProc(int code, ...)
if (code==/* whatever */) {
// do something
return CallNextHookEx(hOldHook, code, ...);
当然,没有人强迫你调用 CallNextHookEx,但是如果不调用,那么你的程序可能会垮掉。MFC 使用 CBT 钩子来监视窗口的创建。只要一创建窗口,Windows 都会用 HCBT_CREATEWND 调用此 CBT 钩子。MFC 通过子类化窗口来处理 HCBT_CREATEWND,并将它附属到其 CWnd 对象。具体细节比较复杂,这里仅给出一个简版的代码:
wincore.cpp 的简化代码
LRESULT _AfxCbtFilterHook(int code, WPARAM wp, ...)
if (code==HCBT_CREATEWND) {
CWnd* pWndInit = pThreadState-&m_pWndI
HWND hWnd = (HWND)
pWndInit-&Attach(hWnd);
SetWindowLongPtr(hWnd, GWLP_WNDPROC, &AfxWndProcafxWndProc);
return CallNextHookEx(...);
这里是去粗取精后的代码,MFC 将窗口对象附属到其 HWND 并通过安装 AfxWndProc 对之进行子类化处理。正是通过这种方式,MFC 将 C++ 窗口对象与它们的 HWNDs 联系起来。AfxWndProc 过程的作用是(通过非常曲折的途径)将 WM_XXX 消息路由到你的消息映射处理函数。
当 Windows 调用 CBT 钩子时,它用 WPARAM 传递 HWND。但 MFC 是如何知道要附属哪个 CWnd 派生对象呢?通过一个全局变量。为了创建窗口,你必须调用 CWnd::Create 或 CWnd::CreateEx。前者调用后者,所以不管怎样都要经过 CWnd::CreateEx 调用。在创建窗口之前, CWnd::CreateEx 安装 CBT 钩子并设置全局变量。代码是这样的:
wincore.cpp 的简化代码
BOOL CWnd::CreateEx(...)
AfxHookWindowCreate(this);
::CreateWindowEx(...);
AfxUnhookWindowCreate();
return TRUE;
AfxHookWindowCreate 安装 CBT 钩子 _AfxCbtFilterHook。它还在线程状态中保存窗口对象指针,pThreadState-&m_pWndInit。
void AFXAPI AfxHookWindowCreate(CWnd* pWnd)
_AFX_THREAD_STATE* pThreadState = _afxThreadState.GetData();
pThreadState-&m_hHookOldCbtFilter = ::SetWindowsHookEx(
WH_CBT, _AfxCbtFilterHook, NULL, ::GetCurrentThreadId());
pThreadState-&m_pWndInit = pW
考虑到线程状态是一个保存线程级全局变量的地方。所以这个动作点到为止。你的程序调用 CWnd::Create 或者 CWnd::CreateEx。CWnd::CreateEx 安装 CBT 钩子,将一个全局指针赋值给所创建的 CWnd,并且最终调用 ::CreateWindowEx 来真正创建窗口。在创建窗口之后,发送 WM_CREATE 或 WM_GETMINMAXINFO 之类的窗口消息之前―― Windows 用 HCBT_CREATEWND 调用 CBT 钩子。然后 _AfxCbtFilterHook 获得控制并子类化该窗口并将它连接到其 CWnd,MFC 知道使用哪个 CWnd,因为它之前已经将 CWnd 指针保存在 pThreadState-&m_pWndInit 中了。很聪明,不是吗?
在 _AfxCbtFilterHook 将控制返回& Windows 之后,通过将控制交给 OnGetMinMaxInfo 和 OnCreate 处理例程,Windows 向你的窗口发送 WM_GETMINMAXINFO 和 WM_CREATE 消息,MFC 按常规方式处理它们。这是必由之路,因为 HWND 已经被附属到其 CWnd 对象。当 ::CreateWindowEx 将控制返回给 CWnd::CreateEx 的时候,CWnd::CreateEx 调用 AfxUnhookWindowCreate 删除 CBT 钩子并将 pThreadState-&m_pWndInit 置为 NULL。之所以要这样处理 CBT,其唯一的理由就是为了监控窗口的创建,以便 MFC 能将 CWnd 连接到它们的 HWNDs,这个钩子只为 ::CreateWindowEx 调用过程而存在。
机敏的读者可能会问:为什么 MFC 要费那么大的劲――为什么不在 CWnd::CreateEx 中直接附属并子类化窗口?那样做也行得通,只是会有一个问题。CWnd 对象将错过任何从 ::CreateWindowEx 发送的消息――如:WM_GETMINMAXINFO、WM_NCCREATE 以及 WM_CREATE。这个问题的来由是这样的:在创建窗口时 ::CreateWindowEx 无法让你指定窗口过程。你必须在之后进行子类化。但是另一方面,几个消息都已发出。为了处理这些消息,包括早先创建的消息,MFC 不得不在消息被发送之前连接到窗口对象。唯一途径就是使用 CBT 钩子,因为 Windows 正是在它创建窗口之后,发送任何消息之前调用该 CBT 钩子。所以说到底,CBT 钩子的目的是监视窗口的创建,以便在该窗口接收到任何消息之前将 CWnd 对象连接到它们的 HWNDs。
其实要回答你的问题不需要这么罗嗦,之所以讲这么多主要是为了更好地理解什么时候,在哪里使用 CBT 钩子以及 MFC 为什么使用 CBT 钩子。我还想向你展示 MFC 如何用线程全局变量 m_pWndInit 向钩子函数传递 CWnd 对象。你会经常遇到类似的处理。SetWindowsHookEx 不具备 void* 类型的参数向钩子函数传递信息。如果你的钩子过程需要这种形式的数据,唯一的方式是通过全局变量。其它的大多数情况只要一个常规静态变量即可;你不需要线程专用的全局变量,除非你的数据是线程专用的。MFC 使用线程状态,因为 它为每个线程维护一个单独的窗口映射。该窗口映射为线程保存所有的 CWnds 对象;从而我们能将每个 CWnd 与其 HWND 连接。
至于多个钩子的情况,只要你愿意,安装多少个钩子都没关系,只是你要记得调用 ::CallNextHook 函数,这样便不会妨碍 MFC。
我正在将一个现有的 C++ 类库转换为托管扩展,以便能在 .NET 框架客户端使用它们。我的代码调用了 API 函数,这些函数需要当前运行模块的 HINSTANCE。我不想使用我的 DLL 的 HINSTANCE;我想让调用者提供 EXE 的 HINSTANCE,该 EXE 调用我的 DLL。我能将 HINSTANCE 声明为一个 IntPtr,但我的基于 .NET 的客户端如何让应用程序的 HINSTANCE 传递给我的函数?在 C# 中是如何做的?
Hunter Gerson
好问题!这个问题把我难住了十五分钟。在 MFC 中你可以调用 AfxGetInstanceHandle()。MFC 将 HINSTANCE 存储在其 Application 对象 CWinApp::m_hInstance 中。所以如果你用的是微软 .NET 框架,你也许会想到要察看一下 Application 对象 Application.HInstance 或者 Application 属性等等。为什么不呢?因为 .NET 框架中就没有这些东西。
如果你在框架文档中搜索“hinstance”,你会发现有一个方法叫 Marshal.GetHINSTANCE。文档中是这样描述的,静态的 Marshal 方法需要一个模块(Module)作为参数,你想获得的是这个模块的 HINSTANCE。
IntPtr h = Marshal.GetHINSTANCE(m);
现在你应该知道如何设置该 HINSTANCE 了――那么到哪里获取模块对象呢?再说一次,你可以察看一下 Application 类,看看有没有象 Application.GetModule 之类的东西。或者也许 Application 派生于模块。可惜不是那样。难道有一个 Module 属性,也不是。嗯,应该说不完全是,有一个 Module 属性,但它不是 Application 属性,而是 Type 的属性。在 .NET 框架中,每个对象都具备一个 Type 属性,而每个 Type 都有一个 Module 属性。Type.Module 表示的是实现该类型的模块。所以获取调用模块的 HINSTANCE 可以这么做:
Type t = myObj.GetType();
Module m = t.M
IntPtr h = Marshal.GetHINSTANCE(m);
你也可以在没有对象实例的情况下用 typeof(C++)来获取类型信息,如:typeof(MyApp)。告诉你的客户一定要使用在调用模块中实现的类型。如果使用某些其它类型――例如,String 之类的框架类型――你得到的模块是错误的。
Figure 1 示范了一个简单的 C# 控制台例子,ShowModule,它阐明了这一点。运行画面如 Figure 2 所示。ShowModule 显示的模块信息包括两种类型的 HINSTANCE:应用自身定义了MyApp 类,而 String[](String 数组)类型在 mscorlib 中定义。
Figure 1 Getting an HINSTANCE in C#
using System.R
using System.Runtime.InteropS
class MyApp {
// main entry point
static void Main(string[] args) {
ShowModule(typeof(MyApp));
// show module for MyApp (me)
ShowModule(args.GetType());
// show module for String[] (CLR)
// Helper to display module info and HINSTANCE given Type.
static void ShowModule(Type t)
Module m = t.M
Console.WriteLine("Module info for type {0}:", t);
Console.WriteLine(" Name = {0}", m.Name);
Console.WriteLine(" FullyQualifiedName = {0}",
m.FullyQualifiedName);
Console.WriteLine(" HINSTANCE = 0x{0:x}\n",
(int)Marshal.GetHINSTANCE(m));
Figure 2 模块信息
我要如何将 MFC CString 转换为托管 C++ 中的 String?我有一个函数是这样的:
int ErrMsg::ErrorMessage(CString& msg) const
msg.LoadString(m_nErrId);
msg += _T("::Error");
return -1;
我如何用托管 C++ 重写这个函数,并用 String 替换参数中的 CString?我不知道如何声明参数,如何处理 const,以及如何从资源文件中加载托管 String。我看了文档说 String 是不能被修改的,因为它们是不可变的,但我有想修改传递的字符串。
Sumit Prakash
这个问题涉及到几个方面,所以让我们一个一个来解决。首先是 const 的声明。在 .NET 框架中是没有常量方法这种概念的,所以你要忘掉它,每办法,只能这么做。
其次,如何声明新的函数。你确信你要将 CString 修改为 String,但到底用什么样的语法呢?你的函数修改传递的 CString,这就是你使用引用的原因。在 .NET 中,String 确实是不可变的。你不能修改一个 String 的内容。所有修改 String 的方法实际上都返回一个新的 String。例如:
String* str = S"hello";
str = str-&ToUpper();
String::ToUpper 返回一个新 String,你可以赋值给 str。如果你想修改 String,必须使用另外一个类,也就是 StringBuilder。但这里你是不需要 StringBuilder 的,因为你并不真正修改这个 String,你修改的是引用它的变量。为了弄明白这一点,考虑一下在 C# 中你的函数会是什么样子:
int ErrorMessage(ref string msg)
msg = ...;
return -1;
msg 参数被声明为 ref,意思是说当 ErrorMessage 修改 msg 时,它修改的是传递的变量,而非 String 对象本身,看下面代码:
string str = "";
err.ErrorMessage(ref str);
现在用空串代替引用,str 引用任何 ErrorMessage 给它指定的串。所以在 C# 中,你可以用 ref 参数。但是在 C++ 中没有 ref 关键字,也没有任何托管的 __ref 关键字。C++ 不需要,因为 C++ 已经具备一个引用机制!并且编译器很灵敏,知道如何处理托管代码。你只要记住在 C++ 中,托管对象总是指针或者句柄。只要用 String* 代替 CString 即可(如果你用的 IDE 是具备 C++/CLI 的 Visual Studio 2005,可以直接用 String 代替 CString)。新的声明方法如下:
int ErrMsg::ErrorMessage(String*& msg){
msg = "foo";
return -1;
这样,新函数的参数便是一个对托管 String 指针的引用。如果你想用得暴露一点,甚至可以使用 __gc,比如:
ErrorMessage(String __gc * __gc & msg);
在实际的实现中,你不必使用 __gc,因为编译器知道 String,是一个托管类。如果你使用 C++/CLI,便可以在使用引用到句柄的跟踪(tracking reference-to-handle):
ErrorMessage(String^% msg);
它的意义更加明确。到此故事还没有完结,因为另外还有一个方法声明 ErrorMessage,那就是使用指针到指针的方式:
int ErrMsg::ErrorMessage(String** msg){
*msg = "foo";
return -1;
即使是在 C++ 中,指针和引用之间的差别是微小的。主要的不同是引用总是必须初始化,不能为 NULL。其它区别主要是语法上的――不论你是使用.还是-&反引用。在内部看到的引用都是以指针方式实现的。在 .NET 中,没有指针。万物皆引用。或者说一切都归为一个指针,因为如果你深入到底层的话便可窥见一斑。所以不论是使用引用到指针还是指针到指针,你的 String 参数对于框架以外的世界来说都是一个引用参数。我写了一个 C# 示范程序 RetTest。(参见 Figure 3 和 Figure 4)
Figure 3 Library that Uses Pass-By-Reference Parameters
#using &mscorlib.dll&
#include &atlstr.h& // CString
using namespace S
using namespace System::Runtime::InteropS
namespace MyLib {
public __gc class ErrMsg {
// reference-to-pointer
int Message1(String*& str)
str = "Hello, world #1";
// pointer-to-pointer
int Message2(String** str)
*str = "Hello, world #2";
// Load string from DLL resource file. Note explicit module handle.
int GetString(String*& str, int id)
if (s.LoadString(::GetModuleHandle(_T("MyLib.dll")), id)) {
// Copy to caller's string. Compiler knows what to do.
// Note: need to box id sinve String::Format expects an Object.
str = String::Format("Error: String {0} not found.", __box(id));
return -1;
// Resource file has two strings
STRINGTABLE
1 "Resource string #1"
2 "Resource string #2"
Figure 4 C# Consumer of C++ Library
using MyL // C++ lib
class MyApp {
// main entry point
static int Main(string[] args) {
ErrMsg em = new ErrMsg();
String str =
// Test declaration 1: reference-to-pointer
em.Message1(ref str);
Console.WriteLine("Message1: str = {0}", str);
// Test declaration 2: pointer-to-pointer
em.Message2(ref str);
Console.WriteLine("Message2: str = {0}", str);
// Test old-style resource strings: There are only 2.
for (int i=1; i&=3; i++) {
em.GetString(ref str, i);
Console.WriteLine("Resource String #{0} = {1}", i, str);
RefTest 使用了一个用 C++ 写的类库。ErrMsg 是一个托管类,它有两个方法,Message1 和 Message2,这两个方法将其 String 参数分别赋值为“Hello, world #1”和“Hello, world #2”,一个使用 String** 另一个使用 String*&。两种方法,不管是调用 Message1 还是 Message2,C# 调用者都必须用 ref 关键字。
“ref”对于两种情况都是必须的。如果你去掉它,便会有“error CS1503: Argument ''1'': cannot convert from ''string'' to ''ref string''.”错误。注意:用 str=NULL 调用 Message1 是合法的。对于你的 C++ 函数,str 不是 NULL,它是一个空引用。如果你的函数存取传递的 String,你应该注意这一点。例如:
int ErrMsg::Message1(String*& str)
int len = str-&L
这样编译没问题,但如果调用者传递 str=NULL,那么它丢出一个异常。你应该重写代码仔细处理 str=NULL 的情况,就像下面这样:
int ErrMsg::Message2(String*& str)
if (str==NULL)
return -1;
那么,到底使用哪一个呢――指针还是饮用?我个人更喜欢引用(&),因为它反映的是 ref,看起来更简洁,反引用对象时也容易。
关于声明的问题讲了够多的了,下面是最后一个问题。如何加载资源串?正像你发现的,在 String 类中找不到 LoadString 方法。那是因为 .NET 框架不象 Windiws 那样处理资源,.NET 框架完全采用不同的方法,我在 2002 年 11 月的 MSDN 杂志文章中有过描述(参见:“.NET GUI Bliss: Streamline Your Code and Simplify Localization Using an XML-Based GUI Language Parser”),我是这样认为的:“无限的灵活性,但哪怕是一个小小的任务都很繁琐”。
.NET 的处理方式使用文本或 XML 资源文件(.resx)卫星程序集。在 .NET 中有两种资源:字符串和对象。对于字符串来说,你只要创建一个名字=值对( name=value ).txt文件,然后运行 resgen.exe。你的程序要调用 ResourceManager.GetString 来获取字符串。其它的处理包括你得编写一个将对象序列化到 .resx 文件的程序,然后在运行时调用 ResourceManger.GetObject 加载它。具体细节请参考文档或我的文章。在我的我的文章中,我编写 FileRes 类以及一个例子程序 FileResGen 来示范如何做, FileResGen 大大简化了基于文件的资源处理,如:图像文件(.BMP, .GIF, .JPG等等)。
.NET 处理资源的方式其优点在于更容易本地化。只要翻译文本/资源并将它保存在一个子文件夹中,该文件的名字应该与语言缩写名相同――比如:en 代表 English,fr 代表 Franch,或者 kv 代表 Komi。框架会根据用户系统的 CultureInfo.CurrentUICulture 设置自动加载适当的程序集(MFC 使用类似的基于 GetSystemDefaultUILanguage 的卫星动态连接库来处理本地化)。如果你想在 .NET 领域有所作为,那么得用使用卫星程序集和 ResourceManager 重写你的库代码。但是如果本地化并不是很重要(也许你只是加载内部错误信息,这些信息用户看不到)或者工期很短,那么你仍可以按照老方法从 .RC 文件加载串资源。但你得调用 ::LoadString 或在内部使用 CString,加载字符串,然后将它拷贝到调用者的 String 对象。用 C++ 写这样的程序是很爽的事情!你可以直接调用 Windows APIs,不用显式使用 P/Invoke,象往常一样使用你最爱的 ATL/MFC 类。因为你要从 DLL 中加载字符串,而不是从应用程序中加载,所以唯一的诀窍是必须显式地告诉 LoadString 使用你的 DLL HINTANCE:
HINSTANCE h = ::GetModuleHandle(_T("MyLib.dll")); // use DLL''s handle
s.LoadString(h, id);
Figure 3 是全部的实现代码。编译后运行 RefTest 的画面如 Figure 5 所示。与往常一样,更多信息和具体实现细节请参考本文例子程序源代码。
Figure 5 RefTest 运行画面馆
顺祝编程愉快!
您的提问和评论可发送到 Paul 的信箱:. 
Paul DiLascia 是一名自由作家,软件咨询顾问以及大型 Web/UI 的设计师。他是《Writing Reusable Windows Code in C++》书(Addison-Wesley, 1992)的作者。业余时间他开发 PixeLib,这是一个 MFC 类库,从 Paul 的网站
可以获得这个类库。
本文出自 MSDN Magazine 的 January 2006 期刊,可通过当地报摊获得,或者最好是 订阅
最多还可以输入100字
【VIP年会员制套餐】
【C/C++软件工程师实战能力集训大纲】
VC知识库发布了C/C++业界的“本草纲目”
【牛人都在千人一号群! 加群三步走!!!】
第一步:请必须加VC知识库QQ: 为好友;
第二步:请必须关注本站微博:
第三步:申请加入群:.(必须将关注微博截屏发到QQ方可通过!)
【最新2013:】
全部100% VC++源码提供: E-Form++全新大型SCADA & HMI解决方案源码、CAD解决方案源码、Gis解决方案源码 、电力石油化工仿真与图形建模解决方案源码、大量其他高级制图VC++源码下载!
【 新视频发布】
o o o o o o o o o o
Foxmail 新版中有一个《邮件特快专递》的功能。起先搞不懂如何用,后来知道要在“工具->系统选项”那边设置“本地 DNS 服务器的IP地址”。
  觉得这个新功能蛮好用的。不需要通过SMTP代理,可以直接通过本地往邮箱所在的邮件交换器发送邮件。在暑假一开始想在 VC++ 中实现这个功能。用 IRIS 截包后,发现程序中有 mx8.263.net 发送邮箱,不知道这个是什么东西,所以作罢。后来才想到这个就是 263.net 的MX记录主机,原来特快专递的原理就是往这个主机上发送数据就行。...
Foxmail 新版中有一个《邮件特快专递》的功能。起先搞不懂如何用,后来知道要在“工具->系统选项”那边设置“本地 DNS 服务器的IP地址”。
  觉得这个新功能蛮好用的。不需要通过SMTP代理,可以直接通过本地往邮箱所在的邮件交换器发送邮件。在暑假一开始想在 VC++ 中实现这个功能。用 IRIS 截包后,发现程序中有 mx8.263.net 发送邮箱,不知道这个是什么东西,所以作罢。后来才想到这个就是 263.net 的MX记录主机,原来特快专递的原理就是往这个主机上发送数据就行。...
本文介绍了套接字编程的基本知识。...posts - 17,&
comments - 20,&
trackbacks - 0
& MFC的数组类支持的数组类似于常规数组,可以存放任何数据类型。常规数组在使用前必须将其定义成能够容纳所有可能需要的元素,即先确定大小,而MFC数组类创建的对象可以根据需要动态地增大或减小,数组的起始下标是0,而上限可以是固定的,也可以随着元素的增加而增加,数组在内存中的地址仍然是连续分配的。
  MFC定义了数组模板类CArray,并针对各种常用变量类型定义了CByteArray,CArray,CUIntArray,CDArray,CStringArray,CObArray,CPtrArray。详见下表:
&变量数值范围
通过模板类的参数类型设定各种类型
&&&& Afxtempl.h
CByteArray
8位无符号整数 BYTE类型
&&&&& Afxcoll.h
16位无符号整数 WORD类型
&&&&& Afxcoll.h
32位无符号整数 DWORD类型
&&&&& Afxcoll.h
CUIntArray
32位无符号整数 UINT类型
&&&& Afxcoll.h
CStringArray
CString字符串 string字符串
&&&& Afxcoll.h
CObject类及其派生类
&&&& Afxcoll.h
void* 类型指针
&&&& Afxcoll.h
中国教程网
MFC数组类使用方法基本相同,下面分别以CArray和CUIntArray为例演示说明数组类的使用方法。
使用 CArray www.打开++ 6.0,创建基于对话框的工程Array。CArrayDlg类声明文件(ArrayDlg.h)中添加语句:
中国教程网
&#include &afxtempl.h&
请记住:使用CArray一定要包含头文件afxtempl.h。
打开主对话框资源IDD_ARRAY_DIALOG,添加一个按钮IDC_ARRAY_CPOINT,标题为CArray_CPoint,双击该按钮,在OnArrayCpoint()函数中添加如下代码:
void CArrayDlg::OnArrayCpoint()
{&& CArray &CPoint,CPoint&& m_A&&&&&&
m_Array.SetSize(10,10);&&&&&&&
CPoint pt1(10,10);
m_Array.Add(pt1);&&&&
CPoint pt2(10,50);&&&
m_Array.Add(pt2);&&&&
CPoint pt3(10,100);&&
m_Array.Add(pt3);&&&&
int size=m_Array.GetSize();&&&
CClientDC dc(this);&&
dc.MoveTo(0,0);&&&&&&
for(int i=0;i&i++)
{&pt=m_Array.GetAt(i);&&&&&&&&&&&
dc.LineTo(pt);&&&&&&& }}
代码简要说明:
CArray &CPoint,CPoint&& m_A 中国教程网
  该语句定义一个CArray数组对象,模板类CArray有两个参数,第一个参数为数组元素的类型,该例中是CPoint,即m_Array是CPoint数组;第二个参数为引用类型,一般有两种选择,一种选择与第一个参数类型相同,它意味着数组对象作为参数传递时,传递的是数组对象。第二种选择是第一个参数类型的引用,它意味着数组对象作为参数传递时,传递的是数组对象的指针。因此,尤其对于较复杂的数组结构类型,推荐使用引用传递,节约内存同时加快程序运行速度,正如本例使用的是CPoint&。
m_Array.SetSize(10,10); 中国教程网
  SetSize函数设定数组的大小,该函数有两个参数,第一个参数设定数组的大小;第二个参数设定数组增长时内存分配的大小,缺省值是-1,使用缺省值可以保证内存分配得更加合理。本例中第二个参数是10,意即增加一个数组元素会分配10个元素大小的内存供数组使用。
  您可以随时使用SetSize函数设定数组的大小,如果第一个参数值小于数组已有成员数量,多于第一个参数值的成员将被截去并释放相应内存。
  在使用CArray数组前,最好先使用SetSize确定其大小并申请存储空间。如果不这样做,向数组中增加元素时,需要不断地移动和拷贝元素造成运行的低效率和内存碎块。
m_Array.Add(pt1); 中国教程网
Add函数添加数组元素。
int size=m_Array.GetSize();
GetSize返回数组元素的数目。
for(int i=0;i&i++){&pt=m_Array.GetAt(i);&&&&& dc.LineTo(pt);}
  为了直观显示,该段代码将各数组元素作成折线画到屏幕上,其中GetAt(int index)通过index值得到相应的元素值。编译并运行程序,观察运行结果。
继续演示如何使用CArray
  再次打开主对话框资源IDD_ARRAY_DIALOG,添加一个按钮IDC_ARRAY_CSTRING,标题为CArray_CString,双击该按钮,在OnArrayCstring ()函数中添加如下代码:
void CArrayDlg::OnArrayCstring()
&{&&&&&& CArray&CSTRING,CSTRING&& m_
CString sztiger("tiger");&
CString szbear("bear");&&&
CString szdog("dog");
m_string.SetAtGrow(0,sztiger);
m_string.SetAtGrow(2,szdog);&&&&&&&
m_string.InsertAt(1,szbear);
int count=m_string.GetSize();&&&&&&
CClientDC dc(this);&&&&&&&
dc.SetBkMode(TRANSPARENT);
TEXTMETRIC textM&&&&
dc.GetTextMetrics(&textMetric);&&&
int fontHeight=textMetric.tmH&
int displayPos=10;
for(int x=0;x&++x)&&
{&&&&&&&&&&&&&&&
  dc.TextOut(10,displayPos,m_string[x]);&&&&&&&&&&&&&&         &&&&&&&        &&&&&&&&&&&displayPos+=fontH&&
AfxMessageBox("Continue...");
m_string.RemoveAt(2);
count=m_string.GetSize();&
for(x=0;x&++x)&&&&&&
dc.TextOut(10,displayPos,m_string[x]);&&&&&&&&
displayPos+=fontH&&
AfxMessageBox("A string has delete,continue...");&&&
m_string.RemoveAll();&&&&
count=m_string.GetSize();&&&&&&&&&&
if(count==0)&&&&&&&&&&&&&&&&&&&&&&&
AfxMessageBox("All elements are deleted.");}
代码简要说明:
m_string.SetAtGrow(2,szdog);
  SetAtGrow有两个参数,第一个参数决定数组元素的序号值,第二个参数是元素的值。该函数根据序号值设置相应数组元素的值,功能与SetAt相近,不同之处是使用该函数设置元素值时,如果序号值大于数组的上界,数组会自动增长。
  编译运行程序,细心的读者您可能会看到,第一行字符是“tiger”,第二行字符是“bear”,这是我们预料之中的,但第三行是空串,第四行是“dog”。空串是怎样造成的呢?细分析下面三行代码就可以知道:
m_string.SetAtGrow(0,sztiger);m_string.SetAtGrow(2,szdog);m_string.InsertAt(1,szbear);
第一行设定元素0为“tiger”,这是没有疑义的。
第二行设定元素2为“dog”,但是在设定元素2的同时自动将元素1填充为空串。
第三行插入“bear”为元素1,同时原来的元素1和元素2后移为元素2和元素3。
怎么样,这回明白了吧。
m_string.InsertAt(1,szbear);
  InsertAt函数在指定序号处插入相应元素,该函数在执行过程中,插入点后面的元素会自动后移。dc.TextOut(10,displayPos,m_string[x]);其中,m_string[x]是数组类对操作符[]的重载,数组类CArray允许使用[]操作符,类似于的常规数组。m_string[x]也可以用m_string.GetAt(x)替代。
m_string.RemoveAt(2);
RemoveAt只有一个参数,即元素序号值。该函数根据元素序号值删除相应元素值,后面的元素会自动前移。
m_string.RemoveAll();
RemoveAll删除所有元素值
  最后再说明一点:RemoveAt,InsertAt函数操作时会使得数组元素移位,运行时间大于SetAt,RemoveAll,Add函数。
阅读(...) 评论()}

我要回帖

更多关于 mfc cstring转int 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信