??xml version="1.0" encoding="utf-8" standalone="yes"?>欧美亚洲国产精品久久蜜芽,狠狠色狠狠色综合久久,亚洲人AV永久一区二区三区久久http://www.shnenglu.com/zjj2816/category/2063.htmlzh-cnSun, 23 Nov 2008 18:31:47 GMTSun, 23 Nov 2008 18:31:47 GMT60如何在运行时定对象cdQRTTIQ??/title><link>http://www.shnenglu.com/zjj2816/archive/2008/11/19/67286.html</link><dc:creator>井泉</dc:creator><author>井泉</author><pubDate>Wed, 19 Nov 2008 06:59:00 GMT</pubDate><guid>http://www.shnenglu.com/zjj2816/archive/2008/11/19/67286.html</guid><wfw:comment>http://www.shnenglu.com/zjj2816/comments/67286.html</wfw:comment><comments>http://www.shnenglu.com/zjj2816/archive/2008/11/19/67286.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/zjj2816/comments/commentRss/67286.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/zjj2816/services/trackbacks/67286.html</trackback:ping><description><![CDATA[RTTI ?#8220;Runtime Type Information”的羃写,意思是Q运行时cd信息。它提供了运行时定对象cd的方法。本文将略介l?RTTI 的一些背景知识、描q? RTTI 的概念,q过具体例子和代码介l什么时候用以及如何?RTTIQ本文还详l描qC个重要的 RTTI q算W的使用ҎQ它们是 typeid ?dynamic_cast?br>     其实QRTTI 在C++中ƈ不是什么新的东西,它早在十多年以前已l出C。但是大多数开发h员,包括许多高层ơ的C++E序员对它ƈ不怎么熟悉Q更不用说?RTTI 来设计和~写应用E序了?br>     一些面向对象专家在传播自己的设计理忉|Q大多都d在设计和开发中明智C用虚拟成员函敎ͼ而不?RTTI 机制。但是,在很多情况下Q虚拟函数无法克服本w的局限。每每涉及到处理异类容器和根基类层次Q如 MFCQ时Q不可避免要对对象类型进行动态判断,也就是动态类型的侦测。如何确定对象的动态类型呢Q答案是使用内徏? RTTI 中的q算W:typeid ?dynamic_cast?br>     首先让我们来设计一个类层次Q假设我们创Z某个处理文g的抽象基cR它声明下列U虚拟函敎ͼopen()、close()、read()? write()Q? <pre>class File<br>{<br>public:<br> virtual int open(const string & filename)=0;<br> virtual int close(const string & filename)=0;<br> //<br> virtual ~File()=0; // CdU虚拟析构函敎ͼdtorQ?br>};</pre> 现在?File cL生的c要实现基类的纯虚拟函数Q同时还要提供一些其他的操作。假设派生类?DiskFileQ除了实现基cȝU虚拟函数外Q还要实现自qflush()和defragment()操作Q? <pre>class DiskFile: public File<br>{<br>public:<br> int open(const string & filename);<br><br> // 实现其他的纯虚拟函数<br> ......<br><br> // 自己的专有操?br> virtual int flush();<br> virtual int defragment();<br>}; </pre> 接着Q又?DiskFile cL生两个类Q假设ؓ TextFile ?MediaFile。前者针Ҏ本文Ӟ后者针寚w频和视频文gQ? <pre>class TextFile: public DiskFile<br>{<br> // ......<br> int sort_by_words();<br>};<br><br>class MediaFile: public DiskFile<br>{<br> //......<br>}; </pre> 我们之所以要创徏q样的类层次Q是因ؓq样做以后可以创建多态对象,如: <pre>File *pfile; // *pfile的静态类型是 File<br>if(some_condition)<br> pfile = new TextFile; // 动态类型是 TextFile<br>else<br> pfile = new DiskFile; // 动态类型是 DiskFile </pre>     假设你正在开发一个基于图形用L面(GUIQ的文g理器,每个文g都可以以图标方式昄。当鼠标Ud图标上ƈ单击右键Ӟ文g理器打开一个菜单,? 个文仉了共同的菜单,不同的文件类型还有不同的菜单V如Q共同的菜单Ҏ“打开”“拯”、和“_脓”Q此外,q有一些针对特D文件的专门操作。比 如,文本文g会有“~辑”操作Q而多媒体文g则会?#8220;播放”菜单。ؓ了?RTTI 来动态定制菜单,文g理器必M每个文件的动态类型。利? q算W?typeid 可以获取与某个对象关联的q行时类型信息。typeid 有一个参敎ͼ传递对象或cd名。因此,Z定 x 的动态类型是不是YQ可以用表达式:typeid(x) == typeid(Y)实现Q? <pre>#include <typeinfo> // typeid 需要的头文?br>void menu::build(const File * pfile)<br>{<br> if (typeid(*pfile)==typeid(TextFile))<br> {<br> add_option("edit"); <br> }<br> else if (typeid(*pfile)==typeid(MediaFile))<br> {<br> add_option("play"); <br> }<br>} </pre>     使用 typeid 要注意一个问题,那就是某些编译器Q如 Visual C++Q默认状态是用 RTTI 的,目的是消除性能上的开销。如果你的程序确实用了 RTTIQ一定要C在编译前启用 RTTI。?typeid 可能产生一些将来的l护问题。假设你军_扩展上述的类层次Q从MediaFile z另一个叫 LocalizeMedia 的类Q用q个c表C带有不同语a说明文字的媒体文件。但 LocalizeMedia 本质上还是个 MediaFile cd的文件。因此,当用户在该类文g图标上单d键时Q文件管理器必须提供一?#8220;播放”菜单。可? build()成员函数会调用失败,原因是你没有查这U特定的文gcd。ؓ了解册个问题,你必象下面q样?build() 打补丁: <pre>void menu::build(const File * pfile)<br>{<br><br> //......<br><br> else if (typeid(*pfile)==typeid(LocalizedMedia))<br> {<br> add_option("play"); <br> }<br>} </pre>     唉,q种做法真是昑־太业余了Q以后每ơ添加新的类Q毫无疑问都必须打类似的补丁。显Ӟq不是一个理想的解决Ҏ。这个时候我们就要用? dynamic_castQ这个运符用于多态编E中保证在运行时发生正确的{换(即编译器无法验证是否发生正确的{换)。用它来定某个对象? MediaFile 对象q是它的zcd象。dynamic_cast 常用于从多态编E基cL针向zcL针的向下cd转换。它有两个参敎ͼ一个是cd名;另一个是多态对象的指针或引用。其功能是在q行时将对象强制转换为目标类型ƈq回布尔型结果。也是_如果该函数成功地q且是动态的? *pfile 强制转换?MediaFileQ那?pfile的动态类型是 MediaFile 或者是它的zcR否则,pfile 则ؓ其它的类型: <pre>void menu::build(const File * pfile)<br>{<br> if (dynamic_cast <MediaFile *> (pfile))<br> {<br> // pfile ?MediaFile 或者是MediaFile的派生类 LocalizedMedia<br> add_option("play"); <br> }<br> else if (dynamic_cast <TextFile*> (pfile))<br> {<br> // pfile ?TextFile 是TextFile的派生类<br> add_option("edit"); <br> }<br>} </pre>     l细想一下,虽然使用 dynamic_cast 实很好地解决了我们的问题,但也需要我们付ZP那就是与 typeid 相比Qdynamic_cast 不是一个常量时间的操作。ؓ了确定是否能完成强制cd转换Qdynamic_cast`必须在运行时q行一些{换细节操作。因此在使用 dynamic_cast 操作Ӟ应该权衡Ҏ能的媄响?img src ="http://www.shnenglu.com/zjj2816/aggbug/67286.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/zjj2816/" target="_blank">井泉</a> 2008-11-19 14:59 <a href="http://www.shnenglu.com/zjj2816/archive/2008/11/19/67286.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>(?q程通信机制http://www.shnenglu.com/zjj2816/archive/2007/12/13/38433.html井泉井泉Thu, 13 Dec 2007 07:50:00 GMThttp://www.shnenglu.com/zjj2816/archive/2007/12/13/38433.htmlhttp://www.shnenglu.com/zjj2816/comments/38433.htmlhttp://www.shnenglu.com/zjj2816/archive/2007/12/13/38433.html#Feedback0http://www.shnenglu.com/zjj2816/comments/commentRss/38433.htmlhttp://www.shnenglu.com/zjj2816/services/trackbacks/38433.html1、引a
在WindowsE序中,各个q程之间常常需要交换数据,q行数据通讯。WIN32 API提供?br>许多函数使我们能够方侉K效的q行q程间的通讯Q通过q些函数我们可以控制不同q?br>E间的数据交换,如同在WIN16中对本地q程q行d操作一栗?br>典型的WIN16两进E可以通过׃n内存来进行数据交换:Q?Q进EAGlobalAllocQGM
EM_SHARE...QAPI分配一定长度的内存Q(2Q进EAGlobalAlloc函数q回的句柄传?br>l进EBQ通过一个登录消息)Q(3Q进EB对这个句柄调用GlobalLock函数Qƈ利用G
lobalLock函数q回的指针访问数据。这U方法在WIN32中可能失败,q是因ؓGlobalLo
ck函数q回指向的是q程A的内存,׃q程使用的是虚拟地址而非实际物理地址Q因?br>q一指针仅与Aq程有关Q而于Bq程无关?br>本文探讨了几UWIN32下进E之间通讯的几U实现方法,读者可以用不同的Ҏ以达?br>E序q行高效可靠的目的?br>2、Windows95中进E的内存I间理
WIN32q程间通讯与Windows95的内存管理有密切关系Q理解Windows95的内存管理对我们
如下的程序设计将会有很大的帮助,下面我们讨论以下Windows95中进E的内存I间理
?br>在WIN16下,所有Windows应用E序׃n单一地址QQ何进E都能够对这一I间中属于共
享单一的地址I间QQ何进E都能够对这一I间中属于其他进E的内存q行d操作Q?br>甚至可以存取操作pȝ本n的数据,q样可能破坏其他程序的数据D代码?br>在WIN32下,每个q程都有自己的地址I间Q一个WIN32q程不能存取另一个地址的私?br>数据Q两个进E可以用h相同值的指针dQ但所d的只是它们各自的数据Q这?br>减了q程之间的相互干扰。另一斚wQ每个WIN32q程拥有4GB的地址I间Q但q不
代表它真正拥?GB的实际物理内存,而只是操作系l利用CPU的内存分配功能提供的?br>拟地址I间。在一般情况下Q绝大多数虚拟地址q没有物理内存于它对应,在真正可?br>使用q些地址I间之前Q还要由操作pȝ提供实际的物理内存(q个q程?#8220;提交”co
mmitQ。在不同的情况下Q系l提交的物理内存是不同的Q可能是RAMQ也可能是硬盘模
拟的虚拟内存?br>3、WIN32中进E间的通讯
在Windows 95中,为实现进E间q等的数据交换,用户可以有如下几U选择Q?br>* 使用内存映射文g
* 通过׃n内存DLL׃n内存
* 向另一q程发送WM_COPYDATA消息
* 调用ReadProcessMemory以及WriteProcessMemory函数Q用户可以发送由GlobalLock(
GMEM_SHARE,...)函数调用提取的句柄、GlobalLock函数q回的指针以及VirtualAlloc?br>数返回的指针?br>3.1、利用内存映文件实现WIN32q程间的通讯
Windows95中的内存映射文g的机制ؓ我们高效地操作文件提供了一U途径Q它允许我们
在WIN32q程中保留一D内存区域,把目标文件映到q段虚拟内存中。在E序实现中必
考虑各进E之间的同步。具体实现步骤如下:
首先我们在发送数据的q程中需要通过调用内存映射API函数CreateFileMapping创徏一
个有名的׃n内存Q?br>HANDLE CreateFileMapping(
HANDLE hFile,    // 映射文g的句柄,
//设ؓ0xFFFFFFFF以创Z个进E间׃n的对?br>LPSECURITY_ATTRIBUTES lpFileMappingAttributes,    // 安全属?br>DWORD flProtect,    // 保护方式
DWORD dwMaximumSizeHigh,    //对象的大?br>DWORD dwMaximumSizeLow,
LPCTSTR lpName     // 必须为映文件命?br>);
与虚拟内存类|保护方式可以是PAGE_READONLY或是PAGE_READWRITE。如果多q程都对
同一׃n内存q行写访问,则必M持相互间同步。映文件还可以指定PAGE_WRITECO
PY标志Q可以保证其原始数据不会遭到破坏Q同时允许其他进E在必要时自q操作?br>据的拯?br>在创建文件映对象后使用可以调用MapViewOfFile函数映射到本q程的地址I间内?br>下面说明创徏一个名为MySharedMem的长度ؓ4096字节的有名映文Ӟ
HANDLE hMySharedMapFile=CreateFileMapping((HANDLE)0xFFFFFFFF)Q?br>NULLQPAGE_READWRITEQ?Q?x1000Q?MySharedMem")Q?br>q映缓存区视图Q?br>LPSTR pszMySharedMapView=(LPSTR)MapViewOfFile(hMySharedMapFileQ?br>FILE_MAP_READ|FILE_MAP_WRITEQ?Q?Q?);
其他q程讉K׃n对象Q需要获得对象名q调用OpenFileMapping函数?br>HANDLE hMySharedMapFile=OpenFileMapping(FILE_MAP_WRITEQ?br>FALSEQ?MySharedMem");
一旦其他进E获得映对象的句柄Q可以象创徏q程那样调用MapViewOfFile函数来映?br>对象视图。用户可以用该对象视图来进行数据读写操作,以达到数据通讯的目的?br>当用戯E结束用共享内存后Q调用UnmapViewOfFile函数以取消其地址I间内的视图
Q?br>if (!UnmapViewOfFile(pszMySharedMapView))
{ AfxMessageBox("could not unmap view of file"); }
3.2、利用共享内存DLL
׃n数据DLL允许q程以类gWindows 3.1 DLL׃n数据的方式访问读写数据,多个q?br>E都可以对该׃n数据DLLq行数据操作Q达到共享数据的目的。在WIN32中ؓ建立׃n
内存Q必L行以下步骤:
首先创徏一个有名的数据区。这在Visual C++中是使用data_seg pragma宏。用data_
seg pragma宏必L意数据的初始化:
#pragma data_seg("MYSEC")
char MySharedData[4096]={0};
#pragma data_seg()
然后在用LDEF文g中ؓ有名的数据区讑֮׃n属性?br>LIBRARY TEST
DATA READ WRITE
SECTIONS
    .MYSEC READ WRITE SHARED
q样每个附属于DLL的进E都接受到属于自己的数据拷贝,一个进E的数据变化q不?br>反映到其他进E的数据中?br>在DEF文g中适当地输出数据。以下的DEF文g说明了如何以常数变量的形式输出MySh
aredData?br>EXPORTS
    MySharedData CONSTANT
最后在应用E序Q进E)按外部变量引用共享数据?br>extern _export"C"{char * MySharedData[];}
q程中用该变量应注意间接引用?br>m_pStatic=(CEdit*)GetDlgItem(IDC_SHARED);
m_pStatic->GetLine(0,*MySharedData,80);
3.3、用于传输只L据的WM_COPYDATA
传输只读数据可以使用Win32中的WM_COPYDATA消息。该消息的主要目的是允许在进E间
传递只L据。Windows95在通过WM_COPYDATA消息传递期_不提供承同步方式。SD
K文档推荐用户使用SendMessage函数Q接受方在数据拷贝完成前不返回,q样发送方?br>不可能删除和修改数据Q?br>SendMessage(hwnd,WM_COPYDATA,wParam,lParam);
其中wParam讄为包含数据的H口的句柄。lParam指向一个COPYDATASTRUCT的结构:
typedef struct tagCOPYDATASTRUCT{
    DWORD dwData;//用户定义数据
    DWORD cbData;//数据大小
    PVOID lpData;//指向数据的指?br>}COPYDATASTRUCT;
该结构用来定义用h据?br>3.4、直接调用ReadProcessMemory和WriteProcessMemory函数实现q程间通讯
通过调用ReadProcessMemory以及WriteProcessMemory函数用户可以按类gWindows3.
1的方法实现进E间通讯Q在发送进E中分配一块内存存放数据,可以调用GlobalAlloc
或者VirtualAlloc函数实现Q?br>pApp->m_hGlobalHandle=GlobalAlloc(GMEM_SHARE,1024);
可以得到指针地址Q?br>pApp->mpszGlobalHandlePtr=(LPSTR)GlobalLock
(pApp->m_hGlobalHandle);
在接收进E中要用到用户希望媄响的q程的打开句柄。ؓ了读写另一q程Q应按如下方
式调用OpenProcess函数Q?br>HANDLE hTargetProcess=OpenProcess(
STANDARD_RIGHTS_REQUIRED|
PROCESS_VM_REDA|
PROCESS_VM_WRITE|
PROCESS_VM_OPERATION,//讉K权限
FALSE,//l承关系
dwProcessID);//q程ID
Z证OpenProcess函数调用成功Q用h影响的进E必ȝ上述标志创徏?br>一旦用戯得一个进E的有效句柄Q就可以调用ReadProcessMemory函数d该进E的?br>存:
BOOL ReadProcessMemory(
HANDLE hProcess,    // q程指针
LPCVOID lpBaseAddress,    // 数据块的首地址
LPVOID lpBuffer,    // d数据所需~冲?br>DWORD cbRead,    // 要读取的字节?br>LPDWORD lpNumberOfBytesRead
);
使用同样的句柄也可以写入该进E的内存Q?br>BOOL WriteProcessMemory(
HANDLE hProcess,    // q程指针
LPVOID lpBaseAddress,    // 要写入的首地址
LPVOID lpBuffer,    // ~冲区地址
DWORD cbWrite,    // 要写的字节数
LPDWORD lpNumberOfBytesWritten
);
如下所C是d另一q程的共享内存中的数据:
ReadProcessMemory((HANDLE)hTargetProcess,
(LPSTR)lpsz,m_strGlobal.GetBuffer(_MAX_FIELD),
_MAX_FIELD,&cb);
WriteProcessMemory((HANDLE)hTargetProcess,
(LPSTR)lpsz,(LPSTR)STARS,
m_strGlobal.GetLength(),&cb);
4、进E之间的消息发送与接收
在实际应用中q程之间需要发送和接收Windows消息来通知q程间相互通讯Q发送方发?br>通讯的消息以通知接收方,接收方在收到发送方的消息后可以对内存q行d操作?br>
我们在程序设计中采用Windows注册消息q行消息传递,首先在发送进E初始化q程中进
行消息注册:
m_nMsgMapped=::RegisterWindowsMessage("Mapped");
m_nMsgHandle=::RegisterWindowsMessage("Handle");
m_nMsgShared=::RegisterWindowsMessage("Shared");
在程序运行中向接收进E发送消息:
CWnd* pWndRecv=FindWindow(lpClassName,"Receive");
pWndRecv->SendMessage(m_MsgMapped,0,0);
pWndRecv->SendMessage(m_nMsgHandle,
(UINT)GetCurrentProcessID(),(LONG)pApp->m_hGlobalHandle);
pWndRecv->SendMessage(m_nMsgShared,0,0);
可以按如下方式发送WM_COPYDATA消息Q?br>static COPYDATASTRUCT cds;//用户存放数据
pWnd->SendMessage(WM_COPYDATA,NULL,(LONG)&cds);
接收方进E初始化也必进行消息注册:
UNIT CRecvApp:: m_nMsgMapped=::RegisterWindowsMessage("Mapped");
UNIT CRecvApp::m_nMsgHandle=::RegisterWindowsMessage("Handle");
UNIT CRecvApp::m_nMsgShared=::RegisterWindowsMessage("Shared");
同时映射消息函数如下Q?br>ON_REGISTERED_MASSAGE(CRecvApp::m_nMsgMapped,OnRegMsgMapped)
ON_REGISTERED_MASSAGE(CRecvApp::m_nMsgHandle,OnRegMsgHandle)
ON_REGISTERED_MASSAGE(CRecvApp::m_nMsgShared,OnRegMsgShared)
在这些消息函数我们就可以采用上述技术实现接收进E中数据的读写操作了?br>5、结束语
从以上分析中我们可以看出Windows95的内存管理与Windows 3.x相比有很多的不同Q对
q程之间的通讯有较Z格的限制。这q保了M故障E序无法意外地写入用L?br>址I间Q而用户则可根据实际情늁zdq行q程间的数据通讯Q从q一点上来讲Wind
ows95增强应用E序的强壮性?br>参考文献:
1?nbsp;David J.Kruglinski, Visual C++技术内q? 北京Q清华大学出版社Q?995.
2?nbsp;Microsoft Co. Visual C++ 5.0 On Line Help.


井泉 2007-12-13 15:50 发表评论
]]>
windows mobile 关闭gprsq接http://www.shnenglu.com/zjj2816/archive/2007/11/22/37127.html井泉井泉Thu, 22 Nov 2007 04:59:00 GMThttp://www.shnenglu.com/zjj2816/archive/2007/11/22/37127.htmlhttp://www.shnenglu.com/zjj2816/comments/37127.htmlhttp://www.shnenglu.com/zjj2816/archive/2007/11/22/37127.html#Feedback1http://www.shnenglu.com/zjj2816/comments/commentRss/37127.htmlhttp://www.shnenglu.com/zjj2816/services/trackbacks/37127.html{
     int index; // An integer index
     DWORD dwError, dwRasConnSize, dwNumConnections; // Number of connections found
     RASCONN RasConn[20]; // Buffer for connection state data,Assume the maximum number of entries is 20.
    BOOL RETURN_VALUE=0;
    WCHAR *MySelectNetName;

     // Assume no more than 20 connections.
     RasConn[0].dwSize = sizeof (RASCONN);
     dwRasConnSize = 20 * sizeof (RASCONN);

     // Find all connections.
     if (dwError = RasEnumConnections (RasConn, &dwRasConnSize,&dwNumConnections))
     {
          return -1;
     }

     // If there are no connections, return zero.
     if (!dwNumConnections)
     {
          return 0;
     }

     // Terminate all of the remote access connections.
     GetConnectionStatus();
    //here add to get selected network
    MySelectNetName=GetMMSSelectNet();
   
    GPRSServerName* P_CMWAPtemp=pCMWAP_backup;
     for (index = 0; index < (int)dwNumConnections; ++index)
     {
         while( P_CMWAPtemp )
         {
              if(!wcscmp(RasConn[index].szEntryName,P_CMWAPtemp->ServerName)||
                !wcscmp(RasConn[index].szEntryName, MySelectNetName))
              {
                   if (dwError = RasHangUp (RasConn[index].hrasconn))
                       
                        RETURN_VALUE=-1;
                   else
                           //successfully disconnect cmwap;
                        RETURN_VALUE=0;
              }
            P_CMWAPtemp = P_CMWAPtemp->pnext ;
          }
     }
    //free mem
     freelink(pCMWAP_backup);
     return RETURN_VALUE;
}




井泉 2007-11-22 12:59 发表评论
]]>
c++ ?jscripthttp://www.shnenglu.com/zjj2816/archive/2007/11/20/36988.html井泉井泉Tue, 20 Nov 2007 01:19:00 GMThttp://www.shnenglu.com/zjj2816/archive/2007/11/20/36988.htmlhttp://www.shnenglu.com/zjj2816/comments/36988.htmlhttp://www.shnenglu.com/zjj2816/archive/2007/11/20/36988.html#Feedback0http://www.shnenglu.com/zjj2816/comments/commentRss/36988.htmlhttp://www.shnenglu.com/zjj2816/services/trackbacks/36988.html
#include <afxdisp.h>
#include <activscp.h>

