Tải bản đầy đủ - 0 (trang)
Hack 83. Control iTunes Under Windows

Hack 83. Control iTunes Under Windows

Tải bản đầy đủ - 0trang

directory,youcangeneratetheinterfaceslikethis:

java-jartlbimp.jar-ojtunes-ptest.jtunesiTunes.exe



ThiscommandwillloadtheiTunesexecutableandlookforCOM

definitions.Oncetheyarelocated,tlbimpwillgenerateabunch

ofJavainterfacesinthetest.jtunespackageandputthe.java

filesintothejtunesdirectory.IfyoulookatthegeneratedJava

interfaces,youwillseeawholeslewofmethodsandobjectsfor

playing,queryingtracks,anddealingwithvirtuallyeveryother

featureofiTunes.com4jwillalsopulloutanyembedded

documentationandinsertthedocumentationasJavaDoc

commentsinthegeneratedinterfaces.



Thisprocessisprettyquick,soyoumayfinditusefultocallitfromAnt

aspartofyourcompileprocess.



Onceyouhavetheinterfacestubs,youcancreateaprogramto

controliTunesquiteeasily.Youcanusethesameprogramthat

youdidwhencontrollingiTunesontheMac[Hack#82].Just

replacetheactionlistenerwiththeclassinExample11-6.



Example11-6.AlistenertocontroliTuneson

Windows











importtest.jtunes.*;

publicclassWinItunes{



publicvoidactionPerformed(ActionEventevt){





try{



































IiTunesitunes;

itunes=ClassFactory.createiTu

itunes.playPause();



























}











}



}catch(Excepti(Exceptionex){



System.out.println("exception:



ex.printStackTrace();

}



Compilethisclassalongwiththeinterfacesinthetest.jtunes

package.Youwillalsoneedthecom4j.jarinyourCLASSPATHand

com4j.dllfilesinyourPATH.Whenyouruntheprogram,the

com4jlibrarywillconnecttoiTuneslaunchingitifnecessaryand

executetheplayPause()method.



com4jonlyallowsyoutocallmethodsfromthesamethreadthatyou

usedtocreatetheCOMproxy.Typically,youwanttoupdateyourSwing

componentswithiTunesinformation,whichyoucandosafelyfromthe

Swingeventthreadonly.ThismeansthatyoushouldcreatetheCOM

proxyfromtheeventthreadaswell(usingtheClassFactorymethod).

Unfortunately,thismaycauseyourapplicationtoblockforafew

secondswhileiTunesloads(ifit'snotalreadyrunning).Toavoidthis

delay,youprobablywanttodoallofyouriTunescommunication

throughacustomqueue,orusethenewconcurrencyutilitiesavailable

inJava5.0.Thecom4jdevelopersareworkingonasolutiontothis

problem,soitmaybesolvedbythetimeyoureadthis.



11.6.2.GetTrackInformation

AswithAppleEventsontheMac[Hack#82],theCOM

interfacegivesyouawaytoquerythecurrentlyplayingtrack.

YoucancalliTunes.currentTrack()togetanIITTrackobject.This

objecthasmethodstoqueryjustaboutanythingyoucould

possiblewanttoknowaboutatrack,includingtheartist,



album,playingtime,encodingmethod,andeventheimport

date.EachmethodontheIITTrackobjectreturnsinformationas

StringsorJavaprimitives,soit'sprettyeasytoaccessanything

youwantandthenstuffitintoyourSwinginterface.The

followingcodeshowshowtogetthetracknumber,count,

name,album,andartist:











IITTracktrack;

track=itunes.currentTrack();

inttrack_number=track.trackNumber();

inttrack_count=track.trackCount();











Stringtrack_name=track.name();

Stringalbum_name=track.album();

Stringartist_name=track.artist();



com4jisagreatopensourceprojectthatunleashesthepower

ofJavacodeintegratedwithnativeapplications.TheiTunes

COMinterfaceprovideshooksforvirtuallyeverythingthat

iTunescando.Thesetwothingsmeanyoucouldwritea

programtosortsongs,createnewplaylists,orevenexport

tracklistingstoyourownapplicationthatprintsCDlabels.You

canfindfscom/sdk/itunescomsdk.html,soseewhatothercool

thingsyoucancomeupwith.



Hack84.ConstructSingle-LaunchApplications



Onlyallowoneinstanceofaprogram,notifyingthe

existinginstancewhentheusertriestolaunchanew

one.

Mostgraphicaldesktopapplicationsaredesignedfor

multitasking.Youstartyourprogramtoworkonsomething,

thenswitchtoanotherprogramandcomebacklater.

Oftentimesyou'llleavealargeprogram,likeawordprocessor,

runninginthebackgroundtobeusedagainwhenyouneedto

openanotherdocument,sayanemailattachmentyoureceived.

Whenyouclickontheattachment,youroperatingsystemwon't

startanewinstanceofthewordprocessor;instead,itwillsend

amessagetothecurrentlyrunninginstancetoopenthenew

filesavinglotsofsystemresources.

Javaprogramsaren'tdesignedwithsingle-launchbehaviorin

mind.TheystillusetheoldUnixstyleofsingleuse,commandlinelaunching.Youstarttheprogramtodosomethingandit

finishesquickly.Ifyouusetheprogramagainitwillstartanew

instance,dothework,andfinish.Thereisneveranyinstance

reuse,butmoderndesktopprogramsdemandit.BecauseJava

doesn'tsupportsingle-launchapplications,thishackshowsyou

howtobuilditintoyourprogramswithasimpleuseofsockets.



11.7.1.LocalSockets

Buildingasingle-launchapplicationrequirestwoparts.When

theprogramstarts,itneedstodetectifanothercopyisalready

running.Ifthereis,thentheprogramcanquitinsteadof

continuingtolaunch.Thenewprogramalsoneedstotellthe



firstcopyaboutanycommand-lineargumentsthefilenameto

open,forexample.Youcouldcreateatempfileinaknown

locationandlooktoseeifitalreadyexists.Thiswouldtakecare

ofmultipleprograminstances,butnotpassingarguments

around.Plus,youwouldneedtoworryaboutraceconditions

andcleaningupthetempfilewhenthelastprogramexits.

Thankfully,there'samuchbettersolution:localsockets.

Asocketisanetworkconnectiondefinedbyahostnameanda

port.Alocalsocketisanetworkconnectiononlyonthelocal

machine.Whenyouopenasockettolistenforconnectionsyou

arebindingtothatport.Onlyoneprogramcanbindtoany

givenportatonetime,sotheportitselfcanserveasyourlock.

Ifyourprogramcannotconnecttotheport,thenanother

programmustalreadybeusingit.Itdoesn'tmatterwhatthe

portnumberis,aslongasyourprogramalwaysusesthesame

one.Hereisthebeginningofthecodetoputthisintoaction:











publicclassSingleLauncherApplicationimplementsRunna



publicstaticfinalintPORT=38629;



publicJLabellabel;



publicServerSocketserver;



























publicvoidlaunch(String[]args){



try{





server=newServerSocket(PORT)





newThread(this).start();





firstMain(args);



























}catch(IOExceptionioex){



System.out.println("alreadyrun



relaunch(args);

















}



}



SingleLauncherApplicationisaclasswithonecoremethod:launch().

launch()takesthesameargumentsasthestandardmain()



method,whichisimportantsinceyouareessentiallycreating

fakeversionsofmain.Whenlaunchiscalled,itwillfirsttryto

bindtotheportbycreatingaserversocket.NoticethePORT

constantsettothenumber38629.Itisimportantthattheport

isn'treservedforusebyanysystemservices.Someoperating

systemsalsorestrictuserprogramstoonlyuseportsover

1,000,soIpickedthisnumberatrandomfromthe20,000to

60,000range.Thismakesitveryunlikelythattheportwill

alreadybeinusebyanyotherprogram.

Iflaunch()cancreateaServerSocket,thenitwillstartanew

thread,engagerun(),andthencallfirstMain():













publicvoidfirstMain(String[]args){



JFrameframe=newJFrame("SingleLaunchApplic



frame.setDefaultCloseOperation(JFrame.EXIT_ON_C



Stringword="";



if(args.length>=1){



































}





word=args[0];

}

label=newJLabel("Thewordofthedayis:"+

frame.getContentPane().add(label);

frame.pack();

frame.show();



firstMain()containsthenormalstartupcodethatwouldhave



goneinmain()previously.Here,itcreatesanewJFramewitha

singlelabelinit,containingthetext"Thewordofthedayis:"

followedbythefirstcommandlineargument.



Nextcomestherun()method,whichislaunchedinthenew

threadbylaunch().Itsentirepurposeinlifeistositonthatport

andwaitforconnections.Ifanotherinstanceconnects,thenit

readsintheargumentsandcallsotherMain()torelaunchthe

application:













































publicvoidrun(){



System.out.println("waitingforaconnection");



while(true){





try{







//waitforasocketconnection







Socketsock=server.accept();













//readthecontentsintoastr







InputStreamReaderin=newInpu







sock.getInputStream());







StringBuffersb=newStringBuf







char[]buf=newchar[256];







while(true){







intn=in.read(buf);







if(n<0){break;}







sb.append(buf,0,n);







}







//splitthestringbufferinto







String[]results=sb.toString(







//callothermain







otherMain(results);



























}catch(IOExceptionex){



System.out.println("ex:"+ex)



ex.printStackTrace();















}





}



}



server.accept()willblockuntilanotherprogramconnects.When



onedoes,thecodewillopenaninputstreamforthesocketand

begintoreadoutcharactersandsaveitinastringbuffer.If

in.read(buf)returns-1(n<0),thenitknowstheotherend

disconnectedandthat'sallthereis.Command-linearguments

arejuststrings,buttheymayhavespacesinthem,sothecode

abovewillsplitthestringbufferbynewlines("\\n")intoan

arrayofstrings.Finally,itcallsotherMain()withthestringarray:









publicvoidotherMain(finalString[]args){



if(args.length>=1){





SwingUtilities.invokeLater(newRunnable













}



publicvoidrun(){







label.setText("Thewordofthe





}



});

}



otherMain()doesn'trepeatthestartupstepsoffirstMain().



Insteaditjustchangesthetextofthelabeltomatchthenew

command-linearguments.BecauseSwingisn'tthread-safe,you

can'tsetthelabeltextinthelaunchingthread.Instead,you

needtocallitfromtheSwingeventthread.Theeasiestwayto

dothisiswiththeutilitymethod:SwingUtilities.invokeLater().You

canpassitananonymousRunnable()thatdoestheactual

setText()call.Notethattheinputvariableargshastobemade

finalforthistowork.

Ifthisisthesecondinstanceoftheprogram,thenthenew

ServerSocket()willfail,andrelaunch()iscalledtosendthe

command-lineargumentstothefirstinstance:













publicvoidrelaunch(String[]args){



try{



//openasockettotheoriginalinstance



Socketsock=newSocket("localhost",PORT);



































//writetheargstotheoutputstream



OutputStreamWriterout=newOutputStreamWriter





sock.getOutputStream());



for(inti=0;i




out.write(args[i]+"\n");





p("wrote:"+args[i]);



}



//cleanup



out.flush();



out.close();



}catch(Exceptionex){



System.out.println("ex:"+ex);



ex.printStackTrace();





}



}



relaunch()opensasockettotheportonlocalhost.Sincenew

ServerSocket()failed,itknowsthatthefirstinstanceofthe



programisalreadywaitingontheothersideofthatport.Once

itconnects,itwritesthecommand-lineargumentstothe

socket'soutputstream,separatingeachargumentwitha

newline(\n).Finally,itflushestheoutputstreamtomakesure

everythingwaswritten,andthenclosesit.Afterthat,the

relaunch()andlaunch()methodswillreturn,quittingthesecond

instanceoftheprogram.Theargumentshavenowbeensentto

thefirstinstance.

Toactuallystartthiswholeclass,yousimplycallthelaunch



methodlikethis:









publicstaticvoidmain(String[]args){

newSingleLauncherApplication().launch(args);

}



Thefirsttimetheprogramislauncheditwillcreatethewindow

withthelabel.Forexample,runningthefollowingcommand

wouldresultinFigure11-8.





java-cp.SingleLauncherApplication'anonymous'



Figure11-8.Initiallaunch



Now,starttheprogramagain,withthefirstrunning:





java-cp.SingleLauncherApplication'perspicacity'



Insteadofcreatinganewwindow,theprogramwillcontactthe

original(andstillrunning)instanceandchangethetextto.



Figure11-9.Afterrelaunching



Tài liệu bạn tìm kiếm đã sẵn sàng tải về

Hack 83. Control iTunes Under Windows

Tải bản đầy đủ ngay(0 tr)

×