JAVA教程之COM组件计划与使用(四)复杂挪用组件仓酷云
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(longn1,longn2,long*pnSum);//IDL文件(注2)STDMETHOD(Add)(/**/longn1,/**/longn2,/**/long*pnSum);//.h文件假如参数是静态分派的内存指针,那末恪守以下的划定:
偏向请求人开释人提醒挪用者挪用者组件吸收指针后,不克不及从头分派内存组件挪用者组件前往指针后,挪用者“爱咋咋地”(注3)挪用者挪用者组件能够从头分派内存
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={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;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;::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开发的程序以上是我的愚见,其实不管那种语言,你学好了,都能找到好的工作, Sun公司看见Oak在互联网上应用的前景,于是改造了Oak,于1995年5月以Java的名称正式发布。Java伴随着互联网的迅猛发展而发展,逐渐成为重要的网络编程语言。 Java 编程语言的风格十分接近C、C++语言。 是一种语言,用以产生「小应用程序(Applet(s)) 如果你学过HTML,那么事情要好办的多,如果没有,那你快去补一补HTML基础吧。其实JSP中的Java语法也不多,它更象一个脚本语言,有点象ASP。 自从Sun推出Java以来,就力图使之无所不包,所以Java发展到现在,按应用来分主要分为三大块:J2SE,J2ME和J2EE,这也就是Sun ONE(Open Net Environment)体系。J2SE就是Java2的标准版,主要用于桌面应用软件的编程;J2ME主要应用于嵌入是系统开发,如手机和PDA的编程;J2EE是Java2的企业版,主要用于分布式的网络程序的开发,如电子商务网站和ERP系统。 有时间再研究一下MVC结构(把Model-View-Control分离开的设计思想) 设计模式是高级程序员真正掌握面向对象核心思想的必修课。设计模式并不是一种具体"技术",它讲述的是思想,它不仅仅展示了接口或抽象类在实际案例中的灵活应用和智慧 那么我书也看了,程序也做了,别人问我的问题我都能解决了,是不是就成为高手了呢?当然没那么简单,这只是万里长征走完了第一步。不信?那你出去接一个项目,你知道怎么下手吗,你知道怎么设计吗,你知道怎么组织人员进行开发吗?你现在脑子里除了一些散乱的代码之外,可能再没有别的东西了吧! 其实说这种话的人就如当年小日本号称“三个月拿下中国”一样大言不惭。不是Tomjava泼你冷水,你现在只是学到了Java的骨架,却还没有学到Java的精髓。接下来你得研究设计模式了。 所以现在应用最广泛又最好学的就是J2EE了。 J2EE又包括许多组件,如Jsp,Servlet,JavaBean,EJB,JDBC,JavaMail等。要学习起来可不是一两天的事。那么又该如何学习J2EE呢?当然Java语法得先看一看的,I/O包,Util包,Lang包你都熟悉了吗?然后再从JSP学起。 一直感觉JAVA很大,很杂,找不到学习方向,前两天在网上找到了这篇文章,感觉不错,给没有方向的我指了一个方向,先不管对不对,做下来再说。 Java自面世后就非常流行,发展迅速,对C++语言形成了有力冲击。Java 技术具有卓越的通用性、高效性、平台移植性和安全性,广泛应用于个人PC、数据中心、游戏控制台 Sun公司看见Oak在互联网上应用的前景,于是改造了Oak,于1995年5月以Java的名称正式发布。Java伴随着互联网的迅猛发展而发展,逐渐成为重要的网络编程语言。 你可以去承接一些项目做了,一开始可能有些困难,可是你有技术积累,又考虑周全,接下项目来可以迅速作完,相信大家以后都会来找你的,所以Money就哗啦啦的。。。。。。 让你能够真正掌握接口或抽象类的应用,从而在原来的Java语言基础上跃进一步,更重要的是,设计模式反复向你强调一个宗旨:要让你的程序尽可能的可重用。 设计模式是高级程序员真正掌握面向对象核心思想的必修课。设计模式并不是一种具体"技术",它讲述的是思想,它不仅仅展示了接口或抽象类在实际案例中的灵活应用和智慧 当然你也可以参加一些开源项目,一方面可以提高自己,另一方面也是为中国软件事业做贡献嘛!开发者在互联网上用CVS合作开发,用QQ,MSN,E-mail讨论联系,天南海北的程序员分散在各地却同时开发同一个软件,是不是很有意思呢? 所以现在应用最广泛又最好学的就是J2EE了。 J2EE又包括许多组件,如Jsp,Servlet,JavaBean,EJB,JDBC,JavaMail等。要学习起来可不是一两天的事。那么又该如何学习J2EE呢?当然Java语法得先看一看的,I/O包,Util包,Lang包你都熟悉了吗?然后再从JSP学起。 任职于太阳微系统的詹姆斯·高斯林等人于1990年代初开发Java语言的雏形,最初被命名为Oak,目标设置在家用电器等小型系统的程序语言
页:
[1]