class CCodeObject;
class CScriptSite;

class CScriptingSupportHelper
{
public:
    CScriptingSupportHelper();
    ~CScriptingSupportHelper();

    BOOL Create(CWnd* pWnd);
    BOOL RunScript(CString str);

    CCodeObject* GetCodeObject() const { return m_pCodeObject; }
    CScriptSite* GetScriptSite() const { return m_pScriptSite; }
    IActiveScript* GetActiveScript() const { return m_pActiveScript; }

private:
    CCodeObject* m_pCodeObject;
    CScriptSite* m_pScriptSite;

    IActiveScript* m_pActiveScript;  
    IActiveScriptParse* m_pActiveScriptParse;
};

class CCodeObject : public CCmdTarget
{
public:
    CCodeObject(CScriptingSupportHelper* pScripting, CWnd* pWnd);
    virtual ~CCodeObject();

    void Line(long, long, long, long);
    void Ellipse(long, long, long, long);
    void DrawText(LPCTSTR msg, long x, long y, long w, long h);

    void OnPaint();
    void OnMouseClick(long x, long y);

private:
    CWnd* m_pWnd;
    CScriptingSupportHelper* m_pScripting;
    BOOL GetDispatch(OLECHAR* name, COleDispatchDriver& disp, DISPID& dispid);

