Understanding Strings In COM
2000-12-30 02:22
453 查看
UnderstandingStringsInCOM
BySystemNotes |
Toreplicatethestepsdescribedinthisarticle,you'llneedWindows95+orWindowsNT4.0+andVisualC++5.0orhigher. |
Strings,i.e.vectorsofalphanumericcharacters,areandhavealwaysbeenafundamentaldatatypeineveryprogramminglanguageandplatform.Whereasthecomputeritselfpreferstodealwithnumbers,humanbeingsprefermessagesoftexttosequencesofbinary,hexadecimalorevendecimaldigits.Thisimpliesthatwheneverapieceofsoftwareneedstointeractwiththeuser(orsignalsomenotableevents)somekindofstringtreatmentislikelytocomeintoplay.
Untilafewyearsagostringswerejuststrings,thatis,arraysofsingle-bytedatatypes(charinC/C++)containingtheASCIInumberofthecharacterateachelement.Thebiggestproblemwasdistinguishingzero-terminatedstrings(alsoknownasASCIIZ)fromnon-zero-terminatedarrays.ThencameUnicode,anewcharactersetwhichextendedthesizeofeachcharacterfrom8to16bits,thusallowingfor65536theoreticaldifferentcharacters,enoughtocontainalsoFarEasternsymbolssuchastheKanjistandardset.InC/C++abrandnewstandarddatatypewasdefinedtostoreUnicodestrings,wchar_t,andconsequentlytheAPIsofUnicode-awareWin32operatingsystemsthattookstringsasparametershadtobeduplicatedtoacceptbothANSIandUnicodeversions.
JustastheWindowsprogrammercommunitybegantogetacquaintedwiththisduplicationandgotintothehabitofnotassuminganythingaboutthelengthofacharacterapriori,COMjumpedtothecentralstagewithitsburdenofnewtypesandaliases.IfyouarewonderingwhatisthefunctionaldifferencebetweenanarrayofOLECHARsandapointertoaBSTR,whenandhowitisnecessarytoconvertastringtoanothertype,andwhatdegreeofassistanceATLandMFCoffertothedeveloper,thisarticleisforyou.
OLECHARs
ThemainstringdatatypeinCOMisnamedOLECHAR,whichisthekindofvariableexpectedbyalmostallCOMlibraryfunctionsandwell-educatedinterfaces'methods.AnOLECHARrepresentsasingleOLE-compatiblecharacter,thereforeyoucanspeakofastringonlywhenyouhaveanarrayofOLECHARs.ItisobvioustoeveryonewhohasutilizedC++forsometimethatthereisnotanOLECHARbuilt-indatatypeinthelanguage,asunderlined(amongotherthings)bytheuppercaseofthename.TheCandC++standardspecificationsdictatetheexistenceofonlytwocharactertypes:charandwchar_t.Hence,OLECHARmustbeanaliastooneofthem,andinfactitis.ItsrelationisestablishedbythestandardWin32headerfilewtypes.h,whichwewillmeetagainlaterinthisarticle.Thefollowingcodesnippet,adaptedfromtheheaderfileforclarity,representstheofficialdefinitionofOLECHARinC/C++:
#ifdefined(_WIN32)&&!defined(OLE2ANSI) typedefWCHAROLECHAR; #else typedefcharOLECHAR; #endif |
#ifdefined(_WIN32)&&!defined(OLE2ANSI) typedefOLECHAR__RPC_FAR*LPOLESTR; typedefconstOLECHAR__RPC_FAR*LPCOLESTR; #else typedefLPSTRLPOLESTR; typedefLPCSTRLPCOLESTR; #endif |
Asyoucansee,theBSTRtypedoesnotmaptothesameactualbuilt-intypeoneveryplatform.Ifthecodeiscompiledon32-bitWindows,whichcanbedetectedfromthe_WIN32preprocessorsymboldefinition,allCOMcharactersareUnicodestring(WCHARisitselfatypedef'eddatatypethattranslatestothebuilt-inwchar_ttype).Ifnot,thenthebuildcommandisprobablytargetingWindows3.1x,whichdoesnotsupportUnicodestringsatall,soallthestringsareregularoldarraysofchar.NotethatonSunSolaris,themainUNIXflavortobenefitfromaportingofthe(D)COMimplementationtodate,OLECHARsare16-bitUnicodecharactersexactlyasonWin32.
TheoriginalMicrosoftengineerswhodesignedCOMmadeaprettycourageousdecision:TheydefactoimposedUnicodetoeveryoneinthe32-bitworldatatimewhentheoriginalversionofWindowsNTwasbarelytakingshapeandthedoubledamountofRAMrequiredtoholdthesamestringscouldeasilybecomeproblematicduetothehighcostofmemory.Butthedecisionprovedadvantageous,asitsavedCOMdevelopersfromhavingtoimplementtwovariantsofeachinterface(andrelativecoclassesimplementingit)justtodealwitheverypossibletypeofclient.
NowwehaveseenhowtodefineaCOM-compliantcharacterandbyextensionaCOM-compliantstring,butwehavenotrevealedyethowonecaninitializesuchastringwithastringliteral.Thefollowingstatement:
constOLECHAR*pComStr; pComStr="IloveVCDJandCOM"; |
constOLECHAR*pComStr; pComStr=L"IloveVCDJandCOM"; |
constOLECHAR*pComStr; pComStr=OLESTR("IloveVCDJandCOM"); |
#ifdefined(_WIN32)&&!defined(OLE2ANSI) #defineOLESTR(str)L##str #else #defineOLESTR(str)str #endif |
Note:InallotherWin32APIimplementationsthereisadiscrepancybetweenWindows95/Windows98andWindowsNT'sstringtreatment,sincetheformeremploysone-byteANSIcharactersandthelatterinternallyworksonlywithtwo-byteUnicodecharacters.However,whenitcomestoCOM,bothoperatingsystemsagreeontheuseofUnicodestrings. |
OLECHARsarethestandardwaytocreatestringsinCOMcodeandbyfarthemostcomfortableaslongasCandC++areusedinboththeclientsideandtheserverside.Otherlanguagesandtoolsbringtheirburdenofspecialconstraintsthatopenthewaytoanotherkindofstring,whichconstitutethetopicofthenextparagraph.
Copyright©1999-VisualC++DevelopersJournal |
B-strings,moreproperlycalledBasicstrings,areaspecialkindofstringformat.InsteadofcomprisingaclassicarrayofcharactersfollowedbyaNULcharacter(code/0)thatmarkstheterminationofthearray,thestructureofthedatainmemoryisasupersetofOLECHAR.Inshort,aBSTRisanull-terminatedarrayofOLECHARsprefixedbyitslength.Thestringlengthisdeterminedbythecharactercount,notbytheindexofthefirstnullcharacter.
Thispresenceofthelengthoftheobjectbeforetheactualarraydatarendersthesestringssuitableformanipulationinhigh-leveltoolslikeVisualBasic(forwhichthisstringformatwasinventedinthefirstplace)andJavaonaCOM-awarevirtualmachinelikeMicrosoft'sJVM.Actually,thereisnootherwaytoexchangestring-likedatawithcomponentswritteninthoselanguagesthantoemployBSTRs.WhileinCandC++thedeveloperhastounderstandandusethedatatypeinaratheruncomfortablemanner,bothVisualBasicandJavaencapsulatethemintotheirtraditionalstringtypes,respectivelyStringandjava.lang.String.Thefinaldeveloperisthereforeshieldedfromthesubtletiesoftheorganizationoftherawbytesinmemory.Moreover,thetoolstakecareofallocatingandfreeingthememoryrequiredtocontaintheircontentwithouttheprogrammerneedingtoknowhowthisprocessworksbehindthescenes.
Thisisthebrilliantsideofthemedalofcourse.YouastheC/C++hardcoreengineergetthetoughpartofthework,sinceyouneedtolearnacompletelynewspecificsetofAPIsthatcarryoutthebasicoperationswithBasicstrings.Thefamilyoffunctionsisamazinglynamed"systemstringsmanagementAPI"anditsmemberscaneasilybedistinguishedbythe"Sys"prefixintheirnames.
Thefollowingcodesnippet,borrowedfromOleauto.h(thisstuffusedtobemostusefulwhencoupledwithAutomation,asVisualBasic'sCOMsupportwasalotlesspowerfulthen),showstheprototypesofeachofthefunctionsinthegroup:
/*---------------------------------------------------------------------*/ /*BSTRAPI*/ /*---------------------------------------------------------------------*/ WINOLEAUTAPI_(BSTR)SysAllocString(constOLECHAR*); WINOLEAUTAPI_(INT)SysReAllocString(BSTR*,constOLECHAR*); WINOLEAUTAPI_(BSTR)SysAllocStringLen(constOLECHAR*,UINT); WINOLEAUTAPI_(INT)SysReAllocStringLen(BSTR*,constOLECHAR*,UINT); WINOLEAUTAPI_(void)SysFreeString(BSTR); WINOLEAUTAPI_(UINT)SysStringLen(BSTR); #ifdef_WIN32 WINOLEAUTAPI_(UINT)SysStringByteLen(BSTRbstr); WINOLEAUTAPI_(BSTR)SysAllocStringByteLen(LPCSTRpsz,UINTlen); #endif |
Thefollowingtablebrieflydescribesthetaskofeachroutine:
Functionname | Description |
SysAllocString() | AllocatesanewBSTRandinitializesitwithanOLECHAR* |
SysReAllocString() | ReallocatesanexistingBSTRandinitializesitwithanOLECHAR* |
SysAllocStringLen() | AllocatesanewBSTR,copiesaspecifiednumberofcharactersfromthepassedOLECHAR*intoit,andthenappendsanullcharacter |
SysReAllocStringLen() | ReallocatesanexistingBSTR,copiesaspecifiednumberofcharactersfromthepassedOLECHAR*intoit,andthenappendsanullcharacter |
SysFreeString() | DeallocatesaBSTR |
SysStringLen() | ReturnsthenumberofcharactersinaBSTR |
SysStringByteLen() | ReturnsthelengthinbytesofaBSTR(Win32only) |
SysAllocStringByteLen() | AllocatesaBSTRthatcontainstheANSIstringpassedasaparameter.DoesnotperformanyANSI-to-Unicodetranslation(Win32only) |
Basicstringsmustbeallocatedandfreedmanually.Butwhohastheresponsibilityofdoingsowhenfunctioncallsareinvolved?ThisisageneralCOMquestionandsotheanswerdoesnotapplysolelytostrings.Iftheparameterisinput-only(IDLattribute[in])thecallerisresponsibleforboththecreationandthedestructionofthevariable.Iftheparameterisoutput-only(IDLattribute[out])thenthecalleeisresponsiblefortheallocationofthestring,butthecallerisexpectedtofreeitafteruse.Iftheparameterisbothinputandoutput(IDLattribute[in,out])thenthecallerallocatesthestringandafterthemethodinvocationfreesthememory.Thecalleethoughisallowedtoreallocatethestringifnecessarytodosobeforereturningittothecaller.
ObviouslythesedetailsinterestC/C++developersonly,asVisualBasicwillcontinuetotreatstringsasusualwithoutanyspecialconsideration.
BSTRwrappers
BothATLandMFCofferparticularsupportforsimplifiedBSTRmanagement.ATLdoesitbymeansofaspecializedwrapperclass,CComBSTR,whosedeclarationinatlbase.hlookslikethefollowing(strippeddownasusualforclarityandspaceconstraints):
classCComBSTR { public: BSTRm_str; CComBSTR(); CComBSTR(intnSize,LPCOLESTRsz=NULL); CComBSTR(LPCOLESTRpSrc); CComBSTR(constCComBSTR&src); CComBSTR&operator=(constCComBSTR&src); CComBSTR&operator=(LPCOLESTRpSrc); ~CComBSTR(); unsignedintLength()const; operatorBSTR()const; BSTR*operator&(); BSTRCopy()const; voidAttach(BSTRsrc); BSTRDetach(); voidEmpty(); #if_MSC_VER>1020 booloperator!(); #else BOOLoperator!(); #endif voidAppend(constCComBSTR&bstrSrc); voidAppend(LPCOLESTRlpsz); voidAppendBSTR(BSTRp); voidAppend(LPCOLESTRlpsz,intnLen); CComBSTR&operator+=(constCComBSTR&bstrSrc); #ifndefOLE2ANSI CComBSTR(LPCSTRpSrc); CComBSTR(intnSize,LPCSTRsz=NULL); CComBSTR&operator=(LPCSTRpSrc); voidAppend(LPCSTR); #endif HRESULTWriteToStream(IStream*pStream); HRESULTReadFromStream(IStream*pStream); }; |
encapsulationoftheallocationanddeallocationprocedureswithintheconstructoranddestructor;
duplicationofthecontents(throughCComBSTR::Copy());
possibilitytoappendalmostanykindofstringtothewrappedBSTRexploitingtheoverloadingfeatureofC++;
supportforreadablestringcomparisonsthroughthecustomized!operator;
basicI/Ooperationstostorethecontentsofthestringto,andretrieveitfrom,astructuredstoragestream.
Ontheotherhand,MFCdoesnotprovideanydirectwrapperclassforsystemstrings.AllthesupportisanintegralpartoftheextremelyversatileCstringclass.Asshowninthefollowingcodesnippetborrowedfromtheclass'sprototypeinafx.h,thereareonlyacoupleofmethodsspecificallygeneratingCOMstrings:
//OLEBSTRsupport(useforOLEautomation) BSTRAllocSysString()const; BSTRSetSysString(BSTR*pbstr)const; |
Moreover,ifyouareusingVisualC++5.0orhigher,youcanexploittheDirectToCOMproprietaryextensionwhichincludes,amongmanyotherthings,a_bstr_tclass.Thedocumentationreportsthatitisdefinedinsidecomdef.h,whileinrealityitsdeclarationresidesincomutil.h.ThedegreeofencapsulationandfunctionalityissimilartoATL'sCComBSTR,butrememberthatusingtheCOMcompilersupportbindsyoutoVisualC++evenmorethanATLwoulddo.Probablythemostrelevantdifferencebetweenthetwoimplementationsisthat_bstr_traisesC++exceptionsandthusrequiresyourcodetobepreparedtocatchthem,whereasCComBSTRdoesnot.Thisdetailwilllikelyinfluenceyourchoicemorethanalltheotherpossibleconsiderations.Thefollowingcodelistingsummarizesthepublicinterfaceof_bstr_t;thecommentsshouldmakeiteasytounderstandwhatthediversemethodgroupsareupto:
class_bstr_t{ public: //Constructors // _bstr_t()throw(); _bstr_t(const_bstr_t&s)throw(); _bstr_t(constchar*s)throw(_com_error); _bstr_t(constwchar_t*s)throw(_com_error); _bstr_t(const_variant_t&var)throw(_com_error); _bstr_t(BSTRbstr,boolfCopy)throw(_com_error); //Destructor // ~_bstr_t()throw(); //Assignmentoperators // _bstr_t&operator=(const_bstr_t&s)throw(); _bstr_t&operator=(constchar*s)throw(_com_error); _bstr_t&operator=(constwchar_t*s)throw(_com_error); _bstr_t&operator=(const_variant_t&var)throw(_com_error); //Operators // _bstr_t&operator+=(const_bstr_t&s)throw(_com_error); _bstr_toperator+(const_bstr_t&s)constthrow(_com_error); //Friendoperators // friend_bstr_toperator+(constchar*s1,const_bstr_t&s2); friend_bstr_toperator+(constwchar_t*s1,const_bstr_t&s2); //Extractors // operatorconstwchar_t*()constthrow(); operatorwchar_t*()constthrow(); operatorconstchar*()constthrow(_com_error); operatorchar*()constthrow(_com_error); //Comparisonoperators // booloperator!()constthrow(); booloperator==(const_bstr_t&str)constthrow(); booloperator!=(const_bstr_t&str)constthrow(); booloperator<(const_bstr_t&str)constthrow(); booloperator>(const_bstr_t&str)constthrow(); booloperator<=(const_bstr_t&str)constthrow(); booloperator>=(const_bstr_t&str)constthrow(); //Low-levelhelperfunctions // BSTRcopy()constthrow(_com_error); unsignedintlength()constthrow(); private: //[...privatestuffomitted...] } |
Copyright©1999-VisualC++DevelopersJournal |
YourideasofOLECHARandBSTRandyourunderstandingofthemannerCOMhandlesstringsshouldbemuchclearernow,butwestillhavetocopewithtypeconversionstoandfromthesesomewhatspecialdatatypesandthemoretraditionalTCHAR,WCHARandchar.
ATLandMFCbothusethesamegroupofmacrostodealwithstringconversions.Thesemacros'namesfollowapreciseconvention:thecharactersbeforethe"2"indicatetheoriginaltypeofthevariabletoconvert,andthecharactersafterthe"2"indicatethedestinationtypeaftertheconversion.Thefollowingtableliststhevalidsymbolsinaconversionmacroname:
Shortname | Datatype |
A | LPSTR,char* |
OLE | LPOLESTR |
T | LPTSTR,TCHAR* |
W | LPWSTR,wchar_t* |
BSTR | BSTR |
C | const-associatedtoanothertype |
//ConversionsthroughMFC/ATL'smacros voidSample2() { USES_CONVERSION; //ANSI LPSTRansiStr="Thisisasamplemessage"; printf("BEFOREthestringcontains:%s/n",ansiStr); //ANSI->constTCHAR constTCHAR*pTChar=A2CT(ansiStr); _tprintf(_T("MIDWAYthestringcontains:%s/n"),pTChar); //constTCHAR->Unicode LPWSTRwStr=T2W(pTChar); wprintf(L"AFTERthestringcontains:%s/n",wStr); } |
TheCOMcompilersupportoffersgoodBSTRconversioncode,too.Theactualconversionfunctionsarethecastoperatorsthatconverta_bstr_ttoeitheranANSIoraUnicodestring,eitherconstantornot,plustheomnipresentclassconstructors.Thefollowingcodesnippet,takenfromthedownloadablesamplepackavailableontheWeb,showssomecommonusagepatternsofBSTRconversions:
//BSTRconversions voidSample3() { USES_CONVERSION; LPWSTRwStr=L"Thisisasamplemessage"; wprintf(L"BEFOREthestringcontains:%s/n",wStr); BSTRbstr1=W2BSTR(wStr); CStringmfcStr=bstr1; printf("MIDWAYthestringcontains:%s/n",(LPCSTR)mfcStr); BSTRbstr2=mfcStr.AllocSysString(); _bstr_tbstr3=bstr2; VERIFY(bstr3==(_bstr_t)bstr1); WCHAR*wStr2=bstr3; wprintf(L"AFTERthestringcontains:%s/n",wStr2); ::SysFreeString(bstr1); ::SysFreeString(bstr2); } |
Conclusion
Aftersomestudyanddirectexperimentation,thevariousstringtypesinCOMprovetobemuchlesscrypticandproblematicthanatfirsttheyseemed.Fundamentally,itallboilsdowntorecognizingandmemorizingahandfulofnewdatatypeswhichmaybehavedifferentlyondifferentplatforms,andgettingusedtotheframeworkofhandyconversionfunctionsprovidedbyATL,MFC,ortheDirectToCOMVisualC++extension.Regardlessofwhichofthementionedtasksyouaregoingtotackle,Ihopethisarticlewillserveasavaluableaidinsavingprecioustimeworkingwithstrings.
Copyright©1999-VisualC++DevelopersJournal |
相关文章推荐
- .NET中使用Redis:http://www.cnblogs.com/yangecnu/p/Introduct-Redis-in-DotNET.html
- Conflicting collector combinations in option list; please refer to the release notes for the combina
- 解决:ould not find a getter for porDate in class com.bc.bean.PortalSheet Caused by: org.hibernate.PropertyNotFoundException: Could
- Understanding Annotations in Java
- Exception in thread "main" org.hibernate.MappingException: Unknown entity: com.mao.PersonSet
- Find common characters in a set of strings
- Ubuntu 16.04更新软件提示"需要安装不能信任的软件包" http://archive.ubuntukylin.com:10006/ubuntukylin xenial InRelease
- ListView应用(转自http://www.cnblogs.com/allin/archive/2010/05/11/1732200.html)
- com.atomikos.datasource.ResourceException: Error in recovery
- Understanding “extern” keyword in C
- EJB在weblogic下遇到的Exception:Exception in javax.naming.NameNotFoundException: While trying to lookup 'ejb.com/genuitec/trader/ejb/T
- Understanding Templates in ASP.NET
- Spring Cloud ZooKeeper集成Feign的坑2,服务调用了一次后第二次调用就变成了500,错误:Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is com.n
- Outputting Strings in the Console
- This is [an example](http://example.com/ "Title") inline link
- 记一次错误:Error:Conflict with dependency 'com.google.code.findbugs:jsr305' in project ':app'.错误!
- 译:用标准C编写COM(八) 2010-08-04 15:32:07| 分类: ActiveX Scriptin | 标签: |举报 |字号大
- python csv.Error: iterator should return strings, not bytes (did you open the file in text mode?)
- There is no getter for property named 'itmesCustom' in 'class com.ssm.po.Ite
- Comparing cursor vs. WHILE loop performance in SQL Server 2008(ZThttp://stackoverflow.com/questions)