|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
net网页编程程序员的大部门代码都靠控件拖拽完成的,虽然java也有,但是无论从美观和速度上都没发和.net网页编程比。java程序员都是代码完成的,所以java程序员常戏称.net网页编程程序员是操作员,呵呵。1、媒介
同道们、伴侣们、列位向导,人人好。
VCKBASE不得了, 网友浩瀚文章好。 组件计划怎样学? 常识库里闷头找! 摘自---杨先生打油集录
在VCKBASE的顶力撑持下,在列位网友回帖的勉励下,我才干顺遂完成系列论文的前三回。书到本回,我们终究入手下手写代码啦。写点啥那?恩,有了!我们先从怎样挪用现成的复杂的组件入手下手吧,同时也特地先容一些相干的常识。
2、组件的启动和开释
在第三回中,人人用“小本本”纪录了一个准绳:COM组件是运转在散布式情况中的。因而,怎样启动组件立即就碰到了严峻的成绩,人人看这段代码:- p=new对象;p->对象函数();deletep;
复制代码 如许的代码再熟习不外了,在当地历程中运转是不会有成绩的。可是你想一想,假如这个对象是在“地球另外一边”的盘算机上,了局会怎样?嘿嘿,C++在计划new的时分,可没有思索远程的完成呀(盘算机言语固然不会,也没需要往计划)。因而启动组件、挪用接口的功效,固然就由COM体系来完成了。
<br>
图一 组件挪用机制
由上图能够看出,当挪用组件的时分,实际上是依托代办署理(运转在当地)和存根(运转在远端)之间的通信完成的。详细来讲,当客户程序经由过程CoCreateInstance()函数启动组件,则代办署理接受该挪用,它和存根通信,存根则它地点的当地(相对客户程序来讲就是远程了)实行new操纵加载对象。关于初学者,你能够不必理它,代办署理和存根对我们来讲是通明的。只需约莫晓得是怎样一回事就统统OK了。
成绩又来了,这个远程的对象甚么时分没落呢?在第二回先容接口观点的时分,事先我们特地疏忽了两个函数,就是IUnknown::AddRef()和IUnknown::Release(),从函数名就可以猜到了,一个是对外部援用记数器(Ref)加1,一个是开释(减1),当记数器减为0的时分,就是开释的时机啦。看起来很庞大,没举措,由于这是在先容道理。实在在我们写程序的时分到对照复杂,请人人恪守几个准绳:
1、启动组件失掉一个接口指针(Interface)后,不要挪用AddRef()。由于体系晓得你失掉了一个指针,以是它已帮你挪用了AddRef()函数;
2、经由过程QueryInterface()失掉另外一个接口指针后,不要挪用AddRef()。由于......和下面的事理一样;
3、当你把接口指针赋值给(保留到)另外一个变量中的时分,请挪用AddRef();
4、当不必要再利用接口指针的时分,务必实行Release()开释;
5、当利用智能指针的时分,能够省略指针的保护事情;(注1)
3、内存分派和开释
自从进修了C言语,先生就教训我们说:关于静态内存的请求和开释,必定要恪守“谁请求,谁开释”的准绳。在此准绳的引导下,不但是我、不但是你,就连特级大家都计划了如许怪怪的函数:
函数申明批评GetWindowText(HWND,LPTSTR,int)获得窗口题目。必要在参数中给出保留题目所利用的内存指针,和这块内存的尺寸。晕!我又不晓得窗口题目的长度,竟然还要我供应尺寸?!没举措,只能估摸着给一个年夜一些的尺寸吧。sprintf(char*,constchar*,...)格局化一个字符串。这个函数不必给出缓冲区的长度啦。恩,固然不必给出长度了,但你敢给个小尺寸吗?哼!intCListBox::GetTextLen(int)
CListBox::GetText(int,LPTSTR)获得列表窗中子项目标题目。必要挪用两个函数,先获得长度,然后分派内存,再实践获得题目内容。真烦!
说其实的,不仅函数挪用者感到别扭,就连函数计划者心境也不会爽的,而这统统都是为了满意所谓“谁请求,谁开释”的准绳。办理这个成绩最好的体例就是:函数外部依据实践必要静态请求内存,而挪用者卖力开释。这固然违反了上述准绳,但COM从便利性和效力动身,的确是这么计划的。
C言语C++言语Windows平台COMIMalloc接口BSTR请求malloc()newGlobalAlloc()CoTaskMemAlloc()Alloc()SysAllocString()从头请求realloc() GlobalReAlloc()CoTaskRealloc()Realloc()SysReAllocString()开释free()deleteGlobalFree()CoTaskMemFree()Free()SysFreeString()
以上这些函数必需要按范例共同利用(好比:new请求的内存,则必需用delete开释)。在COM外部,固然你能够任意利用任何范例的内存分派开释函数,但组件假如必要与客户举行内存的交互,则必需利用上表中的后三类函数族。
1、BSTR内存在上回书中,已有对照丰厚的先容了,不再反复;
2、CoTaskXXX()函数族,其实质上就是挪用C言语的函数(malloc...);
3、IMalloc接口又是对CoTaskXXX()函数族的一个包装。包装后,同时加强了一些功效,好比:IMalloc::GetSize()能够获得尺寸,利用IMallocSpy能够监督内存的利用;
4、参数传送偏向
在C言语的函数声明中,特别当参数为指针的时分,你是看不出它传送偏向的。好比:
voidfun(char*p1,int*p2);叨教,p1、p2哪一个是进参?哪一个是出参?甚或都是进参或都是出参?因为牵涉到内存分派和开释等成绩,COM必要明白标注参数偏向。今后我们写程序,就相似上面的模样:- HRESULTAdd([in]longn1,[in]longn2,[out]long*pnSum);//IDL文件(注2)STDMETHOD(Add)(/*[in]*/longn1,/*[in]*/longn2,/*[out]*/long*pnSum);//.h文件
复制代码 假如参数是静态分派的内存指针,那末恪守以下的划定:
偏向请求人开释人提醒[in]挪用者挪用者组件吸收指针后,不克不及从头分派内存[out]组件挪用者组件前往指针后,挪用者“爱咋咋地”(注3)[in,out]挪用者挪用者组件能够从头分派内存
5、示例程序
示例1、由CLSID失掉ProgID。(程序以word为例子。假如运转不准确,嘿嘿,你没有安装word吧?)- ::CoInitialize(NULL);HRESULThr;//{000209FF-0000-0000-C000-000000000046}=word.application.9CLSIDclsid={0x209ff,0,0,{0xc0,0,0,0,0,0,0,0x46}};LPOLESTRlpwProgID=NULL;hr=::ProgIDFromCLSID(clsid,&lpwProgID);if(SUCCEEDED(hr)){::MessageBoxW(NULL,lpwProgID,L"ProgID",MB_OK);IMalloc*pMalloc=NULL;hr=::CoGetMalloc(1,&pMalloc);//获得IMallocif(SUCCEEDED(hr)){pMalloc->Free(lpwProgID);//开释ProgID内存pMalloc->Release();//开释IMalloc}}::CoUninitialize();
复制代码 示例2、怎样利用“扫瞄文件夹”选择对话窗。- CStringBrowseFolder(HWNDhWnd,LPCTSTRlpTitle){//挪用SHBrowseForFolder获得目次(文件夹)称号//参数hWnd:父窗口句柄//参数lpTitle:窗口题目charszPath[MAX_PATH]={0};BROWSEINFOm_bi;m_bi.ulFlags=BIF_RETURNONLYFSDIRS|BIF_STATUSTEXT;m_bi.hwndOwner=hWnd;m_bi.pidlRoot=NULL;m_bi.lpszTitle=lpTitle;m_bi.lpfn=NULL;m_bi.lParam=NULL;m_bi.pszDisplayName=szPath;LPITEMIDLISTpidl=::SHBrowseForFolder(&m_bi);if(pidl){if(!::SHGetPathFromIDList(pidl,szPath))szPath[0]=0;IMalloc*pMalloc=NULL;if(SUCCEEDED(::SHGetMalloc(&pMalloc)))//获得IMalloc分派器接口{pMalloc->Free(pidl);//开释内存pMalloc->Release();//开释接口}}returnszPath;}
复制代码 示例3、在窗口中显现一幅JPG图像。- voidCxxxView::OnDraw(CDC*pDC){::CoInitialize(NULL);//COM初始化HRESULThr;CFilefile;file.Open("c:aa.jpg",CFile::modeRead|CFile::shareDenyNone);//读进文件内容DWORDdwSize=file.GetLength();HGLOBALhMem=::GlobalAlloc(GMEM_MOVEABLE,dwSize);LPVOIDlpBuf=::GlobalLock(hMem);file.ReadHuge(lpBuf,dwSize);file.Close();::GlobalUnlock(hMem);IStream*pStream=NULL;IPicture*pPicture=NULL;//由HGLOBAL失掉IStream,参数TRUE暗示开释IStream的同时,开释内存hr=::CreateStreamOnHGlobal(hMem,TRUE,&pStream);ASSERT(SUCCEEDED(hr));hr=::OleLoadPicture(pStream,dwSize,TRUE,IID_IPicture,(LPVOID*)&pPicture);ASSERT(hr==S_OK);longnWidth,nHeight;//宽高,MM_HIMETRIC形式,单元是0.01毫米pPicture->get_Width(&nWidth);//宽pPicture->get_Height(&nHeight);//高////////原年夜显现//////CSizesz(nWidth,nHeight);pDC->HIMETRICtoDP(&sz);//转换MM_HIMETRIC形式单元为MM_TEXT像素单元pPicture->Render(pDC->m_hDC,0,0,sz.cx,sz.cy,0,nHeight,nWidth,-nHeight,NULL);////////按窗口尺寸显现////////// CRectrect; GetClientRect(&rect);// pPicture->Render(pDC->m_hDC,0,0,rect.Width(),rect.Height(),//0,nHeight,nWidth,-nHeight,NULL);if(pPicture)pPicture->Release();//开释IPicture指针if(pStream)pStream->Release();//开释IStream指针,同时开释了hMem::CoUninitialize();}
复制代码 示例4、在桌面创建快速体例
在浏览代码之前,先看一下关于“快速体例”组件的布局表示图。
<br>
、快速体例组件的接口布局表示图
从布局图中能够看出,“快速体例”组件(CLSID_ShellLink),有3个(实在不止)接口,每一个接口完成一组相干功效的函数。IShellLink接口(IID_IShellLink)供应快速体例的参数读写功效(见图三),IPersistFile接口(IID_IPersistFile)供应快速体例延续性文件的读写功效。对象的延续性(注5),是一个十分经常使用,而且功效壮大的接口家属。但明天,我们只需懂得个中两函数,就能够了:IPersistFile::Save()和IPersistFile:Load()。(注6)
<br>
、快速体例中的各类属性- #include<atlconv.h>voidCreateShortcut(LPCTSTRlpszExe,LPCTSTRlpszLnk){//创建块捷体例//参数lpszExe:EXE文件全路径名//参数lpszLnk:快速体例文件全路径名::CoInitialize(NULL);IShellLink*psl=NULL;IPersistFile*ppf=NULL;HRESULThr=::CoCreateInstance(//启动组件CLSID_ShellLink,//快速体例CLSIDNULL,//聚适用(注4)CLSCTX_INPROC_SERVER,//历程内(Shell32.dll)服务IID_IShellLink,//IShellLink的IID(LPVOID*)&psl);//失掉接口指针if(SUCCEEDED(hr)){psl->SetPath(lpszExe);//全路径程序名//psl->SetArguments();//命令行参数//psl->SetDescription();//备注//psl->SetHotkey();//快速键//psl->SetIconLocation();//图标//psl->SetShowCmd();//窗口尺寸//依据EXE的文件名,失掉目次名TCHARszWorkPath[MAX_PATH];::lstrcpy(szWorkPath,lpszExe);LPTSTRlp=szWorkPath;while(*lp)lp++;while(""""!=*lp)lp--;*lp=0;//设置EXE程序的默许事情目次psl->SetWorkingDirectory(szWorkPath);hr=psl->QueryInterface(//查找延续性文件接口指针IID_IPersistFile,//延续性接口IID(LPVOID*)&ppf);//失掉接口指针if(SUCCEEDED(hr)){USES_CONVERSION;//转换为UNICODE字符串ppf->Save(T2COLE(lpszLnk),TRUE);//保留}}if(ppf) ppf->Release();if(psl) psl->Release();::CoUninitialize();}voidOnXXX(){CreateShortcut(_T("c:winnt
- otepad.exe"),//记事本程序。注重,你的体系是不是也是这个目次?_T("c:DocumentsandSettingsAdministrator桌面我的记事本.lnk"));//桌面上创建快速体例(lnk)文件的全路径名。注重,你的体系是不是也是这个目次?//假如用程序完成寻觅桌面的路径,则能够查注册表//HKEY_CURRENT_USERSoftwareMicrosoftWindowsCurrentVersionExplorerShellFolders}
复制代码
7、小结
本回先容的内容对照有用。人人不要只剽窃代码,而必定要了解它。分离MSDN的申明往思考代码、了解其寄义。好了,千方百计把代码忘记!三天后(如过你还没有健忘,那就再过三天),你在不参考示例代码,但能够任意翻阅MSDN的情形下,本人能自力地再次完成这四个例程,那末祝贺你,你已进门了:0)从下回入手下手,我们要用ATL做COM的开辟事情啦,您白叟家筹办好了吗?
功课,留功课啦......
1、你已学会怎样创建快速体例了,那末你晓得怎样读取它的属性吗?(假如写不出这个程序,那末你就不必持续进修了。由于......动点头脑呀!我还没有见过象你这么笨的先生呢!)
2、示例程序三中利用了IPicture接口显现一个JPG图像。那末你如今往完成一个功效,把JPG文件转换为BMP文件。
注1:智能指针的观点和用法,后续先容。
注2:IDL文件,下回就要先容啦。
注3:西南话,想干甚么都能够,归正我不论啦。
注4:聚合,大概在第30回中先容吧:-)
注5:延续性,IPersistXXXXXX是一个十分壮大的接口家属,后续先容。
注6:想晓得IShellLink、IPersistFile接口的一切函数吗?别愣着,快往看MSDN呀......
原文链接:http://www.vckbase.com/document/viewdoc/?id=1493
C#是不行的,比如说美国的航天飞船里就有java开发的程序以上是我的愚见,其实不管那种语言,你学好了,都能找到好的工作, |
|