    enum
    {
        idLine = 1,
        idEllipse,
        idDrawText,
    };

    DECLARE_DISPATCH_MAP()
};

class CScriptSite : public IActiveScriptSite
{
public:
    CScriptSite(CScriptingSupportHelper* pScripting)  
    {
        m_pScripting = pScripting;
    };
   
    ~CScriptSite() 
    {
    };

    virtual ULONG STDMETHODCALLTYPE AddRef()
    {   
        return InterlockedIncrement(&m_nRefCount);
    }
   
    virtual ULONG STDMETHODCALLTYPE Release()
    {    
        return InterlockedDecrement(&m_nRefCount);
    };
   
    virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void** ppObj)
    {
        *ppObj = NULL;

        if ((iid == IID_IUnknown) || (iid == IID_IActiveScriptSite))
        {
            *ppObj= (IActiveScriptSite*)this;
            AddRef();
            return S_OK;
        }

        return E_NOINTERFACE;
    }

    virtual HRESULT STDMETHODCALLTYPE GetLCID(LCID __RPC_FAR *)
    {
        return E_NOTIMPL;
    }
   
    virtual HRESULT STDMETHODCALLTYPE GetItemInfo(LPCOLESTR, DWORD, IUnknown __RPC_FAR *__RPC_FAR * pObj, ITypeInfo __RPC_FAR *__RPC_FAR *)
    {
        ASSERT(m_pScripting);
        ASSERT(m_pScripting->GetCodeObject());

        *pObj = m_pScripting->GetCodeObject()->GetIDispatch(TRUE);
        return S_OK;
    }
       
    virtual HRESULT STDMETHODCALLTYPE GetDocVersionString(BSTR __RPC_FAR *)
    {
        return E_NOTIMPL;
    }
       
    virtual HRESULT STDMETHODCALLTYPE OnScriptTerminate(const VARIANT __RPC_FAR * ,const EXCEPINFO __RPC_FAR *)
    {
        return E_NOTIMPL;
    }

       
    virtual HRESULT STDMETHODCALLTYPE OnStateChange(SCRIPTSTATE)
    {
        return E_NOTIMPL;
    }
       
    virtual HRESULT STDMETHODCALLTYPE OnScriptError(IActiveScriptError __RPC_FAR * pScriptError)
    {
        return E_NOTIMPL;
    }
       
    virtual HRESULT STDMETHODCALLTYPE OnEnterScript()
    {
        return E_NOTIMPL;
    }
       
    virtual HRESULT STDMETHODCALLTYPE OnLeaveScript()
    {
        return E_NOTIMPL;
    }

private:
    long m_nRefCount;
    CScriptingSupportHelper* m_pScripting;
};

#include "StdAfx.h"
#include "ScriptingSupport.h"

CCodeObject::CCodeObject(CScriptingSupportHelper* pScripting, CWnd* pWnd)
    : m_pWnd(pWnd),
      m_pScripting(pScripting)

{
    EnableAutomation();
}

CCodeObject::~CCodeObject()
{
}

BEGIN_DISPATCH_MAP(CCodeObject, CCmdTarget)
DISP_FUNCTION_ID(CCodeObject, "Line", idLine, Line, VT_EMPTY, VTS_I4 VTS_I4 VTS_I4 VTS_I4)
DISP_FUNCTION_ID(CCodeObject, "Ellipse", idEllipse, Ellipse, VT_EMPTY, VTS_I4 VTS_I4 VTS_I4 VTS_I4)
DISP_FUNCTION_ID(CCodeObject, "DrawText", idDrawText, DrawText, VT_EMPTY, VTS_BSTR VTS_I4 VTS_I4 VTS_I4 VTS_I4)
END_DISPATCH_MAP()

void CCodeObject::Line(long x1, long y1, long x2, long y2)
{
    CWindowDC dc(m_pWnd);

    dc.MoveTo(x1, y1);
    dc.LineTo(x2, y2);
}

void CCodeObject::Ellipse(long x1, long y1, long x2, long y2)
{
    CWindowDC dc(m_pWnd);
    dc.Ellipse(x1, y1, x2, y2);
}

void CCodeObject::DrawText(LPCTSTR msg, long x, long y, long w, long h)
{
    CWindowDC dc(m_pWnd);
    CRect rect(x, y, x+w, y+h);

    dc.DrawText(msg, rect, 0);
}

void CCodeObject::OnPaint()
{
    COleDispatchDriver disp;
    DISPID dispid;
    if (GetDispatch(L"OnPaint", disp, dispid)) {
        disp.InvokeHelper(dispid, DISPATCH_METHOD, VT_EMPTY, 0, 0);
    }
}

BOOL CCodeObject::GetDispatch(OLECHAR* name, COleDispatchDriver& disp, DISPID& dispid)
{
    IDispatch* pScriptDispatch = 0;
    m_pScripting->GetActiveScript()->GetScriptDispatch(0, &pScriptDispatch);
    disp.AttachDispatch(pScriptDispatch);
    HRESULT hr = pScriptDispatch->GetIDsOfNames(IID_NULL, &name, 1, LOCALE_SYSTEM_DEFAULT, &dispid);
    return SUCCEEDED(hr);
}

void CCodeObject::OnMouseClick(long x, long y)
{
    COleDispatchDriver disp;
    DISPID dispid;
    if (GetDispatch(L"OnMouseClick", disp, dispid)) {
        disp.InvokeHelper(dispid, DISPATCH_METHOD, VT_EMPTY, 0, (const BYTE*)(VTS_I4 VTS_I4), x, y);
    }
}

CScriptingSupportHelper::CScriptingSupportHelper()
    : m_pCodeObject(0),
      m_pScriptSite(0),
      m_pActiveScript(0),
      m_pActiveScriptParse(0)
{
}

CScriptingSupportHelper::~CScriptingSupportHelper()
{
    if (m_pActiveScript)
    {
        m_pActiveScript->Close();
        m_pActiveScriptParse->Release();
        m_pActiveScript->Release();
    }

    delete m_pCodeObject; m_pCodeObject=0;
    delete m_pScriptSite; m_pScriptSite=0;
}

BOOL CScriptingSupportHelper::RunScript(CString strText)
{
    EXCEPINFO ei = {0};
    BSTR bstrText = strText.AllocSysString();
    m_pActiveScriptParse->ParseScriptText(bstrText, NULL, NULL, NULL, 0, 0, 0, NULL, &ei);
    SysFreeString(bstrText);

    m_pActiveScript->SetScriptState(SCRIPTSTATE_CONNECTED);

    return TRUE;
}

BOOL CScriptingSupportHelper::Create(CWnd* pWnd)
{
    m_pCodeObject = new CCodeObject(this, pWnd);
    m_pScriptSite = new CScriptSite(this);

    CLSID clsidJScript;
    CLSIDFromProgID(L"JScript", &clsidJScript);
    CoCreateInstance(clsidJScript, NULL, CLSCTX_INPROC_SERVER, IID_IActiveScript, (void **)&m_pActiveScript);
    m_pActiveScript->QueryInterface(IID_IActiveScriptParse, (void**)&m_pActiveScriptParse);
    m_pActiveScript->SetScriptSite(m_pScriptSite);
    m_pActiveScript->AddNamedItem(L"Code", SCRIPTITEM_ISVISIBLE | SCRIPTITEM_ISSOURCE | SCRIPTITEM_GLOBALMEMBERS);
    m_pActiveScriptParse->InitNew();


    return TRUE;
}






井泉 2007-11-20 09:19 发表评论
]]>
(msdn)Using MFC to Automate SAPI (SAPI 5.3)http://msdn2.microsoft.com/en-us/library/ms717069.aspxhttp://www.shnenglu.com/zjj2816/archive/2007/11/20/36985.html井泉井泉Tue, 20 Nov 2007 01:06:00 GMThttp://www.shnenglu.com/zjj2816/archive/2007/11/20/36985.htmlhttp://www.shnenglu.com/zjj2816/comments/36985.htmlhttp://www.shnenglu.com/zjj2816/archive/2007/11/20/36985.html#Feedback0http://www.shnenglu.com/zjj2816/comments/commentRss/36985.htmlhttp://www.shnenglu.com/zjj2816/services/trackbacks/36985.htmlMicrosoft Speech API 5.3   用oleview 可以产生 idl 文g 再用 midl工具 可以产生 tlb,h,c 存根文g {?

Using MFC to Automate SAPI

Introduction

The Microsoft Foundation Classes (MFC) provides an easy and convenient way to automate calls to SAPI using its Class Wizard to generate wrappers for the SAPI layer from the SAPI Type Library.

In order to accomplish this, perform the following steps:

  1. Create a new MFCAppWizard(exe) project in Visual C++.
  2. Based on the type of application you are creating, follow the wizard prompts. In Step 3 of the wizard prompts, (or Step 2 if you are creating a Dialog Based application) make sure that the Automation check box is selected under the heading, What other support would you like to include?

Once the new project is ready, access Class Wizard.

  1. Click the Automation tab, and then click Add Class and select From a type library in the drop-down list.
  2. Browse for the sapi.dll file and open it.
  3. Select the classes you would like Class Wizard to generate a wrapper for. The resulting default header and implementation files are sapi.h and sapi.cpp respectively. The rest of this document assumes that you have chosen to use these default file names. Click OK.
  4. You should now be back in the Class Wizard window. Click OK.
After you are done with the above steps, Visual C++ will automatically add the Class Wizard generated files sapi.cpp and sapi.h to your project.

Upon viewing the sapi.h file, you should notice that it is nothing more than an automation wrapper that has been generated for all the classes you selected. Notice that all the classes inherit from COleDispatchDriver, hence the dispatch interface needs to be set up. This only requires a few lines of simple code, after which the wrapper class can be used just like any other C++ class.

Example

This example assumes that you chose to generate a wrapper for the ISpeechVoice class from among any other classes you may have selected. Using the project created above, include the sapi.h file within a source file in the project that will make automation calls to SAPI using the wrapper. In that source file, type the following code.

CLSID CLSID_SpVoice;    // class ID for the SAPI SpVoice object
LPDISPATCH pDisp; // dispatch interface for the class
ISpeechVoice voice; // use the MFC Class Wizard generated wrapper

CLSIDFromProgID(L"SAPI.SpVoice", &CLSID;_SpVoice);
voice.CreateDispatch(CLSID_SpVoice);
pDisp = voice.m_lpDispatch;

HRESULT hr = pDisp->QueryInterface(CLSID_SpVoice, (void**)&voice;.m_lpDispatch);

if (hr == S_OK) {
pDisp->Release();
}
else {
voice.AttachDispatch(pDisp, TRUE);
}

voice.Speak("hello world", 1); // asynchronous call to Speak method of ISpeechVoice interface

If you have been following the steps outlined above properly, you should hear your computer say "hello world!" That's all there is to using MFC to make automation calls to SAPI. Currently however, not all the wrapper classes generated by MFC's Class Wizard work properly. For instance, the ISpeechLexicon interface does not work. The work around for this is to implement your own automation wrapper classes using C++. The steps to do that are beyond the scope of this document. Of course, you can always use the COM interfaces in C++ and Automation in Visual Basic to ensure that every interface in SAPI works easily and flawlessly.



井泉 2007-11-20 09:06 发表评论
]]>
客户端调用comhttp://www.shnenglu.com/zjj2816/archive/2007/11/20/36983.html井泉井泉Tue, 20 Nov 2007 00:49:00 GMThttp://www.shnenglu.com/zjj2816/archive/2007/11/20/36983.htmlhttp://www.shnenglu.com/zjj2816/comments/36983.htmlhttp://www.shnenglu.com/zjj2816/archive/2007/11/20/36983.html#Feedback0http://www.shnenglu.com/zjj2816/comments/commentRss/36983.htmlhttp://www.shnenglu.com/zjj2816/services/trackbacks/36983.html{
    ::CoInitializeEx(NULL, COINIT_MULTITHREADED);
    //    {2D8EBDEE-437C-47c9-ABCC-F169E5E781D0}speeddial
    //    {85140985-7A18-4009-B5FB-43268FD154F8}ISpRecognizerLite
     
        CLSID CLSID_SpVoice;
        ::CLSIDFromProgID(L"SpeedDial", &CLSID_SpVoice);
        LPCLASSFACTORY pClsF;
        LPUNKNOWN punk;                   ::CoGetClassObject(CLSID_SpVoice,CLSCTX_INPROC_SERVER,NULL,IID_IClassFactory,(void**)&pClsF);
        pClsF->CreateInstance(NULL,IID_IUnknown,(void**)&punk);
    punk->QueryInterface(IID_ISpRecognizerLite,(void**)&非抽象类);
    ::CoUninitialize();
}


井泉 2007-11-20 08:49 发表评论
]]>
(?手工注册comhttp://www.shnenglu.com/zjj2816/archive/2007/11/20/36982.html井泉井泉Tue, 20 Nov 2007 00:48:00 GMThttp://www.shnenglu.com/zjj2816/archive/2007/11/20/36982.htmlhttp://www.shnenglu.com/zjj2816/comments/36982.htmlhttp://www.shnenglu.com/zjj2816/archive/2007/11/20/36982.html#Feedback0http://www.shnenglu.com/zjj2816/comments/commentRss/36982.htmlhttp://www.shnenglu.com/zjj2816/services/trackbacks/36982.html{
    //for registration
    HMODULE hLib = ::LoadLibrary(strLib);
    if(hLib == 0) {
        return FALSE;
    }
    HRESULT (STDAPICALLTYPE *pDllRegisterServer)();
    (FARPROC&)pDllRegisterServer = ::GetProcAddress(hLib, _T("DllRegisterServer"));
    if(pDllRegisterServer == NULL) {  
        ::FreeLibrary(hLib);
        return FALSE;
    }
    if(FAILED(pDllRegisterServer ())) {
        ::FreeLibrary(hLib);
        return FALSE;
    } else {
        ::FreeLibrary(hLib);
        return TRUE;
    }
}

BOOL unregcom(LPCWSTR strLib)
{
    HMODULE hLib = ::LoadLibrary(strLib);
    if(hLib == 0) {
        return FALSE;
    }
    HRESULT (STDAPICALLTYPE *pDllUnregisterServer)();
    (FARPROC&)pDllUnregisterServer = ::GetProcAddress(hLib, _T("DllUnregisterServer"));
    if(pDllUnregisterServer == NULL) {
        ::FreeLibrary(hLib);
        return FALSE;
    }
    if(FAILED(pDllUnregisterServer())) {
        ::FreeLibrary(hLib);
        return FALSE;
    } else {
        ::FreeLibrary(hLib);
        return TRUE;
    }
}




井泉 2007-11-20 08:48 发表评论
]]>
(?Rapi 使用http://www.shnenglu.com/zjj2816/archive/2007/11/20/36981.html井泉井泉Tue, 20 Nov 2007 00:46:00 GMThttp://www.shnenglu.com/zjj2816/archive/2007/11/20/36981.htmlhttp://www.shnenglu.com/zjj2816/comments/36981.htmlhttp://www.shnenglu.com/zjj2816/archive/2007/11/20/36981.html#Feedback0http://www.shnenglu.com/zjj2816/comments/commentRss/36981.htmlhttp://www.shnenglu.com/zjj2816/services/trackbacks/36981.html{
    CFile oldFile;
    oldFile.Open(strFileNamePC, CFile::modeRead |CFile::typeBinary);
    int iLen = oldFile.GetLength();
    iLen = iLen / BUFFER_SIZE;
    BSTR bstr = strFileNamePPC.AllocSysString();
    SysFreeString(bstr);
    CeRapiInit();
    HANDLE h = CeCreateFile(bstr, GENERIC_READ | GENERIC_WRITE, 0, NULL,
        OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
    char cTemp[BUFFER_SIZE];
    DWORD nbytes;
    int iTotBytes = 0;
    int iReaded=0;
    while((iReaded=oldFile.Read(&cTemp, BUFFER_SIZE)) >= 1)
        CeWriteFile(h, &cTemp, (DWORD)iReaded, &nbytes, NULL);
    CeCloseHandle(h);
    oldFile.Close();
    CeRapiUninit();
}

void CopyFileWinCEtoPC(CString strFileNamePPC, CString strFileNamePC)
{
    BSTR bstr = strFileNamePPC.AllocSysString();
    SysFreeString(bstr);
    CeRapiInit();

    HANDLE h;
    h = CeCreateFile(bstr, GENERIC_READ, FILE_SHARE_READ, NULL,
        OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

    CFile oldFile;
    oldFile.Open(strFileNamePC, CFile::modeCreate | CFile::modeWrite);

    char cTemp[BUFFER_SIZE];
    DWORD nbytes;
    CString s;

    while(CeReadFile(h, &cTemp, (DWORD)BUFFER_SIZE, &nbytes, NULL) == TRUE)
    {
        oldFile.Write(&cTemp, nbytes);
        if(nbytes < BUFFER_SIZE)
            break;
    }
    CeCloseHandle(h);
    oldFile.Close();
    CeRapiUninit(); 
}

BOOL DeleteFileFromCE(CString strFileNamePPC)
{
    BSTR bstr = strFileNamePPC.AllocSysString();
    SysFreeString(bstr);
    CeRapiInit();
    BOOL bRet = CeDeleteFile(bstr);
    CeRapiUninit();
    return bRet;
}




井泉 2007-11-20 08:46 发表评论
]]>
函数Ҏhttp://www.shnenglu.com/zjj2816/archive/2007/11/19/36923.html井泉井泉Mon, 19 Nov 2007 02:25:00 GMThttp://www.shnenglu.com/zjj2816/archive/2007/11/19/36923.htmlhttp://www.shnenglu.com/zjj2816/comments/36923.htmlhttp://www.shnenglu.com/zjj2816/archive/2007/11/19/36923.html#Feedback0http://www.shnenglu.com/zjj2816/comments/commentRss/36923.htmlhttp://www.shnenglu.com/zjj2816/services/trackbacks/36923.html
用_t替换字符'w',比如 wcsncpy  to _tcsncpy(自适应函数).

_tcsncpy_l 后缀  _l 不推荐用的函数

_tcsncpy_s 后缀  _s Security Enhancements in the CRT

_tcsncpy_s_l 后缀  _s_l ?_s

security enhancements


宽字W处理函数函C普通函数对照表 
  
 

字符分类Q?nbsp;    宽字W函数普通C函数描述 
iswalnumQ)     isalnumQ) 试字符是否为数字或字母 
iswalphaQ)     isalphaQ) 试字符是否是字?nbsp;
iswcntrlQ)     iscntrlQ) 试字符是否是控制符 
iswdigitQ)     isdigitQ) 试字符是否为数?nbsp;
iswgraphQ)     isgraphQ) 试字符是否是可见字W?nbsp;
iswlowerQ)     islowerQ) 试字符是否是小写字W?nbsp;
iswprintQ)     isprintQ) 试字符是否是可打印字符 
iswpunctQ)     ispunctQ) 试字符是否是标点符?nbsp;
iswspaceQ)     isspaceQ) 试字符是否是空白符?nbsp;
iswupperQ)     isupperQ) 试字符是否是大写字W?nbsp;
iswxdigitQ)     isxdigitQ)试字符是否是十六进制的数字 


大小写{换:     
宽字W函?nbsp;   普通C函数描述 
towlowerQ)     tolowerQ) 把字W{换ؓ写 
towupperQ)     toupperQ) 把字W{换ؓ大写 


字符比较Q?nbsp;    宽字W函数普通C函数描述 
wcscollQ)     strcollQ) 比较字符?nbsp;


日期和时间{换: 
宽字W函数描q?nbsp;
strftimeQ)     Ҏ指定的字W串格式和locale讄格式化日期和旉 
wcsftimeQ)     Ҏ指定的字W串格式和locale讄格式化日期和旉Q?nbsp;q返回宽字符?nbsp;
strptimeQ)     Ҏ指定格式把字W串转换为时间| 是strftime的反q程 


打印和扫描字W串Q?nbsp;
宽字W函数描q?nbsp;
fprintfQ)
/fwprintfQ)     使用vararg参量的格式化输出 
fscanfQ)
/fwscanfQ)         格式化读?nbsp;
printfQ)             使用vararg参量的格式化输出到标准输?nbsp;
scanfQ)             从标准输入的格式化读?nbsp;
sprintfQ)
/swprintfQ)     Ҏvararg参量表格式化成字W串 
sscanfQ)             以字W串作格式化d 
vfprintfQ)
/vfwprintfQ)     使用stdarg参量表格式化输出到文?nbsp;
vprintfQ)             使用stdarg参量表格式化输出到标准输?nbsp;
vsprintfQ)
/vswprintfQ)     格式化stdarg参量表ƈ写到字符?nbsp;


数字转换Q?nbsp;
宽字W函?nbsp;   普通C函数描述 
wcstodQ)     strtodQ)  把宽字符的初始部分{换ؓ双精度QҎ 
wcstolQ)     strtolQ)  把宽字符的初始部分{换ؓ长整?nbsp;
wcstoulQ)     strtoulQ) 把宽字符的初始部分{换ؓ无符号长整数 


多字节字W和宽字W{换及操作Q?nbsp;
宽字W函数描q?nbsp;
mblenQ)         Ҏlocale的设|确定字W的字节?nbsp;
mbstowcsQ)         把多字节字符串{换ؓ宽字W串 
mbtowcQ)
/btowcQ)    把多字节字符转换为宽字符 
wcstombsQ)         把宽字符串{换ؓ多字节字W串 
wctombQ)
/wctobQ)     把宽字符转换为多字节字符 


输入和输出: 
宽字W函?nbsp;   普通C函数描述 
fgetwcQ)     fgetcQ)     从流中读入一个字Wƈ转换为宽字符 
fgetwsQ)     fgetsQ)     从流中读入一个字W串q{换ؓ宽字W串 
fputwcQ)     fputcQ)     把宽字符转换为多字节字符q且输出到标准输?nbsp;
fputwsQ)     fputsQ)     把宽字符串{换ؓ多字节字Wƈ且输出到标准输出?nbsp;
getwcQ)     getcQ)     从标准输入中d字符Q?nbsp;q且转换为宽字符 
getwcharQ)     getcharQ)     从标准输入中d字符Q?nbsp;q且转换为宽字符 
None         getsQ)     使用fgetwsQ) 
putwcQ)     putcQ)     把宽字符转换成多字节字符q且写到标准输出 
putwcharQ)     putcharQ)     把宽字符转换成多字节字符q且写到标准输出 
None         putsQ)     使用fputwsQ) 
ungetwcQ)     ungetcQ)     把一个宽字符攑֛到输入流?nbsp;


字符串操作: 
宽字W函?nbsp;       普通C函数描述 
wcscatQ)         strcatQ)     把一个字W串接到另一个字W串的尾?nbsp;
wcsncatQ)         strncatQ)     cM于wcscatQ)Q?nbsp;而且指定_接字符串的_接长度. 
wcschrQ)         strchrQ)     查找子字W串的第一个位|?nbsp;
wcsrchrQ)         strrchrQ)     从尾部开始查扑֭字符串出现的W一个位|?nbsp;
wcspbrkQ)         strpbrkQ)     从一字符字符串中查找另一字符串中M一个字W第一ơ出现的位置 
wcswcsQ)
/wcsstrQ)     strchrQ)     在一字符串中查找另一字符串第一ơ出现的位置 
wcscspnQ)         strcspnQ)     q回不包含第二个字符串的的初始数?nbsp;
wcsspnQ)         strspnQ)     q回包含W二个字W串的初始数?nbsp;
wcscpyQ)         strcpyQ)     拯字符?nbsp;
wcsncpyQ)         strncpyQ)     cM于wcscpyQ)Q?nbsp;同时指定拯的数?nbsp;
wcscmpQ)         strcmpQ)     比较两个宽字W串 
wcsncmpQ)         strncmpQ)     cM于wcscmpQ)Q?nbsp;q要指定比较字符字符串的数目 
wcslenQ)         strlenQ)     获得宽字W串的数?nbsp;
wcstokQ)         strtokQ)     Ҏ标示W把宽字W串分解成一pd字符?nbsp;
wcswidthQ)         None         获得宽字W串的宽?nbsp;
wcwidthQ)         None         获得宽字W的宽度 


另外q有对应于memory操作?nbsp;wmemcpyQ)Q?nbsp;wmemchrQ)Q?nbsp;wmemcmpQ)Q?nbsp;wmemmoveQ)Q?nbsp;wmemsetQ)Q?/span>

井泉 2007-11-19 10:25 发表评论
]]>
IBasicVideo::GetCurrentImage 抓图http://www.shnenglu.com/zjj2816/archive/2007/11/19/36918.html井泉井泉Mon, 19 Nov 2007 00:40:00 GMThttp://www.shnenglu.com/zjj2816/archive/2007/11/19/36918.htmlhttp://www.shnenglu.com/zjj2816/comments/36918.htmlhttp://www.shnenglu.com/zjj2816/archive/2007/11/19/36918.html#Feedback0http://www.shnenglu.com/zjj2816/comments/commentRss/36918.htmlhttp://www.shnenglu.com/zjj2816/services/trackbacks/36918.htmlhttp://www.geekpage.jp/en/programming/directshow/getcurrentimage.php

#include <stdio.h>
#include <dshow.h>
// change here
#define	FILENAME L"C:\\DXSDK\\Samples\\Media\\butterfly.mpg"
// note that this sample fails on some environment
int
main()
{
IGraphBuilder *pGraphBuilder;
IMediaControl *pMediaControl;
IBasicVideo *pBasicVideo;
CoInitialize(NULL);
CoCreateInstance(CLSID_FilterGraph,
NULL,
CLSCTX_INPROC,
IID_IGraphBuilder,
(LPVOID *)&pGraphBuilder);
pGraphBuilder->QueryInterface(IID_IMediaControl,
(LPVOID *)&pMediaControl);
pMediaControl->RenderFile(FILENAME);

pGraphBuilder->QueryInterface(IID_IBasicVideo,
(LPVOID *)&pBasicVideo);

pMediaControl->Run();
// The image will be saved when OK is clicked
MessageBox(NULL,
"Grab Image",
"Grab",
MB_OK);

// Must Pause before using GetCurrentImage
pMediaControl->Pause();
// get width and height
long height, width;
pBasicVideo->get_VideoHeight(&height);
pBasicVideo->get_VideoWidth(&width);
long bufSize;
long *imgData;
HRESULT hr;
/*
The second value is NULL to resolve required buffer size.
The required buffer size will be returned in variable "bufSize".
*/
hr = pBasicVideo->GetCurrentImage(&bufSize, NULL);
if (FAILED(hr)) {
printf("GetCurrentImage failed\n");
return 1;
}
if (bufSize < 1) {
printf("failed to get data size\n");
return 1;
}
imgData = (long *)malloc(bufSize);
// The data will be in DIB format
pBasicVideo->GetCurrentImage(&bufSize, imgData);

// save DIB file as Bitmap.
// This sample saves image as bitmap to help
// understanding the sample.
HANDLE fh;
BITMAPFILEHEADER bmphdr;
BITMAPINFOHEADER bmpinfo;
DWORD nWritten;
memset(&bmphdr, 0, sizeof(bmphdr));
memset(&bmpinfo, 0, sizeof(bmpinfo));
bmphdr.bfType = ('M' << 8) | 'B';
bmphdr.bfSize = sizeof(bmphdr) + sizeof(bmpinfo) + bufSize;
bmphdr.bfOffBits = sizeof(bmphdr) + sizeof(bmpinfo);
bmpinfo.biSize = sizeof(bmpinfo);
bmpinfo.biWidth = width;
bmpinfo.biHeight = height;
bmpinfo.biPlanes = 1;
bmpinfo.biBitCount = 32;
fh = CreateFile("result.bmp",
GENERIC_WRITE, 0, NULL,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
WriteFile(fh, &bmphdr, sizeof(bmphdr), &nWritten, NULL);
WriteFile(fh, &bmpinfo, sizeof(bmpinfo), &nWritten, NULL);
WriteFile(fh, imgData, bufSize, &nWritten, NULL);
CloseHandle(fh);

free(imgData);
// Release resource
pBasicVideo->Release();

pMediaControl->Release();
pGraphBuilder->Release();
CoUninitialize();
return 0;
}


井泉 2007-11-19 08:40 发表评论
]]>
C++cd象的拯构造函数分?/title><link>http://www.shnenglu.com/zjj2816/archive/2006/12/01/15831.html</link><dc:creator>井泉</dc:creator><author>井泉</author><pubDate>Fri, 01 Dec 2006 00:52:00 GMT</pubDate><guid>http://www.shnenglu.com/zjj2816/archive/2006/12/01/15831.html</guid><wfw:comment>http://www.shnenglu.com/zjj2816/comments/15831.html</wfw:comment><comments>http://www.shnenglu.com/zjj2816/archive/2006/12/01/15831.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/zjj2816/comments/commentRss/15831.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/zjj2816/services/trackbacks/15831.html</trackback:ping><description><![CDATA[对于普通类型的对象来说Q它们之间的复制是很单的Q例如: <br /><br /><table bordercolor="#cccccc" width="90%" align="center" bgcolor="#e7e9e9" border="1"><tbody><tr><td>int a=100;<br />int b=a;</td></tr></tbody></table><br />  而类对象与普通对象不同,cd象内部结构一般较为复杂,存在各种成员变量。下面看一个类对象拯的简单例子?<br /><br /><table bordercolor="#cccccc" width="90%" align="center" bgcolor="#e7e9e9" border="1"><tbody><tr><td>#include <iostream><br />using namespace std;<br />class CA<br />{<br /> public:<br />  CA(int b)<br />  {<br />   a=b;<br />  }<br />  void Show ()<br />  {<br />   cout<<a<<endl;<br />  }<br /> private:<br />  int a;<br />};<br /><br />int main()<br />{<br /> CA A(100);<br /> CA B=A;<br /> B.Show ();<br /> return 0;<br />}</td></tr></tbody></table><br />  q行<a class="bluekey" target="_blank">E序</a>Q屏q输?00。从以上代码的运行结果可以看出,pȝ为对象B分配了内存ƈ完成了与对象A的复制过E。就cd象而言Q相同类型的cd象是通过拯构造函数来完成整个复制q程的。下面我们D例说明拷贝构造函数的工作q程?br /><br /><table bordercolor="#cccccc" width="90%" align="center" bgcolor="#e7e9e9" border="1"><tbody><tr><td>#include <iostream><br />using namespace std;<br />class CA<br />{<br /> public:<br />  CA(int b)<br />  {<br />   a=b;<br />  }<br />  CA(const CA& C)<br />  {<br />   a=C.a;<br />  }<br />  void Show()<br />  {<br />   cout<<a<<endl;<br />  }<br /> private:<br />  int a;<br />};<br /><br />int main()<br />{<br /> CA A(100);<br /> CA B=A;<br /> B.Show ();<br /> return 0;<br />}</td></tr></tbody></table><br />  CA(const CA& C)是我们自定义的拯构造函数。可见,拯构造函数是一U特D的构造函敎ͼ函数的名U必dcdUC_它的唯一的一个参数是本类型的一个引用变量,该参数是constcdQ不可变的。例如:cX的拷贝构造函数的形式为X(X& x)?br /><br />  当用一个已初始化过了的自定义类cd对象d始化另一个新构造的对象的时候,拯构造函数就会被自动调用。也是_当类的对象需要拷贝时Q拷贝构造函数将会被调用。以下情况都会调用拷贝构造函敎ͼ<br /><br />  一个对象以g递的方式传入函数?<br /><br />  一个对象以g递的方式从函数返?<br /><br />  一个对象需要通过另外一个对象进行初始化?<br /><br />  如果在类中没有显式地声明一个拷贝构造函敎ͼ那么Q编译器会自动生成一个默认的拯构造函敎ͼ该构造函数完成对象之间的位拷贝。位拯又称拷贝,后面进行说明?<br /><br />  自定义拷贝构造函数是一U良好的~程风格Q它可以L~译器Ş成默认的拯构造函敎ͼ提高源码效率?br /><br />  <b>拷贝和深拷?/b><br /><br />  在某些状况下Q类内成员变量需要动态开辟堆内存Q如果实行位拯Q也是把对象里的值完全复制给另一个对象,如A=B。这Ӟ如果B中有一个成员变量指针已l申请了内存Q那A中的那个成员变量也指向同一块内存。这出C问题Q当B把内存释放了Q如Q析构)Q这时A内的指针是野指针了Q出现运行错误?br /><br />  深拷贝和拷贝可以简单理解ؓQ如果一个类拥有资源Q当q个cȝ对象发生复制q程的时候,资源重新分配Q这个过E就是深拯Q反之,没有重新分配资源Q就是浅拯。下面D个深拯的例子?<br /><br /><table bordercolor="#cccccc" width="90%" align="center" bgcolor="#e7e9e9" border="1"><tbody><tr><td>#include <iostream><br />using namespace std;<br />class CA<br />{<br /> public:<br />  CA(int b,char* cstr)<br />  {<br />   a=b;<br />   str=new char[b];<br />   strcpy(str,cstr);<br />  }<br />  CA(const CA& C)<br />  {<br />   a=C.a;<br />   str=new char[a]; //深拷?br />   if(str!=0)<br />    strcpy(str,C.str);<br />  }<br />  void Show()<br />  {<br />   cout<<str<<endl;<br />  }<br />  ~CA()<br />  {<br />   delete str;<br />  }<br /> private:<br />  int a;<br />  char *str;<br />};<br /><br />int main()<br />{<br /> CA A(10,"Hello!");<br /> CA B=A;<br /> B.Show();<br /> return 0;<br />}</td></tr></tbody></table><br />  好吧Q就说这些,希望本文能对您有所帮助?img src ="http://www.shnenglu.com/zjj2816/aggbug/15831.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/zjj2816/" target="_blank">井泉</a> 2006-12-01 08:52 <a href="http://www.shnenglu.com/zjj2816/archive/2006/12/01/15831.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>体验C++中接口与实现分离的技?/title><link>http://www.shnenglu.com/zjj2816/archive/2006/07/05/9419.html</link><dc:creator>井泉</dc:creator><author>井泉</author><pubDate>Wed, 05 Jul 2006 01:59:00 GMT</pubDate><guid>http://www.shnenglu.com/zjj2816/archive/2006/07/05/9419.html</guid><wfw:comment>http://www.shnenglu.com/zjj2816/comments/9419.html</wfw:comment><comments>http://www.shnenglu.com/zjj2816/archive/2006/07/05/9419.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/zjj2816/comments/commentRss/9419.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/zjj2816/services/trackbacks/9419.html</trackback:ping><description><![CDATA[在用C++写要导出cȝ库时Q我们经常只x露接口,而隐藏类的实现细节。也是说我们提供的头文仉只提供要暴露的公共成员函数的声明Q类的其他所有信息都不会在这个头文g里面昄出来。这个时候就要用到接口与实现分离的技术?br /><br />  下面用一个最单的例子来说明?br /><br />  cClxExp是我们要导出的类Q其中有一个私有成员变量是ClxTestcȝ对象Q各个文件内容如下: <br /><br />  lxTest.h文g内容Q?br /><br /><table bordercolor="#cccccc" width="90%" align="center" bgcolor="#e3e3e3" border="1"><tbody><tr><td>class ClxTest <br />{<br /> public:<br />  ClxTest();<br />  virtual ~ClxTest();<br />  void DoSomething();<br />};</td></tr></tbody></table><br />  lxTest.cpp文g内容Q?br /><br /><table bordercolor="#cccccc" width="90%" align="center" bgcolor="#e3e3e3" border="1"><tbody><tr><td>#include "lxTest.h"<br /><br />#include <iostream><br />using namespace std;<br /><br />ClxTest::ClxTest()<br />{}<br /><br />ClxTest::~ClxTest()<br />{}<br /><br />void ClxTest::DoSomething()<br />{<br /> cout << "Do something in class ClxTest!" << endl;<br />}<br /><br />////////////////////////////////////////////////////////////////////////////</td></tr></tbody></table><br />  lxExp.h文g内容Q?br /><br /><table bordercolor="#cccccc" width="90%" align="center" bgcolor="#e3e3e3" border="1"><tbody><tr><td>#include "lxTest.h"<br /><br />class ClxExp <br />{<br /> public:<br />  ClxExp();<br />  virtual ~ClxExp();<br />  void DoSomething();<br /> private:<br />  ClxTest m_lxTest;<br />  void lxTest();<br />};</td></tr></tbody></table><br />  lxExp.cpp文g内容Q?br /><br /><table bordercolor="#cccccc" width="90%" align="center" bgcolor="#e3e3e3" border="1"><tbody><tr><td>#include "lxExp.h"<br /><br />ClxExp::ClxExp()<br />{}<br /><br />ClxExp::~ClxExp()<br />{}<br /><br />// 其实该方法在q里q没有必要,我这样只是ؓ了说明调用关p?br />void ClxExp::lxTest()<br />{<br /> m_lxTest.DoSomething(); <br />}<br /><br />void ClxExp::DoSomething()<br />{<br /> lxTest();<br />}</td></tr></tbody></table><br />  Z让用戯使用我们的类ClxExpQ我们必L供lxExp.h文gQ这LClxExp的私有成员也暴露l用户了。而且Q仅仅提供lxExp.h文g是不够的Q因为lxExp.h文ginclude了lxTest.h文gQ在q种情况下,我们q要提供lxTest.h文g。那样ClxExpcȝ实现l节全暴露l用户了。另外,当我们对cClxTest做了修改Q如d或删除一些成员变量或ҎQ时Q我们还要给用户更新lxTest.h文gQ而这个文件是跟接口无关的。如果类ClxExp里面有很多像m_lxTest那样的对象的话,我们pl用h供N个像lxTest.h那样的头文gQ而且其中M一个类有改动,我们都要l用h新头文g。还有一点就是用户在q种情况下必进行重新编译!<br /><br />  上面是非常小的一个例子,重新~译的时间可以忽略不计。但是,如果cClxExp被用户大量用的话,那么在一个大目中,重新~译的时候我们就有时间可以去喝杯咖啡什么的了。当然上面的U种情况不是我们想看到的Q你也可以想像一下用户在自己E序不用改动的情况下要不停的更新头文件和~译Ӟ他们心里会骂些什么。其实对用户来说Q他们只兛_cClxExp的接口DoSomething()Ҏ。那我们怎么才能只暴露类ClxExp的DoSomething()Ҏ而不又生上面所说的那些问题呢?{案是Q-接口与实现的分离。我可以让类ClxExp定义接口Q而把实现攑֜另外一个类里面。下面是具体的方法:<br /><br />  首先Q添加一个实现类ClxImplement来实现ClxExp的所有功能。注意:cClxImplement有着跟类ClxExp一L公有成员函数Q因Z们的接口要完全一致?br /><br />  lxImplement.h文g内容Q?br /><br /><table bordercolor="#cccccc" width="90%" align="center" bgcolor="#e3e3e3" border="1"><tbody><tr><td>#include "lxTest.h"<br /><br />class ClxImplement <br />{<br /> public:<br />  ClxImplement();<br />  virtual ~ClxImplement();<br /><br />  void DoSomething();<br /> <br /> private:<br />  ClxTest m_lxTest;<br />  void lxTest();<br />};</td></tr></tbody></table><br />  lxImplement.cpp文g内容Q?br /><br /><table bordercolor="#cccccc" width="90%" align="center" bgcolor="#e3e3e3" border="1"><tbody><tr><td>#include "lxImplement.h"<br /><br />ClxImplement::ClxImplement()<br />{}<br /><br />ClxImplement::~ClxImplement()<br />{}<br /><br />void ClxImplement::lxTest()<br />{<br /> m_lxTest.DoSomething();<br />}<br /><br />void ClxImplement::DoSomething()<br />{<br /> lxTest();<br />}</td></tr></tbody></table><br />  然后Q修改类ClxExp?br /><br />  修改后的lxExp.h文g内容Q?br /><br /><table bordercolor="#cccccc" width="90%" align="center" bgcolor="#e3e3e3" border="1"><tbody><tr><td>// 前置声明<br />class ClxImplement;<br /><br />class ClxExp <br />{<br /> public:<br />  ClxExp();<br />  virtual ~ClxExp();<br />  void DoSomething();<br /> private:<br />  // 声明一个类ClxImplement的指针,不需要知道类ClxImplement的定?br />  ClxImplement *m_pImpl;<br />};</td></tr></tbody></table><br />  修改后的lxExp.cpp文g内容Q?br /><br /><table bordercolor="#cccccc" width="90%" align="center" bgcolor="#e3e3e3" border="1"><tbody><tr><td>// 在这里包含类ClxImplement的定义头文g<br />#include "lxImplement.h"<br /><br />ClxExp::ClxExp()<br />{<br /> m_pImpl = new ClxImplement;<br />}<br /><br />ClxExp::~ClxExp()<br />{<br /> delete m_pImpl;<br />}<br /><br />void ClxExp::DoSomething()<br />{<br /> m_pImpl->DoSomething();<br />}</td></tr></tbody></table><br />  通过上面的方法就实现了类ClxExp的接口与实现的分R请注意两个文g中的注释。类ClxExp里面声明的只是接口而已Q而真正的实现l节被隐藏到了类ClxImplement里面。ؓ了能在类ClxExp中用类ClxImplement而不include头文件lxImplement.hQ就必须有前|声明class ClxImplementQ而且只能使用指向cClxImplement对象的指针,否则׃能通过~译?br /><br />  在发布库文g的时候,我们只需l用h供一个头文glxExp.hp了,不会暴露cClxExp的Q何实现细节。而且我们对类ClxTest的Q何改动,都不需要再l用h新头文gQ当Ӟ库文件是要更新的Q但是这U情况下用户也不用重新编译!Q。这样做q有一个好处就是,可以在分析阶D는pȝ分析员或者高U程序员来先把类的接口定义好Q甚臛_以把接口代码写好Q例如上面修改后的lxExp.h文g和lxExp.cpp文gQ,而把cȝ具体实现交给其他E序员开发?<img src ="http://www.shnenglu.com/zjj2816/aggbug/9419.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/zjj2816/" target="_blank">井泉</a> 2006-07-05 09:59 <a href="http://www.shnenglu.com/zjj2816/archive/2006/07/05/9419.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++ PrimerMW记http://www.shnenglu.com/zjj2816/archive/2006/06/29/9151.html井泉井泉Thu, 29 Jun 2006 07:11:00 GMThttp://www.shnenglu.com/zjj2816/archive/2006/06/29/9151.htmlhttp://www.shnenglu.com/zjj2816/comments/9151.htmlhttp://www.shnenglu.com/zjj2816/archive/2006/06/29/9151.html#Feedback0http://www.shnenglu.com/zjj2816/comments/commentRss/9151.htmlhttp://www.shnenglu.com/zjj2816/services/trackbacks/9151.html因ؓ刚学C++不久Q笔下难免有谬误之处Q行文更是凌乱;
所q怸是用来显配的东西Q发在linuxsir只是Z方便自己阅读记忆Q以防只上|忘了正事?br />书看了不C半,所以大U才写了一半,慢慢补充?br />=========================================


==========================================
转蝲务必注明原作?br />neplusultra 2005.2.3
==========================================


const要注意的问题
  1、下面是一个几乎所有h刚开始都会搞错的问题Q?br />已知Qtypedef char *cstring;
在以下声明中Qcstr的类型是什么?
extern const cstring cstr;

错误{案Qconst char *cstr;
正确{案Qchar *const cstr;

  错误在于typedef当作宏扩展。const 修饰cstr的类型。cstr是一个指针,因此Q这个定义声明了cstr是一个指向字W的const指针?br />  2、指针是constq是data为constQ?br />辨别Ҏ很简单,如下Q?br />
代码:
char *p="hello"; //non-const pointer, non-const data; const char *p="hello"; // non-const pointer, const data; char * const p="hello"; // const pointer , non-const data; const char * const p="hello"; // const pointer, const data;
  要注意的是,"hello"的类型是const char * Q按C++standard规则Qchar *p="hello" 是非法的(叛_的const char* 不能转换为左式的char *)Q违反了帔R性。但是这U行为在C中实在太频繁Q因此C++standard对于q种初始化动作给予豁免。尽如此,q是量避免q种用法?br />  3、const初始化的一些问?br />const 对象必须被初始化Q?br />
代码:
const int *pi=new int; // 错误Q没有初始化 const int *pi=new int(100); //正确 const int *pci=new const int[100]; //~译错误Q无法初始化用new表达式创建的内置cd数组元素?/div>

什么时候需要copy constructor,copy assignment operator,destructor
  注意Q若class需要三者之一Q那么它往往需要三者?br />当class的copy constructor内分配有一块指向hcap的内存,需要由destructor释放Q那么它也往往需要三者?br />
Z么需要protected 讉KU别
  有h认ؓQprotected讉KU别允许zcȝ接访问基cL员,q破坏了装的概念,因此所有基cȝ实现l节都应该是private的;另外一些h认ؓQ如果派生类不能直接讉K基类的成员,那么zcȝ实现无法有_的效率供用户使用Q如果没有protectedQ类的设计者将被迫把基cL员设|ؓpublic?br />  事实上,protected正是在高U度的封装与效率之间做出的一个良好折h案?br />
Z么需要virtual member function又不能滥用virtual
  若基c设计者把本应设计成virtual的成员函数设计成非virtualQ则l承cd无法实现改写(overridden)Q给l承cȝ实现带来不便Q?br />  另一斚wQ一旦成员函数被设计成virtualQ则该类的对象将额外增加虚拟指针QvptrQ和虚拟表格QvtblQ,所以倘若Z方便l承coverridden的目的而所有成员函数都为virtualQ可能会影响效率Q因为每个virtual成员函数都需付出动态分z成本。而且virtual成员函数不能内联QinlineQ,我们知道Q内联发生在~译时刻Q而虚拟函数在q行时刻才处理。对于那些小巧而被频繁调用、与cd无关的函敎ͼ昄不应该被讄成virtual?br />
关于引用的一些注意点
  1、把函数参数声明为数l的引用Q当函数参数是一个数l类型的引用Ӟ数组长度成ؓ参数和实参类型的一部分Q编译器查数l实参的长度和与在函数参数类型中指定的长度是否匹配?br />
代码:
//参数?0个int数组 void showarr(int (&arr)[10]); void func() { int i,j[2],k[10]; showarr(i); //错误Q实参必L10个int的数l? showarr(j); //错误Q实参必L10个int的数l? showarr(k); //正确Q? } //更灵zȝ实现Q借助函数模板。下面是一个显C数l内容的函数? template <typename Type , int size> void printarr(const Type (& r_array)[size]) { for(int i=0;i<size;i++) std::cout<< r_array[i] <<' '; std::cout << std::endl; } void caller() { int ar[5]={1,2,5,3,4}; //数组可以L大小? printarr(ar); //正确Q自动正调用printarr() }
  2?br />  3?br />
goto语句的一些要注意的地?/font>
  1、label语句只能用作goto的目标,且label语句只能用冒L束,且label语句后面不能紧接双括号'}'Q如
代码:
label8: }
  办法是在冒号后面加一个空语句Q一?;'卛_Q,?br />
代码:
label7: ;}
   2、goto语句不能向前跌如下声明语句Q?br />
代码:
goto label6; int x=1; //错误Q不能蟩q该声明Q? cout<<x<<endl; //使用x label6: //其他语句
但是Q把int x=1; 改ؓint x; 则正了。另外一U方法是Q?br />
代码:
goto label6; { int x=1; //正确Q用了语句? cout<<x<<endl; } label6: //其他语句
  3、goto语句可以向后Q向E序开头的方向Q蟩q声明定义语句?br />
代码:
begin: int i=22; cout<< i <<endl; goto begin; //非常y脚Q但它是正确?/div>

变量作用?/font>
  1、花括号可以用来指明局部作用域?br />  2、在for、if、switch、while语句的条?循环条g中可以声明变量,该变量仅在相应语句块内有效?br />  3、extern为声明但不定义一个对象提供了一U方法;它类g函数声明Q指明该对象会在其他地方被定义:或者在此文本的其他地方Q或者在E序的其他文本文件中。例如extern int i; 表示在其他地方存在声?int i;
  extern 声明不会引v内存分配Q他可以在同一个文件或同一个程序中出现多次。因此在全局作用域中Q以下语句是正确的:
代码:
extern int c; int c=1; //没错 extern int c; //没错
  但是Qextern声明若指定了一个显式初始值的全局对象Q将被视为对该对象的定义Q编译器ؓ其分配存储区Q对该对象的后箋定义出错。如下:
代码:
extern int i=1; int i=2; //出错Q重复定?/div>

auto_ptr若干注意?/font>
  1、auto_ptr的主要目的是支持普通指针类型相同的语法Qƈ为auto_ptr所指对象的释放提供自动理Q而且auto_ptr的安全性几乎不会带来额外的代hQ因为其操作支持都是内联的)。定义Ş式有三种Q?br />
代码:
auto_ptr<type_pointed_to>identifier(ptr_allocated_by_new); auto_ptr<type_pointed_to>identifier(auto_ptr_of_same_type); auto_ptr<type_pointed_to>identifier;
  2、所有权概念。auto_ptr_p1=auto_ptr_p2的后果是Qauto_ptr_p2丧失了其原指向对象的所有权Qƈ且auto_ptr_p2.get()==0。不要让两个auto_ptr对象拥有I闲存储区内同一对象的所有权。注意以下两U种初始化方式的区别Q?br />
代码:
auto_ptr<string>auto_ptr_str1(auto_ptr_str2.get()); //注意Q用str2指针初始化str1, 两者同时拥有所有权Q后果未定义? auto_ptr<string>auto_ptr_str1(auto_ptr_str2.release());//OKQstr2释放了所有权?

  3、不能用一个指向“内存不是通过应用new表达式分配的”指针来初始化或者赋值auto_ptr。如果这样做了,delete表达式会被应用在不是动态分配的指针上,q将D未定义的E序行ؓ?br />
C风格字符串结字符问题

代码:
char *str="hello world!"; //str末尾自动加上一个结字符Q但strlen不计该空字符? char *str2=new char[strlen(str)+1] // +1用来存放l尾I字W?/div>


定位new表达?/font>
  头文Ӟ<new>
  形式Qnew (place_address) type-specifier
  该语句可以允许程序员对象创建在已经分配好的内存中,允许E序员预分配大量的内存供以后通过q种形式的new表达式创建对象。其中place_address必须是一个指针。例如:
代码:
char *buf=new char[sizeof(myclass-type)*16]; myclass-type *pb=new (buf) myclass-type; //使用预分配空间来创徏对象 // ... delete [] buf; // 无须 delete pb?/div>


名字I间namespace

  1、namespace的定义可以是不连l的Q即namespace的定义是可以U篏的)Q即Q同一个namespace可以在不同的文g中定义,分散在不同文件中的同一个namespace中的内容彼此可见。这对生成一个库很有帮助Q可以我们更容易将库的源代码组l成接口和实现部分。如Q在头文Ӟ.h文gQ的名字I间部分定义库接口;在实现文Ӟ?c?cpp文gQ的名字I间部分定义库实现。名字空间定义可U篏的特性是“向用户隐藏实现l节”必需的,它允许把不同的实现文Ӟ?c?cpp文gQ编译链接到一个程序中Q而不会有~译错误和链接错误?br />  2、全局名字I间成员Q可以用?:member_name”的方式引用。当全局名字I间的成员被嵌套的局部域中声明的名字隐藏Ӟ可以采用这U方法引用全局名字I间成员?br />  3、名字空间成员可以被定义在名字空间之外。但是,只有包围该成员声明的名字I间Q也是该成员声明所在的名字I间及其外围名字I间Q才可以包含它的定义?br />  其要注意的?include语句的次序。假定名字空间成员mynamespace::member_i的声明在文gdec.h中,?include "dec.h"语句|于全局名字I间Q那么在include语句之后定义的其他名字空间内Qmynamespace::member_i的声明均可见。即Qmynamespace::member_i可以?include "dec.h"之后的Q何地方Q何名字空间内定义?br />  4、未命名的名字空间。我们可以用未命名的名字I间声明一个局部于某一文g的实体。未命名的名字空间可以namespace开_其后不需名字Q而用一对花括号包含名字I间声明块。如Q?br />
代码:
// 其他代码? namespace { void mesg() { cout<<"**********\n"; } } int main() { mesg(); //正确     //... return 0; }
  ׃未命名名字空间的成员是程序实体,所以mesg()可以在程序整个执行期间被调用。但是,未命名名字空间成员只在特定的文g中可见,在构成程序的其他文g中是不可以见的。未命名名字I间的成员与被声明ؓstatic的全局实体hcM的特性。在Q中Q被声明为static的全局实体在声明它的文件之外是不可见的?br />
using关键?/font>
  1、using声明与using指示W:前者是声明某名字空间内的一个成员,后者是使用整个名字I间。例如:
代码:
using cpp_primer::matrix; // ok,using声明 using namespace cpp_primer; //ok,using指示W?/div>
  2?该using指示W语句可以加在程序文件的几乎M地方Q包括文件开_#include语句之前Q、函数内部。不q用using指定的名字空间作用域Q生命周期)受using语句所在位|的生命周期U束。如Q函数内部用“using namespace myspacename;”则 myspacename仅在该函数内部可见?br />  3、可以用using语句指定多个名字I间Q得多个名字空间同时可见。但q增加了名字污染的可能性,而且只有?font color="blue">使用
各名字空间相同成员时由多个using指示W引L二义性错误才能被到Q这给E序的检、扩展、移植带来很大的隐患。因此,因该量使用using声明而不是滥用using指示W?br />
重蝲函数
  1、如果两个函数的参数表中参数的个数或者类型不同,则认两个函数是重载的?br />  如果两个函数的返回类型和参数表精匹配,则第二个声明被视为第一个的重复声明Q与参数名无兟뀂如 void print(string& str)与void print(string&)是一L?br />  如果两个函数的参数表相同Q但是返回类型不同,则第二个声明被视为第一个的错误重复声明Q会标记为编译错误?br />  如果在两个函数的参数表中Q只有缺省实参不同,则第二个声明被视为第一个的重复声明。如int max(int *ia,int sz)与int max(int *, int=10)?br />  参数名类型如果是由typedef提供的,q不作新类型,而应该当作typedef的原cd?br />  当参数类型是const或者volatileӞ分两U情况:对于实参按g递时Qconst、volatile修饰W可以忽略;对于把const、volatile应用在指针或者引用参数指向的cdӞconst、volatile修饰W对于重载函数的声明是有作用的。例如:
代码:
//OK,以下两个声明其实一? void func(int i); void func(const int i); //Error,无法通过~译Q因为func函数被定义了两次? void func(int i){} void func(const int i){} //OK,声明了不同的函数 void func2(int *); void func2(const int *); //OK,声明了不同的函数 void func3(int&); void func3(const int&);
  2、链接指C符extern "C"只能指定重蝲函数集中的一个函数。原因与内部名编码有养I在大多数~译器内部,每个函数明及其相兛_数表都被作ؓ一个惟一的内部名~码Q一般的做法是把参数的个数和cd都进行编码,然后其附在函数名后面。但是这U编码不使用于用链接指示Wextern "C"声明的函敎ͼq就是ؓ什么在重蝲函数集合中只有一个函数可以被声明为extern "C"的原因,h不同的参数表的两个extern "C"的函C被链接编辑器视ؓ同一函数。例如,包含以下两个声明的程序是非法的?br />
代码:
//error:一个重载函数集中有两个extern "C"函数 extern "C" void print(const char*); extern "C" void print(int);

函数模板
  1、定义函数模板:
代码:
template <typename/class identifier, ...> [inline/extern] ReturnType FunctionName(FuncParameters...) {   //definition of a funciton template... }


井泉 2006-06-29 15:11 发表评论
]]>
划分全局名字I间http://www.shnenglu.com/zjj2816/archive/2006/06/29/9150.html井泉井泉Thu, 29 Jun 2006 07:09:00 GMThttp://www.shnenglu.com/zjj2816/archive/2006/06/29/9150.htmlhttp://www.shnenglu.com/zjj2816/comments/9150.htmlhttp://www.shnenglu.com/zjj2816/archive/2006/06/29/9150.html#Feedback0http://www.shnenglu.com/zjj2816/comments/commentRss/9150.htmlhttp://www.shnenglu.com/zjj2816/services/trackbacks/9150.html  
 

条款28: 划分全局名字I间

全局I间最大的问题在于它本w仅有一个。在大的软g目中,l常会有不少人把他们定义的名字都攑֜q个单一的空间中Q从而不可避免地D名字冲突。例如,假设library1.h定义了一些常量,其中包括Q?/p>

const double lib_version = 1.204;

cM的,library2.h也定义了Q?/p>

const int lib_version = 3;

很显Ӟ如果某个E序惛_时包含library1.h和library2.h׃有问题。对于这c问题,你除了嘴里骂几句Q或l作者发报复性邮Ӟ或自q辑头文g来消除名字冲H外Q也没其它什么办法?/p>

但是Q作为程序员Q你可以力使自己写的程序库不给别h带来q些问题。例如,可以预先想一些不大可能造成冲突的某U前~Q加在每个全局W号前。当然得承认Q这L合v来的标识W看h不是那么令h舒服?/p>

另一个比较好的方法是使用c++ namespace。namespace本质上和使用前缀的方法一P只不q避免了别hL看到前缀而已。所以,不要q么做:

const double sdmbook_version = 2.0;      // 在这个程序库?
                                         // 每个W号?sdm"开?br />class sdmhandle { ... };                

sdmhandle& sdmgethandle();             // Z么函数要q样声明Q?br />                                       // 参见条款47

而要q么做:

namespace sdm {
  const double book_version = 2.0;
  class handle { ... };
  handle& gethandle();
}

用户于是可以通过三种Ҏ来访问这一名字I间里的W号Q将名字I间中的所有符号全部引入到某一用户I间Q将部分W号引入到某一用户I间Q或通过修饰W显式地一ơ性用某个符P

void f1()
{
  using namespace sdm;           // 使得sdm中的所有符号不用加
                                 // 修饰W就可以使用

  cout << book_version;          // 解释为sdm::book_version
  ...

  handle h = gethandle();        // handle解释为sdm::handle,
                                 // gethandle解释为sdm::gethandle
  ...                           

}

void f2()
{
  using sdm::book_version;        // 使得仅book_version不用?br />                                 // 修饰W就可以使用

  cout << book_version;           // 解释?br />                                  // sdm::book_version
  ...

  handle h = gethandle();         // 错误! handle和gethandle
                                  // 都没有引入到本空?br />  ...                            

}

void f3()
{
  cout << sdm::book_version;      // 使得book_version
                                  // 在本语句有效
  ...                            

  double d = book_version;        // 错误! book_version
                                  // 不在本空?/p>

  handle h = gethandle();         // 错误! handle和gethandle
                                  // 都没有引入到本空?br />  ...                           

}

Q有些名字空间没有名字。这U没命名的名字空间一般用于限制名字空间内部元素的可见性。详见条ƾm31。)

名字I间带来的最大的好处之一在于Q潜在的二义不会造成错误Q参见条?6Q。所以,从多个不同的名字I间引入同一个符号名不会造成冲突Q假如确实真的从不用这个符L话)。例如,除了名字I间sdm外,假如q要用到下面q个名字I间Q?/p>

namespace acmewindowsystem {

  ...

  typedef int handle;

  ...

}

只要不引用符号handleQ用sdm和acmewindowsystem时就不会有冲H。假如真的要引用Q可以明地指明是哪个名字空间的handleQ?/p>

void f()
{
  using namespace sdm;                 // 引入sdm里的所有符?br />  using namespace acmewindowsystem;    // 引入acme里的所有符?/p>

  ...                                  // 自由地引用sdm
                                       // 和acme里除handle之外
                                       // 的其它符?/p>

  handle h;                            // 错误! 哪个handle?

  sdm::handle h1;                      // 正确, 没有二义

  acmewindowsystem::handle h2;         // 也没有二?/p>

  ...

}

假如用常规的Z头文件的Ҏ来做Q只是简单地包含sdm.h和acme.hQ这L话,׃handle有多个定义,~译不能通过?/p>

名字I间的概念加入到c++标准的时间相对较晚,所以有些h会认为它不太重要Q可有可无。但q种x是错误的Q因为c++标准库(参见条款49Q里几乎所有的东西都存在于名字I间std之中。这可能令你不以为然Q但它却以一U直接的方式影响CQ这是Z么c++提供了那些看h很有的、没有扩展名的头文gQ如<iostream>, <string>{。详l介l参见条?9?/p>

׃名字I间的概念引入的旉相对较晚Q有些编译器可能不支持。就是q样Q那也没理由污染全局名字I间Q因为可以用struct来近似实现namespace。可以这样做Q先创徏一个结构用以保存全局W号名,然后这些全局W号名作为静态成员放入结构中Q?/p>

// 用于模拟名字I间的一个结构的定义
struct sdm {
  static const double book_version;
  class handle { ... };
  static handle& gethandle();
};

const double sdm::book_version = 2.0;      // 静态成员的定义

现在Q如果有人想讉Kq些全局W号名,只用单地在它们前面加上结构名作ؓ前缀Q?/p>

void f()
{
  cout << sdm::book_version;

  ...

  sdm::handle h = sdm::gethandle();

  ...
}

但是Q如果全局范围内实际上没有名字冲突Q用户就会觉得加修饰W麻烦而多余。幸q的是,q是有办法来让用户选择使用它们或忽略它们?/p>

对于cd名,可以用类型定义(typedefQ来昑ּ地去掉空间引用。例如,假设l构sQ模拟的名字I间Q内有个cd名tQ可以这Ltypedef来得t成ؓs::t的同义词Q?/p>

typedef sdm::handle handle;

对于l构中的每个Q静态)对象xQ可以提供一个(全局Q引用xQƈ初始化ؓs::xQ?/p>

const double& book_version = sdm::book_version;

老实_如果M条款47Q你׃不喜Ƣ定义一个象book_versionq样的非局部静态对象。(你就会用条款47中所介绍的函数来取代q样的对象)

处理函数的方法和处理对象一P但要注意Q即使定义函数的引用是合法的Q但代码的维护者会更喜Ƣ你使用函数指针Q?/p>

sdm::handle& (* const gethandle)() =      // gethandle是指向sdm::gethandle
  sdm::gethandle;                         // 的const 指针 (见条?1)

注意gethandle是一个常指针。因Z当然不想让你的用户将它指向别的什么东西,而不是sdm::gethandleQ对不对Q?/p>

Q如果真想知道怎么定义一个函数的引用Q看看下面:

sdm::handle& (&gethandle)() =      // gethandle是指?br />  sdm::gethandle;                  // sdm::gethandle的引?/p>

我个L做法也很好,但你可能以前从没见到q。除了初始化的方式外Q函数的引用和函数的常指针在行ؓ上完全相同,只是函数指针更易于理解。)

有了上面的类型定义和引用Q那些不会遭遇全局名字冲突的用户就会用没有修饰符的类型和对象名;相反Q那些有全局名字冲突的用户就会忽略类型和引用的定义,代之以带修饰W的W号名。还要注意的是,不是所有用户都想用这U简写名Q所以要把类型定义和引用攑֜一个单独的头文件中Q不要把它和Q模拟namespace的)l构的定义؜在一赗?/p>

struct是namespace的很好的q似Q但实际上还是相差很q。它在很多方面很Ơ缺Q其中很明显的一Ҏ对运符的处理。如果运符被定义ؓl构的静态成员,它就只能通过函数调用来用,而不能象常规的运符所设计的那P可以通过自然的中~语法来用:

// 定义一个模拟名字空间的l构Q结构内部包含widgets的类?br />// 和函数。widgets对象支持operator+q行加法q算
struct widgets {
  class widget { ... };


  // 参见条款21Qؓ什么返回const
  static const widget operator+(const widget& lhs,
                                const widget& rhs);

  ...

};

// Z面所q的widge和operator+
// 建立全局Q无修饰W的Q名U?/p>

typedef widgets::widget widget;


const widget (* const operator+)(const widget&,        // 错误!
                                 const widget&);       // operator+不能是指针名
 

widget w1, w2, sum;

sum = w1 + w2;                           // 错误! 本空间没有声?br />                                         // 参数为widgets 的operator+

sum = widgets::operator+(w1, w2);        // 合法, 但不?br />                                         // "自然"的语?/p>

正因些限Ӟ所以一旦编译器支持Q就要尽早用真正的名字I间?/p>

井泉 2006-06-29 15:09 发表评论
]]>
avԾþþþa| þþƷа| ˾Ʒþһav | þþþùƷ| þþƷþ˼˼| þþƷվ| ˾þô߽ۺ5g| ھƷþþþþþ97ţţ | 㽶þҹɫƷ2020| 99þþƷһ| ھƷþþþþ鶹 | ۲ӰԺþ99| þˬһ | ޾ƷƷþ99һ| ˾þۺ| ޹Ʒþ| Ʒþþþ| þþƷ77777| þþ뾫Ʒպý| þŮվ| պƷþþþþ| һɫۺϾþ| þþƷѹƬС| ձǿƬþþþþAAA| ھƷ˾þþӰԺ| þþƷƷ| wwwɫ˾þþƷ| ƷѾþþþþþ| һһþۺϺݺ| ҹƷþþþþӰriav| þøһëƬ| Ѹþ| ɫۺϾþþþ| ھƷŷþþƷ| ĻhdþþƷ| ƷȾþëƬ| þþƷŷƬ| þ| AëƬþþƷ| ҹþþþ| AV12þ|