1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772 |
- /*++
- Copyright (c) 2012 Minoca Corp.
- This file is licensed under the terms of the GNU General Public License
- version 3. Alternative licensing terms are available. Contact
- info@minocacorp.com for details. See the LICENSE file at the root of this
- project for complete licensing information.
- Module Name:
- ntdbgui.c
- Abstract:
- This module implements the graphical UI for the debugger running on
- Windows.
- Author:
- Evan Green 14-Jul-2012
- Environment:
- Debugger (Windows)
- --*/
- //
- // ------------------------------------------------------------------- Includes
- //
- //
- // Define WIN32 versions to enable group view for the list view control.
- //
- #define _WIN32_WINNT 0x0600
- #define _WIN32_IE 0x0600
- #include <windows.h>
- #include <windowsx.h>
- #include <commctrl.h>
- #include <commdlg.h>
- #include <richedit.h>
- #include <shlwapi.h>
- #include <fcntl.h>
- #include <limits.h>
- #include <assert.h>
- #include <stdio.h>
- #include <minoca/debug/spproto.h>
- #include <minoca/debug/dbgext.h>
- #include "dbgrprof.h"
- #include "console.h"
- #include "resource.h"
- #include "missing.h"
- //
- // ---------------------------------------------------------------- Definitions
- //
- #define MAX_KEYWORD 30
- #define MAX_FILENAME MAX_PATH
- #define BACKGROUND_COLOR RGB(39, 40, 34)
- #define BREAKPOINT_COLOR RGB(140, 0, 0)
- #define EXECUTING_COLOR RGB(9, 2, 134)
- #define PLAIN_TEXT_COLOR "\\red248\\green248\\blue242"
- #define CONSTANT_COLOR "\\red174\\green129\\blue255"
- #define KEYWORD_COLOR "\\red249\\green38\\blue114"
- #define COMMENT_COLOR "\\red117\\green113\\blue94"
- #define BRACE_COLOR "\\red240\\green240\\blue240"
- #define QUOTE_COLOR "\\red230\\green219\\blue90"
- #define DISABLED_COLOR "\\red70\\green70\\blue70"
- #define RTF_HEADER "{\\rtf1\\ansi\\ansicpg1252\\deff0\\deftab720{\\fonttbl{" \
- "\\f0\\fmodern\\fcharset1 Courier New;}}{\\colortbl ;" \
- PLAIN_TEXT_COLOR ";" CONSTANT_COLOR ";" KEYWORD_COLOR ";" \
- COMMENT_COLOR ";" BRACE_COLOR ";" QUOTE_COLOR ";" \
- DISABLED_COLOR ";}" \
- "\\deflang1033\\pard\\plain\\f0\\fs18 \\cf1"
- #define RTF_FOOTER "}"
- #define RTF_NEWLINE "\\highlight0\\par"
- #define RTF_NEWLINE_SIZE 15
- #define RTF_PLAIN_TEXT "\\cf1 "
- #define RTF_CONSTANT "\\cf2 "
- #define RTF_KEYWORD "\\cf3 "
- #define RTF_COMMENT "\\cf4 "
- #define RTF_BRACE "\\cf5 "
- #define RTF_QUOTE "\\cf6 "
- #define RTF_DISABLED "\\cf7 "
- #define RTF_COLOR_SIZE 5
- #define RTF_TEST "{\\rtf1\\ansi\\ansicpg1252\\deff0\\deftab720{\\fonttbl{\\f0" \
- "\\fmodern\\fcharset1 Courier New;}}\\deflang1033\\pard" \
- "\\plain\\f0\\fs22 howdy }"
- //
- // Define values associated with the profiler display timer.
- //
- #define PROFILER_TIMER_ID 0x1
- #define PROFILER_TIMER_PERIOD 1000
- //
- // Define the name for the root of the call stack tree.
- //
- #define CALL_STACK_TREE_ROOT_STRING "Root"
- //
- // Define the number of columns in the memory statistics list view.
- //
- #define MEMORY_STATISTICS_COLUMN_COUNT 7
- //
- // Add some extra padding to make mouse click regions bigger.
- //
- #define UI_MOUSE_PLAY 8
- //
- // Define the current debugger UI preferences version number.
- //
- #define DEBUGGER_UI_PREFERENCES_VERSION 2
- //
- // ------------------------------------------------------ Data Type Definitions
- //
- //
- // Define the function type for the common controls initialization routine.
- //
- typedef
- BOOL
- (WINAPI *PINITCOMMONCONTROLSEX) (
- LPINITCOMMONCONTROLSEX lpInitCtrls
- );
- typedef
- INT
- (*PNTDBGCOMPAREROUTINE) (
- ULONGLONG ValueOne,
- ULONGLONG ValueTwo
- );
- typedef
- ULONGLONG
- (*PGETCOLUMNVALUE) (
- PVOID Structure,
- ULONG Offset
- );
- typedef struct _STREAM_IN_DATA {
- PCHAR Buffer;
- ULONG BufferSize;
- ULONG CurrentPosition;
- } STREAM_IN_DATA, *PSTREAM_IN_DATA;
- /*++
- Structure Description:
- This structure defines strings, string formats, and various routines
- associated with a column in the memory statistics list view.
- Members:
- Header - Stores the string to use as the column header.
- Format - Stores the FormatMessage style format message for the column's
- data.
- DeltaFormat - Stores the FormatMessage style format message to use for the
- column's data when in delta mode.
- CompareRoutine - Stores a pointer to a routine that can be used to compare
- two elements in this column.
- DeltaCompareRoutine - Stores a pointer to a routine that can be used to
- compare two elements in this column when in delta mode.
- Offset - Stores the offset within the PROFILER_MEMORY_POOL_TAG_STATISTIC
- structure that holds the column's data.
- --*/
- typedef struct _MEMORY_COLUMN {
- LPTSTR Header;
- LPTSTR Format;
- LPTSTR DeltaFormat;
- PNTDBGCOMPAREROUTINE CompareRoutine;
- PNTDBGCOMPAREROUTINE DeltaCompareRoutine;
- PGETCOLUMNVALUE GetColumnValueRoutine;
- ULONG Offset;
- } MEMORY_COLUMN, *PMEMORY_COLUMN;
- /*++
- Structure Description:
- This structure defines strings, string formats, and various routines
- associated with a column in the memory statistics list view.
- Members:
- Version - Stores the version of the structure. Set to
- DEBUGGER_UI_PREFERENCES_VERSION.
- WindowX - Stores the X position of the debugger window in pixels.
- WindowY - Stores the Y position of the debugger window in pixels.
- WindowWidth - Stores the width of the debugger window in pixels.
- WindowHeight - Stores the height of the debugger window in pixels.
- MainPaneXPosition - Stores the X position of the divider between the two
- main panes.
- MainPainXPositionWidth - Stores the width of the main pane at the time the
- X position was stored. The X position is used to create a percentage of
- the current width and is only relevant if the old width is saved.
- ProfilerPaneYPosition - Stores the Y position of the diveder between the
- profiler and source code.
- ProfilerPaneYPositionHeight - Store the height of the left pain at the time
- the Y position for the profiler was stored. The Y position is used to
- create a percentage of the current height and is only relevant if the
- old height is stored.
- --*/
- typedef struct _DEBUGGER_UI_PREFERENCES {
- ULONG Version;
- DWORD WindowX;
- DWORD WindowY;
- DWORD WindowWidth;
- DWORD WindowHeight;
- DWORD MainPaneXPosition;
- DWORD MainPaneXPositionWidth;
- DWORD ProfilerPaneYPosition;
- DWORD ProfilerPaneYPositionHeight;
- } DEBUGGER_UI_PREFERENCES, *PDEBUGGER_UI_PREFERENCES;
- //
- // ----------------------------------------------- Internal Function Prototypes
- //
- DWORD
- WINAPI
- ConsoleStandardOutThread (
- LPVOID WindowHandle
- );
- DWORD
- WINAPI
- UiThreadMain (
- LPVOID Parameter
- );
- INT_PTR
- CALLBACK
- MainDialogProc (
- HWND DialogHandle,
- UINT Message,
- WPARAM WParam,
- LPARAM LParam
- );
- LRESULT
- CALLBACK
- TreeViewWindowProcedure (
- HWND Window,
- UINT Message,
- WPARAM WParam,
- LPARAM LParam
- );
- DWORD
- CALLBACK
- RichEditLoadCallback (
- DWORD_PTR Context,
- LPBYTE Buffer,
- LONG Bytes,
- PLONG BytesComplete
- );
- BOOL
- LoadFileIntoRichEdit (
- HWND RichEdit,
- LPCTSTR Filename,
- PUCHAR FileBuffer,
- ULONGLONG FileSize
- );
- BOOL
- HighlightSyntax (
- PUCHAR TextBuffer,
- ULONG TextBufferSize,
- PCHAR *BufferOut,
- PULONG FileSizeOut
- );
- BOOL
- IsKeyword (
- PSTR String
- );
- BOOL
- IsKeywordSeparator (
- UCHAR Character
- );
- VOID
- HighlightLine (
- HWND RichEdit,
- LONG LineNumber,
- COLORREF Color,
- BOOL ScrollToLine
- );
- VOID
- HandleResize (
- HWND Dialog
- );
- VOID
- HandleCommandMessage (
- HWND Dialog,
- WPARAM WParam
- );
- VOID
- HandleCommonControlMessage (
- HWND Dialog,
- LPARAM LParam
- );
- VOID
- HandleCommandEnter (
- HWND CommandEdit
- );
- VOID
- WriteByteToInput (
- BYTE Byte
- );
- VOID
- InitializeProfilerControls (
- VOID
- );
- VOID
- UpdateProfilerWindowType (
- HWND Dialog,
- PROFILER_DATA_TYPE DataType
- );
- VOID
- HandleProfilerTreeViewCommand (
- HWND Dialog,
- LPARAM LParam
- );
- VOID
- HandleProfilerListViewCommand (
- HWND Dialog,
- LPARAM LParam
- );
- PSTACK_DATA_ENTRY
- FindStackDataEntryByHandle (
- PSTACK_DATA_ENTRY Root,
- HTREEITEM Handle
- );
- VOID
- SetProfilerTimer (
- PROFILER_DATA_TYPE DataType
- );
- VOID
- KillProfilerTimer (
- PROFILER_DATA_TYPE DataType
- );
- VOID
- PauseProfilerTimer (
- VOID
- );
- VOID
- ResumeProfilerTimer (
- VOID
- );
- VOID
- CALLBACK
- ProfilerTimerCallback (
- HWND DialogHandle,
- UINT Message,
- UINT_PTR EventId,
- DWORD Time
- );
- BOOL
- UpdateProfilerDisplay (
- PROFILER_DATA_TYPE DataType,
- PROFILER_DISPLAY_REQUEST DisplayRequest,
- ULONG Threshold
- );
- VOID
- UpdateCallStackTree (
- HTREEITEM Parent,
- PSTACK_DATA_ENTRY Root,
- ULONG TotalCount
- );
- INT
- CALLBACK
- StackProfilerTreeCompare (
- LPARAM LParamOne,
- LPARAM LParamTwo,
- LPARAM LParamSort
- );
- VOID
- UpdateMemoryStatisticsListView (
- PLIST_ENTRY PoolListHead
- );
- BOOL
- CreateMemoryPoolListViewGroup (
- PPROFILER_MEMORY_POOL MemoryPool,
- PINT GroupId
- );
- BOOL
- DoesMemoryPoolListViewGroupExist (
- PPROFILER_MEMORY_POOL MemoryPool,
- PINT GroupId
- );
- BOOL
- UpdateMemoryPoolListViewGroup (
- PPROFILER_MEMORY_POOL MemoryPool,
- INT GroupId
- );
- INT
- GetMemoryPoolGroupId (
- PPROFILER_MEMORY_POOL MemoryPool
- );
- BOOL
- CreateMemoryPoolTagListViewItem (
- ULONG Tag,
- INT GroupId,
- PINT ItemIndex
- );
- VOID
- DeleteMemoryPoolTagListViewItem (
- INT ListViewIndex
- );
- BOOL
- DoesMemoryPoolTagListViewItemExist (
- PPROFILER_MEMORY_POOL_TAG_STATISTIC Statistic,
- INT GroupId,
- PINT ListViewIndex
- );
- BOOL
- UpdateMemoryPoolTagListViewItem (
- INT ItemIndex,
- INT GroupId,
- PPROFILER_MEMORY_POOL_TAG_STATISTIC Statistic
- );
- INT
- CALLBACK
- MemoryProfilerListViewCompare (
- LPARAM LParamOne,
- LPARAM LParamTwo,
- LPARAM LParamSort
- );
- BOOL
- TreeViewIsTreeItemVisible (
- HWND TreeViewWindow,
- HTREEITEM TreeItem
- );
- BOOL
- TreeViewGetItemRect (
- HWND Window,
- HTREEITEM Item,
- LPRECT Rect,
- BOOL ItemRect
- );
- LPTSTR
- GetFormattedMessageA (
- LPTSTR Message,
- ...
- );
- LPWSTR
- GetFormattedMessageW (
- LPWSTR Message,
- ...
- );
- VOID
- ListViewSetItemText (
- HWND Window,
- int Item,
- int SubItem,
- LPTSTR Text
- );
- INT
- ComparePoolTag (
- ULONGLONG ValueOne,
- ULONGLONG ValueTwo
- );
- INT
- CompareUlong (
- ULONGLONG ValueOne,
- ULONGLONG ValueTwo
- );
- INT
- CompareLong (
- ULONGLONG ValueOne,
- ULONGLONG ValueTwo
- );
- INT
- CompareLonglong (
- ULONGLONG ValueOne,
- ULONGLONG ValueTwo
- );
- INT
- CompareUlonglong (
- ULONGLONG ValueOne,
- ULONGLONG ValueTwo
- );
- ULONGLONG
- GetUlonglongValue (
- PVOID Structure,
- ULONG Offset
- );
- ULONGLONG
- GetUlongValue (
- PVOID Structure,
- ULONG Offset
- );
- VOID
- UiGetWindowPreferences (
- HWND Dialog
- );
- VOID
- UiLoadPreferences (
- HWND Dialog
- );
- VOID
- UiSavePreferences (
- HWND Dialog
- );
- BOOL
- UiReadPreferences (
- PDEBUGGER_UI_PREFERENCES Preferences
- );
- BOOL
- UiWritePreferences (
- PDEBUGGER_UI_PREFERENCES Preferences
- );
- HANDLE
- UiOpenPreferences (
- VOID
- );
- //
- // -------------------------------------------------------------------- Globals
- //
- HANDLE StdInPipeRead;
- HANDLE StdInPipeWrite;
- HANDLE StdOutPipe;
- BOOL ConsoleInitialized = FALSE;
- HWND DialogWindow;
- extern HANDLE StdInPipeWrite;
- //
- // Remember whether or not commands are currently enabled.
- //
- BOOL CommandsEnabled;
- //
- // Stores an enumerated type indicating which data type is currently showing in
- // the profiler window. The max type means the window is hidden.
- //
- PROFILER_DATA_TYPE ProfilerWindowType = ProfilerDataTypeMax;
- //
- // Stores a pointer to the root of the profiler stack tree.
- //
- PSTACK_DATA_ENTRY StackTreeRoot = NULL;
- //
- // Stores a handle to a lock that protects access to the stack tree.
- //
- HANDLE StackTreeLock;
- //
- // Stores an array describing which profiling types are using the timer.
- //
- BOOL ProfilerTimerTypes[ProfilerDataTypeMax];
- //
- // Stores a pointer to the original Tree View Window message procedure call.
- //
- WNDPROC OriginalTreeViewWindowProcedure;
- //
- // Stores a handle to the currently selected Tree View item.
- //
- HTREEITEM TreeViewSelection = NULL;
- //
- // Stores a boolean indicating whether the currently selected Tree View item is
- // visible.
- //
- BOOL TreeViewSelectionVisible = FALSE;
- //
- // Stores an array of memory statistics list view column names.
- //
- MEMORY_COLUMN MemoryStatisticsColumns[MEMORY_STATISTICS_COLUMN_COUNT] = {
- {"Tag",
- "%1!c!%2!c!%3!c!%4!c!",
- "%1!c!%2!c!%3!c!%4!c!",
- ComparePoolTag,
- ComparePoolTag,
- GetUlongValue,
- FIELD_OFFSET(PROFILER_MEMORY_POOL_TAG_STATISTIC, Tag)},
- {"Largest Alloc",
- "%1!#I32x!",
- "%1!#I32x!",
- CompareUlong,
- CompareUlong,
- GetUlongValue,
- FIELD_OFFSET(PROFILER_MEMORY_POOL_TAG_STATISTIC, LargestAllocation)},
- {"Active Bytes",
- "%1!#I64x!",
- "%1!I64d!",
- CompareUlonglong,
- CompareLonglong,
- GetUlonglongValue,
- FIELD_OFFSET(PROFILER_MEMORY_POOL_TAG_STATISTIC, ActiveSize)},
- {"Max Active Bytes",
- "%1!#I64x!",
- "%1!#I64x!",
- CompareUlonglong,
- CompareUlonglong,
- GetUlonglongValue,
- FIELD_OFFSET(PROFILER_MEMORY_POOL_TAG_STATISTIC, LargestActiveSize)},
- {"Active Count",
- "%1!I32u!",
- "%1!I32d!",
- CompareUlong,
- CompareLong,
- GetUlongValue,
- FIELD_OFFSET(PROFILER_MEMORY_POOL_TAG_STATISTIC, ActiveAllocationCount)},
- {"Max Count",
- "%1!I32u!",
- "%1!I32u!",
- CompareUlong,
- CompareUlong,
- GetUlongValue,
- FIELD_OFFSET(PROFILER_MEMORY_POOL_TAG_STATISTIC,
- LargestActiveAllocationCount)},
- {"Lifetime Alloc",
- "%1!#I64x!",
- "%1!#I64x!",
- CompareUlonglong,
- CompareUlonglong,
- GetUlonglongValue,
- FIELD_OFFSET(PROFILER_MEMORY_POOL_TAG_STATISTIC, LifetimeAllocationSize)}
- };
- //
- // Stores an array of headers for each of the profiler memory types.
- //
- LPWSTR MemoryStatisticsPoolHeaders[ProfilerMemoryTypeMax] = {
- L"Non-Paged Pool",
- L"Paged Pool"
- };
- //
- // Stores a handle to a lock that protects access to the memory lists.
- //
- HANDLE MemoryListLock;
- //
- // Stores a list of memory pools.
- //
- PLIST_ENTRY MemoryPoolListHead = NULL;
- //
- // Stores a list of base line memory statistics used to display deltas.
- //
- PLIST_ENTRY MemoryBaseListHead = NULL;
- //
- // Stores a point to the memory pool deltas between the current list and the
- // base line list.
- //
- PLIST_ENTRY MemoryDeltaListHead = NULL;
- //
- // Stores a boolean indicating whether or not delta memory display mode is
- // enabled.
- //
- BOOL MemoryDeltaModeEnabled = FALSE;
- //
- // Stores memory list view sorting variables.
- //
- INT CurrentSortColumn = INT_MAX;
- BOOL SortAscending = TRUE;
- //
- // Store whether or not various panes are currently being resized.
- //
- BOOL WindowSizesInitialized = FALSE;
- BOOL ResizingMainPanes = FALSE;
- LONG MainPaneXPosition;
- LONG MainPaneXPositionWidth;
- BOOL ResizingProfilerPane = FALSE;
- LONG ProfilerPaneYPosition;
- LONG ProfilerPaneYPositionHeight;
- LONG ProfilerPaneCurrentYPosition;
- //
- // Stores the window rect last captured before a minimize or maximize. This is
- // used to save the UI preferences.
- //
- RECT CurrentWindowRect;
- //
- // ------------------------------------------------------------------ Functions
- //
- int
- APIENTRY
- WinMain (
- HINSTANCE Instance,
- HINSTANCE PreviousInstance,
- LPSTR CommandLine,
- int CmdShow
- )
- /*++
- Routine Description:
- This routine is the main entry point for a Win32 application. It simply
- calls the plaform-independent main function.
- Arguments:
- Instance - Supplies a handle to the current instance of the application.
- PreviousInstance - Supplies a handle to the previous instance of the
- application.
- CommandLine - Supplies a pointer to a null-terminated string specifying the
- command line for the application, excluding the program name.
- CmdShow - Supplies how the window is to be shown.
- Return Value:
- Returns TRUE on success, FALSE on failure.
- --*/
- {
- HANDLE PipeRead;
- HANDLE PipeWrite;
- BOOL Result;
- INT ReturnValue;
- HANDLE UiThread;
- //
- // Create a pipe for the standard output.
- //
- Result = CreatePipe(&PipeRead, &PipeWrite, NULL, 0);
- if (Result == FALSE) {
- DbgOut("Error: Could not create stdout pipe.\n");
- return 1;
- }
- //
- // Set standard output to point to the pipe.
- //
- Result = SetStdHandle(STD_OUTPUT_HANDLE, PipeWrite);
- if (Result == FALSE) {
- DbgOut("Error: Could not redirect stdout.\n");
- return 2;
- }
- StdOutPipe = PipeRead;
- //
- // Create a pipe for standard input.
- //
- Result = CreatePipe(&StdInPipeRead, &StdInPipeWrite, NULL, 0);
- if (Result == FALSE) {
- DbgOut("Error: Could not create stdin pipe.\n");
- return 3;
- }
- //
- // Redirect Standard output to the pipe.
- //
- stdout->_file = _open_osfhandle((LONG)PipeWrite, 0);
- setvbuf(stdout, NULL, _IONBF, 0);
- //
- // Kick off the UI thread.
- //
- UiThread = CreateThread(NULL, 0, UiThreadMain, NULL, 0, NULL);
- if (UiThread == NULL) {
- DbgOut("Unable to create the UI thread!\n");
- return 4;
- }
- ReturnValue = DbgrMain(__argc, __argv);
- return ReturnValue;
- }
- BOOL
- DbgrOsInitializeConsole (
- PBOOL EchoCommands
- )
- /*++
- Routine Description:
- This routine performs any initialization steps necessary before the console
- can be used.
- Arguments:
- EchoCommands - Supplies a pointer where a boolean will be returned
- indicating if the debugger should echo commands received (TRUE) or if
- the console has already echoed the command (FALSE).
- Return Value:
- Returns TRUE on success, FALSE on failure.
- --*/
- {
- ULONG Index;
- ULONG Retries;
- *EchoCommands = TRUE;
- //
- // Wait for the UI to initialize.
- //
- Retries = 10;
- while (Retries != 0) {
- if (ConsoleInitialized != FALSE) {
- break;
- }
- Sleep(100);
- Retries -= 1;
- }
- //
- // If the UI timed out, fail.
- //
- if (Retries == 0) {
- return FALSE;
- }
- //
- // Disable commands from being sent.
- //
- SetFocus(GetDlgItem(DialogWindow, IDE_COMMAND));
- UiEnableCommands(FALSE);
- //
- // Create a lock to protect access to the stack data tree.
- //
- StackTreeLock = CreateDebuggerLock();
- if (StackTreeLock == NULL) {
- return FALSE;
- }
- //
- // Create a lock to protect access to the memory pool lists.
- //
- MemoryListLock = CreateDebuggerLock();
- if (MemoryListLock == NULL) {
- return FALSE;
- }
- //
- // Initialize the profiler timer references.
- //
- for (Index = 0; Index < ProfilerDataTypeMax; Index += 1) {
- ProfilerTimerTypes[Index] = FALSE;
- }
- return TRUE;
- }
- VOID
- DbgrOsDestroyConsole (
- VOID
- )
- /*++
- Routine Description:
- This routine cleans up anything related to console functionality as a
- debugger is exiting.
- Arguments:
- None.
- Return Value:
- None.
- --*/
- {
- if (StackTreeLock != NULL) {
- AcquireDebuggerLock(StackTreeLock);
- DbgrDestroyProfilerStackData(StackTreeRoot);
- ReleaseDebuggerLock(StackTreeLock);
- DestroyDebuggerLock(StackTreeLock);
- }
- if (MemoryListLock != NULL) {
- AcquireDebuggerLock(MemoryListLock);
- if (MemoryPoolListHead != MemoryBaseListHead) {
- DbgrDestroyProfilerMemoryData(MemoryBaseListHead);
- }
- DbgrDestroyProfilerMemoryData(MemoryPoolListHead);
- DbgrDestroyProfilerMemoryData(MemoryDeltaListHead);
- ReleaseDebuggerLock(MemoryListLock);
- DestroyDebuggerLock(MemoryListLock);
- }
- return;
- }
- VOID
- DbgrOsPrepareToReadInput (
- VOID
- )
- /*++
- Routine Description:
- This routine is called before the debugger begins to read a line of input
- from the user.
- Arguments:
- None.
- Return Value:
- None.
- --*/
- {
- return;
- }
- BOOL
- DbgrOsGetCharacter (
- PUCHAR Key,
- PUCHAR ControlKey
- )
- /*++
- Routine Description:
- This routine gets one character from the standard input console.
- Arguments:
- Key - Supplies a pointer that receives the printable character. If this
- parameter is NULL, printing characters will be discarded from the input
- buffer.
- ControlKey - Supplies a pointer that receives the non-printable character.
- If this parameter is NULL, non-printing characters will be discarded
- from the input buffer.
- Return Value:
- Returns TRUE on success, FALSE on failure.
- --*/
- {
- ULONG BytesRead;
- UCHAR Character;
- UCHAR ControlKeyValue;
- BOOL Result;
- ControlKeyValue = 0;
- while (TRUE) {
- Result = ReadFile(StdInPipeRead, &Character, 1, &BytesRead, NULL);
- if (Result == FALSE) {
- goto GetCharacterEnd;
- }
- if (BytesRead != 1) {
- continue;
- }
- //
- // If it's the magic escape character, look to see if it's a literal
- // escape or just a poke character since there's remote input.
- //
- if (Character == 0xFF) {
- Result = ReadFile(StdInPipeRead, &Character, 1, &BytesRead, NULL);
- if (Result == FALSE) {
- goto GetCharacterEnd;
- }
- if (BytesRead != 1) {
- DbgOut("Failed to read a second byte.\n");
- continue;
- }
- if (Character != 0xFF) {
- Character = 0;
- ControlKeyValue = KEY_REMOTE;
- }
- }
- break;
- }
- //
- // Handle non-printing characters.
- //
- if (Character == '\n') {
- Character = 0;
- ControlKeyValue = KEY_RETURN;
- }
- if ((Character == KEY_UP) || (Character == KEY_DOWN) ||
- (Character == KEY_ESCAPE)) {
- ControlKeyValue = Character;
- Character = 0;
- }
- Result = TRUE;
- GetCharacterEnd:
- if (Key != NULL) {
- *Key = Character;
- }
- if (ControlKey != NULL) {
- *ControlKey = ControlKeyValue;
- }
- return Result;
- }
- VOID
- DbgrOsRemoteInputAdded (
- VOID
- )
- /*++
- Routine Description:
- This routine is called after a remote command is received and placed on the
- standard input remote command list. It wakes up a thread blocked on local
- user input in an OS-dependent fashion.
- Arguments:
- None.
- Return Value:
- None.
- --*/
- {
- DWORD BytesWritten;
- unsigned char Message[2];
- //
- // Write the escaped "remote" sequence into the input pipe funnel.
- //
- Message[0] = 0xFF;
- Message[1] = 0x00;
- WriteFile(StdInPipeWrite,
- Message,
- sizeof(Message),
- &BytesWritten,
- NULL);
- return;
- }
- VOID
- DbgrOsPostInputCallback (
- VOID
- )
- /*++
- Routine Description:
- This routine is called after a line of input is read from the user, giving
- the OS specific code a chance to restore anything it did in the prepare
- to read input function.
- Arguments:
- None.
- Return Value:
- None.
- --*/
- {
- return;
- }
- BOOL
- UiLoadSourceFile (
- PSTR Path,
- PVOID Contents,
- ULONGLONG Size
- )
- /*++
- Routine Description:
- This routine loads the contents of a file into the source window.
- Arguments:
- Path - Supplies the path of the file being loaded. If this is NULL, then
- the source window should be cleared.
- Contents - Supplies the source file data. This can be NULL.
- Size - Supplies the size of the source file data in bytes.
- Return Value:
- Returns TRUE if there was no error, or FALSE if there was an error.
- --*/
- {
- BOOL Result;
- HWND RichEdit;
- HWND SourceFileEdit;
- INT TextLength;
- if (DialogWindow == NULL) {
- return FALSE;
- }
- Result = TRUE;
- RichEdit = GetDlgItem(DialogWindow, IDE_SOURCE_RICHEDIT);
- SourceFileEdit = GetDlgItem(DialogWindow, IDE_SOURCE_FILE);
- //
- // If NULL was passed in for the file name, just pass that along. This has
- // the effect of clearing the source window.
- //
- if (Path == NULL) {
- Result = LoadFileIntoRichEdit(RichEdit, NULL, NULL, 0);
- Edit_SetText(SourceFileEdit, "");
- goto LoadSourceFileEnd;
- }
- //
- // If the file is not already loaded, then load it.
- //
- Result = LoadFileIntoRichEdit(RichEdit, Path, Contents, Size);
- Edit_SetText(SourceFileEdit, Path);
- LoadSourceFileEnd:
- //
- // Point the cursor at the end of the text.
- //
- TextLength = Edit_GetTextLength(SourceFileEdit);
- Edit_SetSel(SourceFileEdit, TextLength, TextLength);
- return Result;
- }
- BOOL
- UiHighlightExecutingLine (
- LONG LineNumber,
- BOOL Enable
- )
- /*++
- Routine Description:
- This routine highlights the currently executing line and scrolls the source
- window to it, or restores a previously executing source line to the
- normal background color.
- Arguments:
- LineNumber - Supplies the 1-based line number to highlight (ie the first
- line in the source file is line 1).
- Enable - Supplies a flag indicating whether to highlight this line (TRUE)
- or restore the line to its original color (FALSE).
- Return Value:
- Returns TRUE if there was no error, or FALSE if there was an error.
- --*/
- {
- HWND RichEdit;
- if (DialogWindow == NULL) {
- return FALSE;
- }
- RichEdit = GetDlgItem(DialogWindow, IDE_SOURCE_RICHEDIT);
- if (Enable != FALSE) {
- HighlightLine(RichEdit, LineNumber, EXECUTING_COLOR, TRUE);
- } else {
- HighlightLine(RichEdit, LineNumber, BACKGROUND_COLOR, FALSE);
- }
- return TRUE;
- }
- VOID
- UiEnableCommands (
- BOOL Enable
- )
- /*++
- Routine Description:
- This routine enables or disables the command edit control from being
- enabled. If disabled, the edit control will be made read only.
- Arguments:
- Enable - Supplies a flag indicating whether or not to enable (TRUE) or
- disable (FALSE) the command box.
- Return Value:
- None.
- --*/
- {
- HWND CommandEdit;
- CommandEdit = GetDlgItem(DialogWindow, IDE_COMMAND);
- CommandsEnabled = Enable;
- if (Enable != FALSE) {
- SendMessage(CommandEdit, EM_SETREADONLY, (WPARAM)FALSE, 0);
- } else {
- SendMessage(CommandEdit, EM_SETREADONLY, (WPARAM)TRUE, 0);
- }
- return;
- }
- VOID
- UiSetCommandText (
- PSTR Text
- )
- /*++
- Routine Description:
- This routine sets the text inside the command edit box.
- Arguments:
- Text - Supplies a pointer to a null terminated string to set the command
- text to.
- Return Value:
- None.
- --*/
- {
- HWND CommandEdit;
- INT TextLength;
- CommandEdit = GetDlgItem(DialogWindow, IDE_COMMAND);
- Edit_SetText(CommandEdit, Text);
- //
- // Point the cursor at the end of the text.
- //
- TextLength = Edit_GetTextLength(CommandEdit);
- Edit_SetSel(CommandEdit, TextLength, TextLength);
- return;
- }
- DWORD
- CALLBACK
- RichEditLoadCallback (
- DWORD_PTR Context,
- LPBYTE Buffer,
- LONG Bytes,
- PLONG BytesComplete
- )
- /*++
- Routine Description:
- This routine is the callback function Windows uses to get input into the
- rich edit control. When a EM_STREAMIN message is processed, the OS calls
- this function repeatedly to get little chunks of data at a time to put into
- the rich edit control.
- Arguments:
- Context - Supplies a context pointer supplied by the user when the
- EM_STREAMIN message was passed.
- Buffer - Supplies a pointer to the OS created buffer to stream data into.
- Bytes - Supplies the number of bytes the OS wants this routine to put into
- the Buffer.
- BytesComplete - Supplies a pointer where the number of bytes actually
- written into the buffer by this function is returned.
- Return Value:
- Returns 0 on success, and nonzero on failure.
- --*/
- {
- ULONG BytesToTransfer;
- PSTREAM_IN_DATA StreamData;
- StreamData = (PSTREAM_IN_DATA)Context;
- //
- // If the caller didn't pass anything, just bail out now.
- //
- if (StreamData == NULL) {
- return -1;
- }
- if (StreamData->CurrentPosition + Bytes > StreamData->BufferSize) {
- BytesToTransfer = StreamData->BufferSize - StreamData->CurrentPosition;
- } else {
- BytesToTransfer = Bytes;
- }
- *BytesComplete = BytesToTransfer;
- //
- // If no bytes can be transferred, error out.
- //
- if (BytesToTransfer == 0) {
- return -1;
- }
- //
- // Some bytes can be copied, so do it and return success.
- //
- memcpy(Buffer,
- StreamData->Buffer + StreamData->CurrentPosition,
- BytesToTransfer);
- StreamData->CurrentPosition += BytesToTransfer;
- return 0;
- }
- VOID
- UiSetPromptText (
- PSTR Text
- )
- /*++
- Routine Description:
- This routine sets the text inside the prompt edit box.
- Arguments:
- Text - Supplies a pointer to a null terminated string to set the prompt
- text to.
- Return Value:
- None.
- --*/
- {
- HWND CommandEdit;
- CommandEdit = GetDlgItem(DialogWindow, IDE_PROMPT);
- Edit_SetText(CommandEdit, Text);
- return;
- }
- VOID
- UiDisplayProfilerData (
- PROFILER_DATA_TYPE DataType,
- PROFILER_DISPLAY_REQUEST DisplayRequest,
- ULONG Threshold
- )
- /*++
- Routine Description:
- This routine displays the profiler data collected by the core debugging
- infrastructure.
- Arguments:
- DataType - Supplies the type of profiler data that is to be displayed.
- DisplayRequest - Supplies a value requesting a display action, which can
- either be to display data once, continually, or to stop continually
- displaying data.
- Threshold - Supplies the minimum percentage a stack entry hit must be in
- order to be displayed.
- Return Value:
- None.
- --*/
- {
- BOOL DataDisplayed;
- HWND Profiler;
- //
- // Pause the profiler timer before taking any action. If the timer goes
- // off it will try to acquire one or more of the profiler locks, which
- // could deadlock with this routine trying to output to the main dialog
- // window.
- //
- PauseProfilerTimer();
- switch (DisplayRequest) {
- //
- // If the debugger requested a one-time display of the profiler data, try
- // to display the data.
- //
- case ProfilerDisplayOneTime:
- case ProfilerDisplayOneTimeThreshold:
- DataDisplayed = UpdateProfilerDisplay(DataType,
- DisplayRequest,
- Threshold);
- if (DataDisplayed == FALSE) {
- DbgOut("There was no new profiler data to display.\n");
- goto DisplayProfilerDataEnd;
- }
- //
- // If no threshold was supplied, it will get displayed in the GUI
- // window; make sure it is visible.
- //
- if (DisplayRequest == ProfilerDisplayOneTime) {
- UpdateProfilerWindowType(DialogWindow, DataType);
- }
- break;
- //
- // If a continuous display was requested, then set the timer for the given
- // type. Additionally, immediately display the data to give the user a good
- // response time since the timer doesn't fire until after the first period.
- //
- case ProfilerDisplayStart:
- UpdateProfilerDisplay(DataType, DisplayRequest, Threshold);
- SetProfilerTimer(DataType);
- break;
- //
- // If a stop was requested, kill the timer for the provided type, hiding
- // the profiler window for that type.
- //
- case ProfilerDisplayStop:
- KillProfilerTimer(DataType);
- break;
- //
- // Handle clear requests.
- //
- case ProfilerDisplayClear:
- //
- // The clear should only be requested for the stack profiler.
- //
- assert(DataType == ProfilerDataTypeStack);
- //
- // Erase the tree control and erase the previously collected stack data.
- //
- if (StackTreeRoot != NULL) {
- AcquireDebuggerLock(StackTreeLock);
- Profiler = GetDlgItem(DialogWindow, IDC_STACK_PROFILER);
- TreeView_DeleteItem(Profiler, (HTREEITEM)StackTreeRoot->UiHandle);
- DbgrDestroyProfilerStackData(StackTreeRoot);
- StackTreeRoot = NULL;
- ReleaseDebuggerLock(StackTreeLock);
- }
- break;
- case ProfilerDisplayStartDelta:
- //
- // The delta request should only be for the memory profiler.
- //
- assert(DataType == ProfilerDataTypeMemory);
- //
- // The delta start request always moves the most recent full statistics
- // to become the base statistics, destroying the old base statistics.
- // It also destroys the delta statistics, which can be released after
- // it wipes the list view from the screen..
- //
- AcquireDebuggerLock(MemoryListLock);
- Profiler = GetDlgItem(DialogWindow, IDC_MEMORY_PROFILER);
- ListView_DeleteAllItems(Profiler);
- DbgrDestroyProfilerMemoryData(MemoryDeltaListHead);
- MemoryDeltaListHead = NULL;
- DbgrDestroyProfilerMemoryData(MemoryBaseListHead);
- //
- // If there are no current statistics, collect them.
- //
- if (MemoryPoolListHead != NULL) {
- MemoryBaseListHead = MemoryPoolListHead;
- MemoryPoolListHead = NULL;
- } else {
- MemoryBaseListHead = NULL;
- DbgrGetProfilerMemoryData(&MemoryBaseListHead);
- }
- MemoryDeltaModeEnabled = TRUE;
- ReleaseDebuggerLock(MemoryListLock);
- //
- // Display the most recent data and make sure the timer is enabled.
- //
- UpdateProfilerDisplay(DataType, DisplayRequest, Threshold);
- SetProfilerTimer(DataType);
- break;
- case ProfilerDisplayStopDelta:
- //
- // The delta request should only be for the memory profiler.
- //
- assert(DataType == ProfilerDataTypeMemory);
- AcquireDebuggerLock(MemoryListLock);
- //
- // Do nothing if delta mode is not enabled.
- //
- if (MemoryDeltaModeEnabled == FALSE) {
- ReleaseDebuggerLock(MemoryListLock);
- break;
- }
- //
- // The delta stop request always destroys all the memory lists and sets
- // their pointers to NULL after clearing the display of all list items.
- // Note that delta mode stop does not disable the timer, it takes a
- // full stop command to stop the memory profiler.
- //
- Profiler = GetDlgItem(DialogWindow, IDC_MEMORY_PROFILER);
- ListView_DeleteAllItems(Profiler);
- DbgrDestroyProfilerMemoryData(MemoryDeltaListHead);
- MemoryDeltaListHead = NULL;
- DbgrDestroyProfilerMemoryData(MemoryBaseListHead);
- MemoryBaseListHead = NULL;
- DbgrDestroyProfilerMemoryData(MemoryPoolListHead);
- MemoryPoolListHead = NULL;
- MemoryDeltaModeEnabled = FALSE;
- ReleaseDebuggerLock(MemoryListLock);
- break;
- default:
- DbgOut("Error: Invalid profiler display request %d.\n", DisplayRequest);
- break;
- }
- DisplayProfilerDataEnd:
- //
- // Restart the profiler timer.
- //
- ResumeProfilerTimer();
- return;
- }
- //
- // --------------------------------------------------------- Internal Functions
- //
- DWORD
- WINAPI
- ConsoleStandardOutThread (
- LPVOID WindowHandle
- )
- /*++
- Routine Description:
- This routine is the worker thread that simply receives data from the
- standard out pipe and puts it in the command window.
- Arguments:
- WindowHandle - Supplies a pointer to the command window edit box.
- Return Value:
- 0 Always.
- --*/
- {
- CHAR Buffer[1024];
- ULONG BytesRead;
- BOOL Result;
- ULONG TextLength;
- HWND Window;
- Window = (HWND)WindowHandle;
- ConsoleInitialized = TRUE;
- while (TRUE) {
- //
- // Read data out of the stdout pipe.
- //
- Result = ReadFile(StdOutPipe,
- Buffer,
- sizeof(Buffer) - 1,
- &BytesRead,
- NULL);
- if (Result == FALSE) {
- break;
- }
- Buffer[BytesRead] = '\0';
- //
- // Send the character to the command window.
- //
- TextLength = GetWindowTextLength(Window);
- SendMessage(Window, EM_SETSEL, (WPARAM)TextLength, (LPARAM)TextLength);
- SendMessage(Window, EM_REPLACESEL, (WPARAM)FALSE, (LPARAM)Buffer);
- }
- return 0;
- }
- DWORD
- WINAPI
- UiThreadMain (
- LPVOID Parameter
- )
- /*++
- Routine Description:
- This routine is the startup routine for the UI thread.
- Arguments:
- Parameter - Supplies an unused parameter.
- Return Value:
- Returns 0 on success, or nonzero if there was an error.
- --*/
- {
- HACCEL Accelerators;
- HANDLE CommonControl;
- HANDLE CurrentInstance;
- PINITCOMMONCONTROLSEX InitCommonControlsEx;
- INITCOMMONCONTROLSEX InitControls;
- HICON LargeIcon;
- MSG Message;
- BOOL Result;
- HANDLE RichEditDll;
- HICON SmallIcon;
- HWND StackProfiler;
- //
- // Initialize globals.
- //
- DialogWindow = NULL;
- //
- // Load the rich edit DLL.
- //
- RichEditDll = LoadLibrary(TEXT("Riched20.dll"));
- if (RichEditDll == NULL) {
- DbgOut("Error: Unable to load riched20.dll! The source window will "
- "be unavailable.\n");
- return 0;
- }
- //
- // Load the common control DLL. This is used to create tree views.
- //
- CommonControl = LoadLibrary(TEXT("comctl32.dll"));
- if (CommonControl == NULL) {
- DbgOut("Error: Unable to load comctl32.dll! The source and profiler "
- "window will be unavailable.\n");
- return 0;
- }
- InitCommonControlsEx = (PINITCOMMONCONTROLSEX)GetProcAddress(
- CommonControl,
- TEXT("InitCommonControlsEx"));
- if (InitCommonControlsEx == NULL) {
- DbgOut("Error: Could not get the procedure address for "
- "InitCommonControlsEx.\n");
- return 0;
- }
- //
- // Initialize the common controls.
- //
- // N.B. Rumor has it that adding ICC_LISTVIEW_CLASSES to the initialization
- // flags prevents group views from working. It is omitted as a result.
- //
- InitControls.dwSize = sizeof(INITCOMMONCONTROLSEX);
- InitControls.dwICC = ICC_TREEVIEW_CLASSES;
- Result = InitCommonControlsEx(&InitControls);
- if (Result == FALSE) {
- DbgOut("InitCommonControlsEx failed\n");
- }
- //
- // Create the main source window. The DialogBox function will not return
- // until the dialog box has been closed, at which point the thread can
- // clean up and exit.
- //
- CurrentInstance = GetModuleHandle(NULL);
- Accelerators = LoadAccelerators(CurrentInstance,
- MAKEINTRESOURCE(IDD_ACCELERATORS));
- if (Accelerators == NULL) {
- DbgOut("Error: Could not load accelerators.\n");
- return 0;
- }
- DialogWindow = CreateDialog(CurrentInstance,
- MAKEINTRESOURCE(IDD_MAIN_WINDOW),
- NULL,
- MainDialogProc);
- //
- // TODO: Add support for break-at-cursor and goto-cursor
- //
- ShowWindow(GetDlgItem(DialogWindow, IDC_BREAK_CURSOR), SW_HIDE);
- ShowWindow(GetDlgItem(DialogWindow, IDC_GOTO_CURSOR), SW_HIDE);
- ShowWindow(DialogWindow, SW_SHOW);
- //
- // Load the application icons.
- //
- LargeIcon = LoadImage(CurrentInstance,
- MAKEINTRESOURCE(IDI_DEBUG_ICON),
- IMAGE_ICON,
- 32,
- 32,
- LR_DEFAULTSIZE);
- if (LargeIcon != NULL) {
- SendMessage(DialogWindow, WM_SETICON, ICON_BIG, (LPARAM)LargeIcon);
- }
- SmallIcon = LoadImage(CurrentInstance,
- MAKEINTRESOURCE(IDI_DEBUG_ICON),
- IMAGE_ICON,
- 16,
- 16,
- LR_DEFAULTSIZE);
- if (SmallIcon != NULL) {
- SendMessage(DialogWindow, WM_SETICON, ICON_SMALL, (LPARAM)SmallIcon);
- }
- //
- // Set focus on the input command box.
- //
- SetFocus(GetDlgItem(DialogWindow, IDE_COMMAND));
- //
- // Override the stack profiler's window message procedure call.
- //
- StackProfiler = GetDlgItem(DialogWindow, IDC_STACK_PROFILER);
- OriginalTreeViewWindowProcedure = (WNDPROC)SetWindowLong(
- StackProfiler,
- GWL_WNDPROC,
- (LONG)TreeViewWindowProcedure);
- //
- // Initialize the memory profiler list view control.
- //
- InitializeProfilerControls();
- //
- // Pump messages into the dialog processing function.
- //
- while (GetMessage(&Message, NULL, 0, 0) != FALSE) {
- if ((TranslateAccelerator(DialogWindow, Accelerators, &Message) == 0) &&
- (IsDialogMessage(DialogWindow, &Message) == FALSE)) {
- TranslateMessage(&Message);
- DispatchMessage(&Message);
- }
- }
- DialogWindow = NULL;
- FreeLibrary(CommonControl);
- FreeLibrary(RichEditDll);
- if (LargeIcon != NULL) {
- CloseHandle(LargeIcon);
- }
- if (SmallIcon != NULL) {
- CloseHandle(SmallIcon);
- }
- CloseHandle(StdInPipeWrite);
- exit(0);
- return 0;
- }
- INT_PTR
- CALLBACK
- MainDialogProc (
- HWND DialogHandle,
- UINT Message,
- WPARAM WParam,
- LPARAM LParam
- )
- /*++
- Routine Description:
- This routine is the main message pump for the source window. It receives
- messages pertaining to the window and handles interesting ones.
- Arguments:
- DialogHandle - Supplies the handle for the overall dialog window.
- Message - Supplies the message being sent to the window.
- WParam - Supplies the "width" parameter, basically the first parameter of
- the message.
- LParam - Supplies the "length" parameter, basically the second parameter of
- the message.
- Return Value:
- Returns TRUE if the message was handled, or FALSE if the message was not
- handled and the default handler should be invoked.
- --*/
- {
- RECT DialogRect;
- LONG NewDivider;
- CHARFORMAT2 NewFormat;
- HANDLE OutputThread;
- POINT Point;
- BOOL Result;
- HWND SourceEdit;
- RECT SourceRect;
- HWND StdOutEdit;
- RECT StdOutRect;
- Result = FALSE;
- switch (Message) {
- //
- // The WM_INITDIALOG message handles the initial dialog creation.
- //
- case WM_INITDIALOG:
- StdOutEdit = GetDlgItem(DialogHandle, IDE_STDOUT_RICHEDIT);
- SourceEdit = GetDlgItem(DialogHandle, IDE_SOURCE_RICHEDIT);
- //
- // Perform a sanity check to make sure the richedit control is there.
- //
- if ((StdOutEdit != NULL) && (SourceEdit != NULL)) {
- //
- // Set the text color, size, and font of the rich edit controls.
- // The Y height is the font's point size times twenty.
- //
- memset(&NewFormat, 0, sizeof(CHARFORMAT2));
- NewFormat.cbSize = sizeof(CHARFORMAT2);
- NewFormat.dwMask = CFM_FACE | CFM_SIZE;
- NewFormat.yHeight = 10 * 20;
- strcpy(NewFormat.szFaceName, "Courier");
- SendMessage(SourceEdit,
- EM_SETCHARFORMAT,
- (WPARAM)SCF_ALL,
- (LPARAM)&NewFormat);
- SendMessage(StdOutEdit,
- EM_SETCHARFORMAT,
- (WPARAM)SCF_ALL,
- (LPARAM)&NewFormat);
- //
- // Set the background color of the source area.
- //
- SendMessage(SourceEdit,
- EM_SETBKGNDCOLOR,
- (WPARAM)FALSE,
- (LPARAM)BACKGROUND_COLOR);
- //
- // Kick off the stdout thread.
- //
- OutputThread = CreateThread(NULL,
- 0,
- ConsoleStandardOutThread,
- StdOutEdit,
- 0,
- NULL);
- if (OutputThread == NULL) {
- DbgOut("Unable to create the output thread!\n");
- }
- }
- //
- // Position the elements in the window.
- //
- HandleResize(DialogHandle);
- UiLoadPreferences(DialogHandle);
- Result = TRUE;
- break;
- //
- // The WM_LBUTTONDOWN message is sent when the user clicks in the main
- // window.
- //
- case WM_LBUTTONDOWN:
- StdOutEdit = GetDlgItem(DialogHandle, IDE_STDOUT_RICHEDIT);
- SourceEdit = GetDlgItem(DialogHandle, IDE_SOURCE_RICHEDIT);
- GetWindowRect(StdOutEdit, &StdOutRect);
- GetWindowRect(SourceEdit, &SourceRect);
- MapWindowPoints(NULL,
- DialogHandle,
- (LPPOINT)&StdOutRect,
- sizeof(RECT) / sizeof(POINT));
- MapWindowPoints(NULL,
- DialogHandle,
- (LPPOINT)&SourceRect,
- sizeof(RECT) / sizeof(POINT));
- Point.x = LOWORD(LParam);
- Point.y = HIWORD(LParam);
- //
- // Check to see if the click happened between the two edit windows.
- //
- if ((Point.x >= (SourceRect.right - UI_MOUSE_PLAY)) &&
- (Point.x <= (StdOutRect.left + UI_MOUSE_PLAY))) {
- //
- // Capture mouse events.
- //
- SetCapture(DialogHandle);
- SetCursor(LoadCursor(NULL, IDC_SIZEWE));
- ResizingMainPanes = TRUE;
- //
- // Check to see if the click happened between the profiler window and
- // the source window.
- //
- } else if ((Point.y >= (SourceRect.bottom - UI_MOUSE_PLAY)) &&
- (Point.y <=
- (ProfilerPaneCurrentYPosition + UI_MOUSE_PLAY))) {
- SetCapture(DialogHandle);
- SetCursor(LoadCursor(NULL, IDC_SIZENS));
- ResizingProfilerPane = TRUE;
- }
- break;
- //
- // The WM_LBUTTONUP message is sent when the user releases the mouse in the
- // main window (or all mouse events are being captured).
- //
- case WM_LBUTTONUP:
- if ((ResizingMainPanes != FALSE) || (ResizingProfilerPane != FALSE)) {
- ReleaseCapture();
- SetCursor(LoadCursor(NULL, IDC_ARROW));
- ResizingProfilerPane = FALSE;
- ResizingMainPanes = FALSE;
- }
- break;
- //
- // The WM_MOUSEMOVE message is sent when the mouse moves within the window.
- //
- case WM_MOUSEMOVE:
- //
- // Don't do anything if the left button isn't also held down.
- //
- if (WParam != MK_LBUTTON) {
- break;
- }
- GetWindowRect(DialogHandle, &DialogRect);
- MapWindowPoints(NULL,
- DialogHandle,
- (LPPOINT)&DialogRect,
- sizeof(RECT) / sizeof(POINT));
- StdOutEdit = GetDlgItem(DialogHandle, IDE_STDOUT_RICHEDIT);
- SourceEdit = GetDlgItem(DialogHandle, IDE_SOURCE_RICHEDIT);
- GetWindowRect(StdOutEdit, &StdOutRect);
- MapWindowPoints(NULL,
- DialogHandle,
- (LPPOINT)&StdOutRect,
- sizeof(RECT) / sizeof(POINT));
- GetWindowRect(SourceEdit, &SourceRect);
- MapWindowPoints(NULL,
- DialogHandle,
- (LPPOINT)&SourceRect,
- sizeof(RECT) / sizeof(POINT));
- Point.x = LOWORD(LParam);
- Point.y = HIWORD(LParam);
- //
- // Resize the main panes if in the middle of that.
- //
- if (ResizingMainPanes != FALSE) {
- NewDivider = (SHORT)Point.x;
- MainPaneXPosition = NewDivider;
- MainPaneXPositionWidth = DialogRect.right;
- HandleResize(DialogHandle);
- } else if (ResizingProfilerPane != FALSE) {
- NewDivider = (SHORT)Point.y;
- ProfilerPaneYPosition = NewDivider;
- ProfilerPaneYPositionHeight = DialogRect.bottom;
- HandleResize(DialogHandle);
- }
- break;
- //
- // The WM_COMMAND message indicates that a button or keyboard accelerator
- // has been pressed.
- //
- case WM_COMMAND:
- HandleCommandMessage(DialogHandle, WParam);
- Result = TRUE;
- break;
- //
- // The WM_NOTIFY message indicates that a common control event has
- // occurred.
- //
- case WM_NOTIFY:
- HandleCommonControlMessage(DialogHandle, LParam);
- Result = TRUE;
- break;
- //
- // The WM_SIZE message indicates that the window was resized.
- //
- case WM_SIZE:
- HandleResize(DialogHandle);
- Result = TRUE;
- break;
- //
- // The WM_EXITSIZEMOVE message indicates that the window is done being
- // moved (dragged or resized).
- //
- case WM_EXITSIZEMOVE:
- UiGetWindowPreferences(DialogHandle);
- Result = TRUE;
- break;
- //
- // The program is exiting.
- //
- case WM_DESTROY:
- UiSavePreferences(DialogHandle);
- PostQuitMessage(0);
- Result = TRUE;
- break;
- }
- return Result;
- }
- LRESULT
- CALLBACK
- TreeViewWindowProcedure (
- HWND Window,
- UINT Message,
- WPARAM WParam,
- LPARAM LParam
- )
- /*++
- Routine Description:
- This routine handles window messages that are passed to the Tree View
- control.
- Arguments:
- Window - Supplies the handle for the Tree View window.
- Message - Supplies the message being sent to the window.
- WParam - Supplies the "width" parameter, basically the first parameter of
- the message.
- LParam - Supplies the "length" parameter, basically the second parameter of
- the message.
- Return Value:
- Returns TRUE if the message was handled, or FALSE if the message was not
- handled and the default handler should be invoked.
- --*/
- {
- LRESULT Result;
- switch (Message) {
- //
- // On key up or down, if the currently "selected" item is not visible, then
- // reselected it. This will snap it back into view.
- //
- case WM_KEYUP:
- case WM_KEYDOWN:
- if ((TreeViewSelection != NULL) &&
- (TreeViewIsTreeItemVisible(Window, TreeViewSelection) == FALSE)) {
- TreeView_SelectItem(Window, TreeViewSelection);
- TreeViewSelectionVisible = TRUE;
- }
- break;
- //
- // If the window is scrolled and the selected item goes out of view, then
- // deselect it. This makes updates smoother. If the scroll pulls the
- // selected item into view, then select it again.
- //
- case WM_VSCROLL:
- case WM_MOUSEWHEEL:
- if ((TreeViewSelection != NULL) &&
- (TreeViewIsTreeItemVisible(Window, TreeViewSelection) != FALSE)) {
- if (TreeViewSelectionVisible == FALSE) {
- TreeView_SelectItem(Window, TreeViewSelection);
- TreeViewSelectionVisible = TRUE;
- }
- } else {
- if (TreeViewSelectionVisible != FALSE) {
- TreeView_SelectItem(Window, NULL);
- TreeViewSelectionVisible = FALSE;
- }
- }
- break;
- default:
- break;
- }
- //
- // Always forwad the call on to the original window procedure call.
- //
- Result = CallWindowProc(OriginalTreeViewWindowProcedure,
- Window,
- Message,
- WParam,
- LParam);
- return Result;
- }
- BOOL
- LoadFileIntoRichEdit (
- HWND RichEdit,
- LPCTSTR Filename,
- PUCHAR FileBuffer,
- ULONGLONG FileSize
- )
- /*++
- Routine Description:
- This routine loads the contents of a file into the rich edit box.
- Arguments:
- RichEdit - Supplies the handle to the rich edit box.
- Filename - Supplies a NULL terminated string containing the name of the file
- to load.
- FileBuffer - Supplies a pointer to the file contents.
- FileSize - Supplies the size of the file contents in bytes.
- Return Value:
- Returns TRUE if there was no error, or FALSE if there was an error.
- --*/
- {
- EDITSTREAM EditStream;
- LRESULT Result;
- STREAM_IN_DATA StreamData;
- BOOL Success;
- memset(&StreamData, 0, sizeof(STREAM_IN_DATA));
- //
- // Highlight C-Style syntax and convert the text file into a rich text
- // formatted buffer.
- //
- Success = HighlightSyntax(FileBuffer,
- FileSize,
- &(StreamData.Buffer),
- &(StreamData.BufferSize));
- if (Success == FALSE) {
- goto LoadFileIntoRichEditEnd;
- }
- //
- // Set the maximum amount of rich text allowed in the control to twice the
- // buffer size. Without this message, the default is 32 kilobytes.
- //
- SendMessage(RichEdit,
- EM_EXLIMITTEXT,
- (WPARAM)0,
- (LPARAM)(StreamData.BufferSize * 2));
- //
- // Set up the EM_STREAMIN command by filling out the edit stream
- // context and callback function.
- //
- memset(&EditStream, 0, sizeof(EDITSTREAM));
- EditStream.pfnCallback = RichEditLoadCallback;
- EditStream.dwCookie = (DWORD_PTR)&StreamData;
- Result = SendMessage(RichEdit, EM_STREAMIN, SF_RTF, (LPARAM)&EditStream);
- if ((Result != 0) && (EditStream.dwError == 0)) {
- Success = TRUE;
- }
- LoadFileIntoRichEditEnd:
- //
- // If a failure occurred, clear the source window.
- //
- if (Success == FALSE) {
- EditStream.pfnCallback = RichEditLoadCallback;
- EditStream.dwCookie = (DWORD_PTR)NULL;
- SendMessage(RichEdit, EM_STREAMIN, SF_RTF, (LPARAM)&EditStream);
- }
- if (StreamData.Buffer != NULL) {
- free(StreamData.Buffer);
- }
- return Success;
- }
- BOOL
- HighlightSyntax (
- PUCHAR TextBuffer,
- ULONG TextBufferSize,
- PCHAR *BufferOut,
- PULONG FileSizeOut
- )
- /*++
- Routine Description:
- This routine takes in a text file and adds rich text formatting to perform
- C style syntax highlighting. The caller must remember to free memory
- allocated here.
- Arguments:
- TextBuffer - Supplies a pointer to text contents to highlight.
- TextBufferSize - Supplies the size of the text, in bytes.
- BufferOut - Supplies a pointer that receives a pointer to the rich text
- buffer. The caller must remember to free this buffer.
- FileSizeOut - Supplies a pointer that receives the size of the highlighted
- file. Note that the buffer may or may not be bigger than this value.
- Return Value:
- Returns TRUE if there was no error, or FALSE if there was an error.
- --*/
- {
- ULONG BytesOut;
- ULONG BytesReadIn;
- ULONG BytesToCopy;
- ULONG ColorChangeLength;
- PCHAR Destination;
- PCHAR FileBuffer;
- ULONG FileBufferSize;
- UCHAR FileByte;
- BOOL InDisabledCode;
- BOOL InDoubleQuotes;
- BOOL InMultiLineComment;
- BOOL InSingleLineComment;
- BOOL InSingleQuotes;
- CHAR Keyword[MAX_KEYWORD + 1];
- ULONG KeywordIndex;
- ULONG KeywordLength;
- PSTR KeywordStart;
- PSTR PoundIfStart;
- UCHAR PreviousCharacter;
- BOOL PreviousKeywordPoundIf;
- BOOL ResetColor;
- PCHAR Source;
- BOOL Success;
- BOOL WasBackslash;
- BytesOut = 0;
- BytesReadIn = 0;
- InDisabledCode = FALSE;
- InDoubleQuotes = FALSE;
- InSingleLineComment = FALSE;
- InSingleQuotes = FALSE;
- InMultiLineComment = FALSE;
- KeywordIndex = 0;
- KeywordStart = NULL;
- PoundIfStart = NULL;
- PreviousKeywordPoundIf = FALSE;
- Success = TRUE;
- WasBackslash = FALSE;
- *BufferOut = NULL;
- *FileSizeOut = 0;
- //
- // Allocate a buffer big enough to hold the original text file plus all the
- // formatting. Guess a size that should be big enough.
- //
- FileBufferSize = TextBufferSize * 5;
- if (FileBufferSize < strlen(RTF_HEADER) + strlen(RTF_FOOTER) + 8192) {
- FileBufferSize += strlen(RTF_HEADER) + strlen(RTF_FOOTER) + 8192;
- }
- FileBuffer = malloc(FileBufferSize);
- if (FileBuffer == NULL) {
- Success = FALSE;
- goto HighlightSyntaxEnd;
- }
- *BufferOut = FileBuffer;
- memset(Keyword, 0, MAX_KEYWORD + 1);
- //
- // Copy the RTF header.
- //
- memcpy(FileBuffer, RTF_HEADER, strlen(RTF_HEADER));
- FileBuffer += strlen(RTF_HEADER);
- BytesOut += strlen(RTF_HEADER);
- ResetColor = FALSE;
- PreviousCharacter = '\0';
- while (TRUE) {
- //
- // If the entire input file has been read, end the loop.
- //
- if (BytesReadIn == TextBufferSize) {
- break;
- }
- //
- // Get a byte from the input buffer.
- //
- FileByte = TextBuffer[BytesReadIn];
- BytesReadIn += 1;
- //
- // If this is a single quote, it's not preceded by a backslash, and
- // it's not in any other sort of comment or quote, toggle the single
- // line quote.
- //
- if ((FileByte == '\'') &&
- (WasBackslash == FALSE) &&
- (InSingleLineComment == FALSE) &&
- (InMultiLineComment == FALSE) &&
- (InDoubleQuotes == FALSE) &&
- (InDisabledCode == FALSE)) {
- if (InSingleQuotes == FALSE) {
- InSingleQuotes = TRUE;
- memcpy(FileBuffer, RTF_QUOTE, RTF_COLOR_SIZE);
- FileBuffer += RTF_COLOR_SIZE;
- BytesOut += RTF_COLOR_SIZE;
- } else {
- InSingleQuotes = FALSE;
- ResetColor = TRUE;
- }
- }
- //
- // If this is a double quote, it's not preceded by a backslash, and it's
- // not in any other sort of comment or quote, toggle the double line
- // quote.
- //
- if ((FileByte == '\"') &&
- (WasBackslash == FALSE) &&
- (InSingleLineComment == FALSE) &&
- (InMultiLineComment == FALSE) &&
- (InSingleQuotes == FALSE) &&
- (InDisabledCode == FALSE)) {
- if (InDoubleQuotes == FALSE) {
- InDoubleQuotes = TRUE;
- memcpy(FileBuffer, RTF_QUOTE, RTF_COLOR_SIZE);
- FileBuffer += RTF_COLOR_SIZE;
- BytesOut += RTF_COLOR_SIZE;
- } else {
- InDoubleQuotes = FALSE;
- ResetColor = TRUE;
- }
- }
- //
- // If this is a newline, end a single line comment now.
- //
- if ((InSingleLineComment != FALSE) &&
- (InMultiLineComment == FALSE) &&
- (InSingleQuotes == FALSE) &&
- (InDoubleQuotes == FALSE) &&
- (InDisabledCode == FALSE) &&
- ((FileByte == '\n') || (FileByte == '\r'))) {
- InSingleLineComment = FALSE;
- ResetColor = TRUE;
- }
- //
- // If this character is a / and so was the last one, this begins a
- // single line comment. Back up a character to apply the formatting, but
- // remember that the / got formatted as a divide sign, so there's a
- // plain text directive after the slash already which needs to be
- // backed out.
- //
- if ((InSingleLineComment == FALSE) &&
- (InMultiLineComment == FALSE) &&
- (InSingleQuotes == FALSE) &&
- (InDoubleQuotes == FALSE) &&
- (InDisabledCode == FALSE) &&
- (FileByte == '/') &&
- (PreviousCharacter == '/')) {
- FileBuffer -= RTF_COLOR_SIZE + 1;
- memcpy(FileBuffer, RTF_COMMENT, RTF_COLOR_SIZE);
- FileBuffer += RTF_COLOR_SIZE;
- BytesOut += RTF_COLOR_SIZE;
- *FileBuffer = '/';
- FileBuffer += 1;
- BytesOut -= RTF_COLOR_SIZE;
- InSingleLineComment = TRUE;
- }
- //
- // If another comment or quote is not in progress, check for the
- // beginning of a multiline comment. Back up to format the / as well,
- // but watch out for that plain text directive.
- //
- if ((FileByte == '*') &&
- (PreviousCharacter == '/') &&
- (InSingleLineComment == FALSE) &&
- (InSingleQuotes == FALSE) &&
- (InDoubleQuotes == FALSE) &&
- (InDisabledCode == FALSE)) {
- FileBuffer -= RTF_COLOR_SIZE + 1;
- memcpy(FileBuffer, RTF_COMMENT, RTF_COLOR_SIZE);
- FileBuffer += RTF_COLOR_SIZE;
- BytesOut += RTF_COLOR_SIZE;
- *FileBuffer = '/';
- FileBuffer += 1;
- BytesOut -= RTF_COLOR_SIZE;
- InMultiLineComment = TRUE;
- }
- //
- // Don't do syntax highlighting while inside a comment or quote.
- // *Do* go into this loop for disabled code to know when to get out of
- // disabled code.
- //
- if ((InSingleLineComment == FALSE) &&
- (InMultiLineComment == FALSE) &&
- (InSingleQuotes == FALSE) &&
- (InDoubleQuotes == FALSE)) {
- //
- // If this character marks the end of a keyword, evaluate the
- // keyword.
- //
- if (IsKeywordSeparator(FileByte) != FALSE) {
- //
- // End the keyword and compare against known keywords (or a
- // number).
- //
- Keyword[KeywordIndex] = '\0';
- //
- // If the current code is marked as disabled code, an #endif
- // ends that.
- //
- if ((InDisabledCode != FALSE) &&
- ((strcmp(Keyword, "#endif") == 0) ||
- (strcmp(Keyword, "#else") == 0))) {
- InDisabledCode = FALSE;
- ResetColor = TRUE;
- }
- //
- // If the keyword is a zero and the previous keyword was #if,
- // then its a "#if 0" disabling the code.
- //
- if ((PreviousKeywordPoundIf != FALSE) &&
- (strcmp(Keyword, "0") == 0)) {
- //
- // Copy the "#if 0" forward to make room for the color
- // change. Standard memory copy routines are not appropriate
- // here because the regions may be overlapping (which is
- // also the reason for copying backwards).
- //
- ColorChangeLength = RTF_COLOR_SIZE;
- KeywordLength = (ULONG)FileBuffer - (ULONG)PoundIfStart;
- Source = PoundIfStart + KeywordLength - 1;
- Destination = FileBuffer + ColorChangeLength - 1;
- BytesToCopy = KeywordLength;
- while (BytesToCopy != 0) {
- *Destination = *Source;
- Destination -= 1;
- Source -= 1;
- BytesToCopy -= 1;
- }
- InDisabledCode = TRUE;
- //
- // Copy the disabled code color into the text stream. Use
- // memcpy to avoid copying a null terminator over the data.
- //
- memcpy(PoundIfStart, RTF_DISABLED, ColorChangeLength);
- FileBuffer += ColorChangeLength;
- BytesOut += ColorChangeLength;
- }
- //
- // If it's #if, set that flag in preparation for a possible
- // 0 coming next.
- //
- if (strcmp(Keyword, "#if") == 0) {
- PreviousKeywordPoundIf = TRUE;
- PoundIfStart = KeywordStart;
- } else {
- PreviousKeywordPoundIf = FALSE;
- PoundIfStart = NULL;
- }
- //
- // Highlight the keyword if it's a number or C reserved keyword.
- // Don't highlight if in disabled code.
- //
- if ((InDisabledCode == FALSE) &&
- (((Keyword[0] >= '0') && (Keyword[0] <= '9')) ||
- (IsKeyword(Keyword) != FALSE))) {
- //
- // Copy the part of the buffer after the start of the
- // keyword forward to make room for the color change text.
- // Don't use standard routines because the regions may
- // overlap. It's okay to copy overlapping regions manually
- // because it's known that the destination comes after the
- // source, so as long as copying is done right-to-left, the
- // operation is safe.
- //
- ColorChangeLength = RTF_COLOR_SIZE;
- KeywordLength = strlen(Keyword);
- Destination = FileBuffer + ColorChangeLength - 1;
- Source = KeywordStart + KeywordLength - 1;
- BytesToCopy = KeywordLength;
- while (BytesToCopy != 0) {
- *Destination = *Source;
- Destination -= 1;
- Source -= 1;
- BytesToCopy -= 1;
- }
- //
- // Use memcpy instead of strcpy because the null terminator
- // that was that strcpy would write on the end would clobber
- // the data just shifted over.
- //
- memcpy(KeywordStart, RTF_KEYWORD, ColorChangeLength);
- FileBuffer += ColorChangeLength;
- BytesOut += ColorChangeLength;
- ResetColor = TRUE;
- }
- //
- // This was a keyword and it was just dealt with. Reset the
- // keyword contents and pointer.
- //
- KeywordIndex = 0;
- KeywordStart = NULL;
- //
- // This character is not a keyword separator. Save the new byte into
- // the current keyword, but only if there's room.
- //
- } else if (KeywordIndex < MAX_KEYWORD) {
- //
- // If this is the first character in the token, save the
- // position in the file buffer.
- //
- if (KeywordIndex == 0) {
- KeywordStart = FileBuffer;
- }
- Keyword[KeywordIndex] = FileByte;
- KeywordIndex += 1;
- }
- //
- // Handle single character highlights. Don't highlight disabled
- // code.
- //
- if (InDisabledCode == FALSE) {
- switch (FileByte) {
- //
- // Operators +, -, *, /, >, <, =, ., !, ^, &, |, :, ;, ~, %
- // should be highlighted with the constant color.
- //
- case '+':
- case '-':
- case '*':
- case '/':
- case '?':
- case '>':
- case '<':
- case '=':
- case '.':
- case '!':
- case '^':
- case '&':
- case '|':
- case ':':
- case ';':
- case '~':
- case '%':
- memcpy(FileBuffer, RTF_CONSTANT, RTF_COLOR_SIZE);
- FileBuffer += RTF_COLOR_SIZE;
- BytesOut += RTF_COLOR_SIZE;
- ResetColor = TRUE;
- break;
- //
- // Braces {}, [], and () should be highlighted with the brace
- // color.
- //
- case '(':
- case ')':
- case '[':
- case ']':
- case '{':
- case '}':
- memcpy(FileBuffer, RTF_BRACE, RTF_COLOR_SIZE);
- FileBuffer += RTF_COLOR_SIZE;
- BytesOut += RTF_COLOR_SIZE;
- ResetColor = TRUE;
- break;
- default:
- break;
- }
- }
- }
- //
- // New lines must be replaced by /par. The actual new line characters
- // seem to be ignored, so leave them in. Also reset the comment coloring
- // if inside a multi-line comment.
- //
- if (FileByte == '\n') {
- memcpy(FileBuffer, RTF_NEWLINE, RTF_NEWLINE_SIZE);
- FileBuffer += RTF_NEWLINE_SIZE;
- BytesOut += RTF_NEWLINE_SIZE;
- }
- //
- // The characters }, {, and \ have to be preceded by a \.
- //
- if ((FileByte == '{') || (FileByte == '}') || (FileByte == '\\')) {
- *FileBuffer = '\\';
- FileBuffer += 1;
- BytesOut += 1;
- }
- //
- // Copy the character from the file into the buffer.
- //
- if (FileByte != '\r') {
- *FileBuffer = FileByte;
- FileBuffer += 1;
- BytesOut += 1;
- }
- //
- // If this is a */, end a multiline comment now. This couldn't be
- // handled earlier because the / shouldn't be highlighted like a divide.
- //
- if ((InMultiLineComment != FALSE) &&
- (FileByte == '/') &&
- (PreviousCharacter == '*') &&
- (InSingleQuotes == FALSE) &&
- (InDoubleQuotes == FALSE) &&
- (InSingleLineComment == FALSE) &&
- (InDisabledCode == FALSE)) {
- InMultiLineComment = FALSE;
- ResetColor = TRUE;
- }
- PreviousCharacter = FileByte;
- //
- // Reset the color if something was highlighted but is finished now.
- //
- if (ResetColor != FALSE) {
- ResetColor = FALSE;
- memcpy(FileBuffer, RTF_PLAIN_TEXT, RTF_COLOR_SIZE);
- FileBuffer += RTF_COLOR_SIZE;
- BytesOut += RTF_COLOR_SIZE;
- }
- //
- // Remember if the previous character was a backslash.
- //
- if (FileByte == '\\') {
- if (WasBackslash == FALSE) {
- WasBackslash = TRUE;
- } else {
- WasBackslash = FALSE;
- }
- } else {
- WasBackslash = FALSE;
- }
- }
- //
- // Copy the footer, including the NULL terminator.
- //
- memcpy(FileBuffer, RTF_FOOTER, strlen(RTF_FOOTER) + 1);
- FileBuffer += strlen(RTF_FOOTER) + 1;
- BytesOut += strlen(RTF_FOOTER) + 1;
- //
- // Set the output size, and return.
- //
- *FileSizeOut = BytesOut;
- Success = TRUE;
- if (strlen(*BufferOut) + 1 != BytesOut) {
- DbgOut("ERROR: Not all bytes were accounted for. The rich text buffer "
- "is %d bytes, but only %d bytes were reported!\n",
- strlen(*BufferOut) + 1,
- BytesOut);
- }
- if (BytesOut >= FileBufferSize) {
- DbgOut("ERROR: The rich text buffer was %d bytes, but %d were used. "
- "The buffer was overrun!\n",
- FileBufferSize,
- BytesOut);
- assert(BytesOut < FileBufferSize);
- }
- #if 0
- DbgOut("File size: %d, File buffer size: %d, output file size: %d\n",
- TextBufferSize,
- FileBufferSize,
- BytesOut);
- #endif
- HighlightSyntaxEnd:
- if (Success == FALSE) {
- if (*BufferOut != NULL) {
- free(*BufferOut);
- }
- }
- return Success;
- }
- BOOL
- IsKeyword (
- PSTR String
- )
- /*++
- Routine Description:
- This routine determines whether or not the given character is a C reserved
- keyword.
- Arguments:
- String - Supplies the string containing the suspected keyword.
- Return Value:
- Returns TRUE if the keyword is a C reserved keyword. Returns FALSE if it is
- not a C reserved keyword.
- --*/
- {
- if ((strcmp("auto", String) == 0) ||
- (strcmp("do", String) == 0) ||
- (strcmp("for", String) == 0) ||
- (strcmp("return", String) == 0) ||
- (strcmp("typedef", String) == 0) ||
- (strcmp("break", String) == 0) ||
- (strcmp("double", String) == 0) ||
- (strcmp("goto", String) == 0) ||
- (strcmp("short", String) == 0) ||
- (strcmp("union", String) == 0) ||
- (strcmp("case", String) == 0) ||
- (strcmp("else", String) == 0) ||
- (strcmp("if", String) == 0) ||
- (strcmp("sizeof", String) == 0) ||
- (strcmp("unsigned", String) == 0) ||
- (strcmp("char", String) == 0) ||
- (strcmp("enum", String) == 0) ||
- (strcmp("int", String) == 0) ||
- (strcmp("static", String) == 0) ||
- (strcmp("void", String) == 0) ||
- (strcmp("continue", String) == 0) ||
- (strcmp("extern", String) == 0) ||
- (strcmp("long", String) == 0) ||
- (strcmp("struct", String) == 0) ||
- (strcmp("while", String) == 0) ||
- (strcmp("default", String) == 0) ||
- (strcmp("float", String) == 0) ||
- (strcmp("register", String) == 0) ||
- (strcmp("switch", String) == 0) ||
- (strcmp("const", String) == 0) ||
- (strcmp("signed", String) == 0) ||
- (strcmp("volatile", String) == 0)) {
- return TRUE;
- }
- return FALSE;
- }
- BOOL
- IsKeywordSeparator (
- UCHAR Character
- )
- /*++
- Routine Description:
- This routine determines whether or not the given character splits two
- keywords.
- Arguments:
- Character - Supplies the character to evaluate.
- Return Value:
- Returns TRUE if the character could not exist in a keyword, and marks the
- transition between two keywords. Returns FALSE if the character could be
- part of a normal token/keyword.
- --*/
- {
- switch (Character) {
- case ' ':
- case '\r':
- case '\n':
- case '\\':
- case ',':
- case '+':
- case '-':
- case '*':
- case '?':
- case '/':
- case '>':
- case '<':
- case '=':
- case '.':
- case '!':
- case '^':
- case '&':
- case '|':
- case ':':
- case ';':
- case '~':
- case '%':
- case '(':
- case ')':
- case '[':
- case ']':
- case '{':
- case '}':
- return TRUE;
- default:
- break;
- }
- return FALSE;
- }
- VOID
- HighlightLine (
- HWND RichEdit,
- LONG LineNumber,
- COLORREF Color,
- BOOL ScrollToLine
- )
- /*++
- Routine Description:
- This routine highlights or unhighlights a line in the currently loaded
- source file.
- Arguments:
- RichEdit - Supplies a handle to the rich edit control.
- LineNumber - Supplies the line number to change the background of. The first
- line in the file is line 1 (ie line numbers are 1 based).
- Color - Supplies the color to paint the background.
- ScrollToLine - Supplies a flag indicating whether or not the window should
- scroll to that line selection.
- Return Value:
- None.
- --*/
- {
- CHARFORMAT2 Format;
- LONG LineBegin;
- LONG LineEnd;
- ULONG OldSelectionBegin;
- ULONG OldSelectionEnd;
- //
- // Get the character index of the line to highlight. Subtract 1 because the
- // Rich Edit line numbers are zero based. Failure here indicates that the
- // line number is greater than the number of lines in the currently loaded
- // file.
- //
- LineBegin = SendMessage(RichEdit,
- EM_LINEINDEX,
- (WPARAM)(LineNumber - 1),
- (LPARAM)0);
- if (LineBegin == -1) {
- return;
- }
- //
- // Get the character index of the first character of the next line, to find
- // out where highlighting should end. Failure here is okay because -1
- // indicates the end of the file, which is correct for highlighting the
- // last line of the file.
- //
- LineEnd = SendMessage(RichEdit,
- EM_LINEINDEX,
- (WPARAM)LineNumber,
- (LPARAM)0);
- //
- // Get the current selection so it can be restored later.
- //
- if (ScrollToLine == FALSE) {
- SendMessage(RichEdit,
- EM_GETSEL,
- (WPARAM)(&OldSelectionBegin),
- (LPARAM)(&OldSelectionEnd));
- }
- //
- // Set the selection to the line about to be highlighted.
- //
- SendMessage(RichEdit,
- EM_SETSEL,
- (WPARAM)LineBegin,
- (LPARAM)LineEnd);
- //
- // Fill out a format structure indicating that the only valid field in the
- // structure is the background color, which is about to be changed.
- //
- memset(&Format, 0, sizeof(CHARFORMAT2));
- Format.cbSize = sizeof(CHARFORMAT2);
- Format.dwMask = CFM_BACKCOLOR;
- Format.crBackColor = Color;
- //
- // Send the message that actually sets the character formatting. Only format
- // the current selection.
- //
- SendMessage(RichEdit,
- EM_SETCHARFORMAT,
- (WPARAM)(SCF_SELECTION),
- (LPARAM)&Format);
- //
- // Restore the current selection if not scrolling to the line.
- //
- if (ScrollToLine == FALSE) {
- SendMessage(RichEdit,
- EM_SETSEL,
- (WPARAM)OldSelectionBegin,
- (LPARAM)OldSelectionEnd);
- //
- // Set the selection to the beginning of the line (but not highlighting the
- // line anymore), and scroll to the caret.
- //
- } else {
- SendMessage(RichEdit, EM_SETSEL, (WPARAM)LineBegin, (LPARAM)LineBegin);
- SendMessage(RichEdit, EM_SCROLLCARET, 0, 0);
- }
- return;
- }
- VOID
- HandleResize (
- HWND Dialog
- )
- /*++
- Routine Description:
- This routine handles scaling the UI elements when the dialog window is
- resized.
- Arguments:
- Dialog - Supplies the handle to the main dialog window.
- Return Value:
- None.
- --*/
- {
- LONG AdjustedMainPaneXPosition;
- LONG AdjustedProfilerPaneYPosition;
- HWND BreakAtCursorButton;
- HWND CommandEdit;
- RECT Control;
- ULONG DialogHeight;
- RECT DialogSize;
- ULONG DialogWidth;
- HWND GotoCursorButton;
- HWND MemoryToggle;
- HWND MemoryView;
- HWND OutputEdit;
- LONG PaneXPosition;
- HWND ProfilerView;
- LONG ProfilerYPosition;
- HWND PromptEdit;
- BOOL Result;
- HWND SourceEdit;
- HWND SourceFileEdit;
- HWND StackToggle;
- HWND StackView;
- //
- // Get handles to all UI elements that need to be adjusted.
- //
- BreakAtCursorButton = GetDlgItem(Dialog, IDC_BREAK_CURSOR);
- CommandEdit = GetDlgItem(Dialog, IDE_COMMAND);
- GotoCursorButton = GetDlgItem(Dialog, IDC_GOTO_CURSOR);
- MemoryToggle = GetDlgItem(Dialog, IDC_MEMORY_PROFILER_TOGGLE);
- MemoryView = GetDlgItem(Dialog, IDC_MEMORY_PROFILER);
- OutputEdit = GetDlgItem(Dialog, IDE_STDOUT_RICHEDIT);
- PromptEdit = GetDlgItem(Dialog, IDE_PROMPT);
- SourceEdit = GetDlgItem(Dialog, IDE_SOURCE_RICHEDIT);
- SourceFileEdit = GetDlgItem(Dialog, IDE_SOURCE_FILE);
- StackToggle = GetDlgItem(Dialog, IDC_STACK_PROFILER_TOGGLE);
- StackView = GetDlgItem(Dialog, IDC_STACK_PROFILER);
- //
- // Get the size of the dialog window (in dialog units) and conversion
- // factors.
- //
- Result = GetWindowRect(Dialog, &DialogSize);
- if (Result == FALSE) {
- DbgOut("Error: Unable to get dialog size.\n");
- }
- DialogWidth = DialogSize.right - DialogSize.left - 15;
- DialogHeight = DialogSize.bottom - DialogSize.top - 37;
- //
- // Initialize the window sizes to a default value if not done.
- //
- if (WindowSizesInitialized == FALSE) {
- MainPaneXPosition = (DialogWidth / 2) - (UI_BORDER / 2);
- MainPaneXPositionWidth = DialogWidth;
- ProfilerPaneYPosition = (DialogHeight / 2) + (UI_BORDER / 2);
- ProfilerPaneYPositionHeight = DialogHeight;
- WindowSizesInitialized = TRUE;
- }
- //
- // Scale the pane positions.
- //
- AdjustedMainPaneXPosition = MainPaneXPosition;
- if (AdjustedMainPaneXPosition < UI_BORDER - 1) {
- AdjustedMainPaneXPosition = UI_BORDER - 1;
- }
- if (AdjustedMainPaneXPosition > DialogWidth - UI_BORDER) {
- AdjustedMainPaneXPosition = DialogWidth - UI_BORDER;
- }
- AdjustedProfilerPaneYPosition = ProfilerPaneYPosition;
- if (AdjustedProfilerPaneYPosition < UI_BUTTON_HEIGHT + (2 * UI_BORDER)) {
- AdjustedProfilerPaneYPosition = UI_BUTTON_HEIGHT + (2 * UI_BORDER);
- }
- if (AdjustedProfilerPaneYPosition > DialogHeight - UI_BORDER) {
- AdjustedProfilerPaneYPosition = DialogHeight - UI_BORDER;
- }
- PaneXPosition = (AdjustedMainPaneXPosition * DialogWidth) /
- MainPaneXPositionWidth;
- ProfilerYPosition = (AdjustedProfilerPaneYPosition * DialogHeight) /
- ProfilerPaneYPositionHeight;
- ProfilerPaneCurrentYPosition = ProfilerYPosition;
- //
- // Resize the source and output edit controls to split the screen.
- //
- Control.left = UI_BORDER;
- Control.top = UI_BUTTON_HEIGHT + (2 * UI_BORDER);
- Control.right = PaneXPosition;
- if (ProfilerWindowType != ProfilerDataTypeMax) {
- Control.bottom = ProfilerYPosition - UI_BORDER;
- } else {
- Control.bottom = DialogHeight - UI_BORDER;
- }
- MoveWindow(SourceEdit,
- Control.left,
- Control.top,
- Control.right - Control.left,
- Control.bottom - Control.top,
- FALSE);
- Control.left = PaneXPosition + UI_BORDER;
- Control.top = UI_BUTTON_HEIGHT + (2 * UI_BORDER);
- Control.right = DialogWidth - UI_BORDER;
- Control.bottom = DialogHeight - (2 * UI_BORDER) - UI_BUTTON_HEIGHT;
- MoveWindow(OutputEdit,
- Control.left,
- Control.top,
- Control.right - Control.left,
- Control.bottom - Control.top,
- FALSE);
- //
- // Show or hide the correct profiler view depending on window state.
- //
- if (ProfilerWindowType != ProfilerDataTypeMax) {
- if (ProfilerWindowType == ProfilerDataTypeStack) {
- ProfilerView = StackView;
- ShowWindow(MemoryView, SW_HIDE);
- } else {
- assert(ProfilerWindowType == ProfilerDataTypeMemory);
- ProfilerView = MemoryView;
- ShowWindow(StackView, SW_HIDE);
- }
- Control.left = UI_BORDER;
- Control.top = ProfilerYPosition;
- Control.right = PaneXPosition;
- Control.bottom = DialogHeight - UI_BORDER;
- MoveWindow(ProfilerView,
- Control.left,
- Control.top,
- Control.right - Control.left,
- Control.bottom - Control.top,
- FALSE);
- ShowWindow(ProfilerView, SW_SHOW);
- } else {
- ShowWindow(StackView, SW_HIDE);
- ShowWindow(MemoryView, SW_HIDE);
- }
- //
- // Move the prompt and command controls.
- //
- Control.left = PaneXPosition + UI_BORDER;
- Control.top = DialogHeight - UI_BUTTON_HEIGHT - UI_BORDER;
- Control.right = Control.left + UI_PROMPT_WIDTH;
- Control.bottom = Control.top + UI_BUTTON_HEIGHT;
- MoveWindow(PromptEdit,
- Control.left,
- Control.top,
- Control.right - Control.left,
- Control.bottom - Control.top,
- FALSE);
- Control.left = PaneXPosition + (UI_BORDER * 2) + UI_PROMPT_WIDTH;
- Control.top = DialogHeight - UI_BUTTON_HEIGHT - UI_BORDER;
- Control.right = DialogWidth - UI_BORDER;
- Control.bottom = DialogHeight - UI_BORDER;
- MoveWindow(CommandEdit,
- Control.left,
- Control.top,
- Control.right - Control.left,
- Control.bottom - Control.top,
- FALSE);
- //
- // Move the source file edit and right buttons.
- //
- Control.left = UI_BORDER;
- Control.top = UI_BORDER;
- Control.right = PaneXPosition;
- Control.bottom = UI_BORDER + UI_BUTTON_HEIGHT;
- MoveWindow(SourceFileEdit,
- Control.left,
- Control.top,
- Control.right - Control.left,
- Control.bottom - Control.top,
- FALSE);
- Control.left = PaneXPosition + (3 * UI_LARGE_BUTTON_WIDTH) +
- (UI_BORDER * 4);
- Control.top = UI_BORDER;
- Control.right = Control.left + UI_LARGE_BUTTON_WIDTH;
- Control.bottom = Control.top + UI_BUTTON_HEIGHT;
- MoveWindow(GotoCursorButton,
- Control.left,
- Control.top,
- Control.right - Control.left,
- Control.bottom - Control.top,
- FALSE);
- Control.left = PaneXPosition + (2 * UI_LARGE_BUTTON_WIDTH) +
- (UI_BORDER * 3);
- Control.top = UI_BORDER;
- Control.right = Control.left + UI_LARGE_BUTTON_WIDTH;
- Control.bottom = Control.top + UI_BUTTON_HEIGHT;
- MoveWindow(BreakAtCursorButton,
- Control.left,
- Control.top,
- Control.right - Control.left,
- Control.bottom - Control.top,
- FALSE);
- //
- // Move the profiler elements.
- //
- Control.left = PaneXPosition + UI_LARGE_BUTTON_WIDTH + (UI_BORDER * 2);
- Control.top = UI_BORDER;
- Control.right = Control.left + UI_LARGE_BUTTON_WIDTH;
- Control.bottom = Control.top + UI_BUTTON_HEIGHT;
- MoveWindow(MemoryToggle,
- Control.left,
- Control.top,
- Control.right - Control.left,
- Control.bottom - Control.top,
- FALSE);
- Control.left = PaneXPosition + UI_BORDER;
- Control.top = UI_BORDER;
- Control.right = Control.left + UI_LARGE_BUTTON_WIDTH;
- Control.bottom = Control.top + UI_BUTTON_HEIGHT;
- MoveWindow(StackToggle,
- Control.left,
- Control.top,
- Control.right - Control.left,
- Control.bottom - Control.top,
- FALSE);
- //
- // Repaint the entire window.
- //
- RedrawWindow(Dialog, NULL, NULL, RDW_INVALIDATE | RDW_ERASE);
- return;
- }
- VOID
- HandleCommandMessage (
- HWND Dialog,
- WPARAM WParam
- )
- /*++
- Routine Description:
- This routine handles WM_COMMAND messages coming into the dialog box.
- Arguments:
- Dialog - Supplies the handle to the main dialog window.
- WParam - Supplies the W Parameter passed in with the message.
- Return Value:
- None.
- --*/
- {
- HWND CommandEdit;
- HWND Focus;
- CommandEdit = GetDlgItem(Dialog, IDE_COMMAND);
- switch (WParam & 0xFFFF) {
- //
- // Destroy the window if it was closed.
- //
- case IDCANCEL:
- DestroyWindow(Dialog);
- break;
- //
- // Control-B was pressed.
- //
- case IDA_CONTROL_B:
- DbgrRequestBreakIn();
- SetFocus(GetDlgItem(DialogWindow, IDE_COMMAND));
- break;
- //
- // Control-K was pressed.
- //
- case IDA_CONTROL_K:
- MessageBox(NULL, "Control K!", "Yippee!", MB_OK);
- break;
- //
- // Up was pressed.
- //
- case IDA_UP:
- Focus = GetFocus();
- if (Focus == CommandEdit) {
- WriteByteToInput(KEY_UP);
- } else {
- SendMessage(Focus, WM_KEYDOWN, VK_UP, 0);
- }
- break;
- //
- // Down was pressed.
- //
- case IDA_DOWN:
- Focus = GetFocus();
- if (Focus == CommandEdit) {
- WriteByteToInput(KEY_DOWN);
- } else {
- SendMessage(Focus, WM_KEYDOWN, VK_DOWN, 0);
- }
- break;
- //
- // Escape was pressed.
- //
- case IDA_ESCAPE:
- WriteByteToInput(KEY_ESCAPE);
- break;
- //
- // The toggle stack profiler view button was pressed.
- //
- case IDC_STACK_PROFILER_TOGGLE:
- if (ProfilerWindowType != ProfilerDataTypeStack) {
- UpdateProfilerWindowType(Dialog, ProfilerDataTypeStack);
- } else {
- UpdateProfilerWindowType(Dialog, ProfilerDataTypeMax);
- }
- break;
- //
- // The toggle memory profiler view button was pressed.
- //
- case IDC_MEMORY_PROFILER_TOGGLE:
- if (ProfilerWindowType != ProfilerDataTypeMemory) {
- UpdateProfilerWindowType(Dialog, ProfilerDataTypeMemory);
- } else {
- UpdateProfilerWindowType(Dialog, ProfilerDataTypeMax);
- }
- break;
- //
- // The OK button means the enter key was pressed on an edit box.
- //
- case IDOK:
- Focus = GetFocus();
- if (Focus == CommandEdit) {
- HandleCommandEnter(CommandEdit);
- }
- break;
- }
- return;
- }
- VOID
- HandleCommonControlMessage (
- HWND Dialog,
- LPARAM LParam
- )
- /*++
- Routine Description:
- This routine handles WM_NOTIFY messages coming into the dialog box.
- Arguments:
- Dialog - Supplies the handle to the main dialog window.
- LParam - Supplies the L Parameter passed in with the message.
- Return Value:
- None.
- --*/
- {
- LPNMHDR MessageHeader;
- MessageHeader = (LPNMHDR)LParam;
- switch (MessageHeader->idFrom) {
- case IDC_STACK_PROFILER:
- HandleProfilerTreeViewCommand(Dialog, LParam);
- break;
- case IDC_MEMORY_PROFILER:
- HandleProfilerListViewCommand(Dialog, LParam);
- break;
- default:
- break;
- }
- return;
- }
- VOID
- HandleCommandEnter (
- HWND CommandEdit
- )
- /*++
- Routine Description:
- This routine handles a command entered into the command edit box.
- Arguments:
- CommandEdit - Supplies a handle to the command edit box containing the
- command.
- Return Value:
- None.
- --*/
- {
- PCHAR Buffer;
- ULONG BytesWritten;
- PCHAR CurrentBuffer;
- BOOL Result;
- INT TextLength;
- Buffer = NULL;
- //
- // Do nothing if commands are not enabled.
- //
- if (CommandsEnabled == FALSE) {
- return;
- }
- //
- // Get the length of the text in the command control, allocate space,
- // and read in the control.
- //
- TextLength = Edit_GetTextLength(CommandEdit);
- if (TextLength < 0) {
- goto HandleCommandEnterEnd;
- }
- Buffer = malloc(TextLength + 1);
- if (Buffer == NULL) {
- goto HandleCommandEnterEnd;
- }
- Edit_GetText(CommandEdit, Buffer, TextLength + 1);
- //
- // Write the data into the pipe.
- //
- CurrentBuffer = Buffer;
- while (TextLength != 0) {
- Result = WriteFile(StdInPipeWrite,
- CurrentBuffer,
- TextLength,
- &BytesWritten,
- NULL);
- if (Result == FALSE) {
- goto HandleCommandEnterEnd;
- }
- CurrentBuffer += BytesWritten;
- TextLength -= BytesWritten;
- }
- //
- // Write the final newline into the pipe.
- //
- Buffer[0] = '\n';
- Result = WriteFile(StdInPipeWrite,
- Buffer,
- 1,
- &BytesWritten,
- NULL);
- if ((Result == FALSE) || (BytesWritten != 1)) {
- DbgOut("Error: final newline could not be sent.\n");
- goto HandleCommandEnterEnd;
- }
- HandleCommandEnterEnd:
- Edit_SetText(CommandEdit, "");
- if (Buffer != NULL) {
- free(Buffer);
- }
- return;
- }
- VOID
- WriteByteToInput (
- BYTE Byte
- )
- /*++
- Routine Description:
- This routine puts a byte of data into the standard input buffer.
- Arguments:
- Byte - Supplies the byte to insert into stdin.
- Return Value:
- None.
- --*/
- {
- ULONG BytesWritten;
- BOOL Result;
- Result = WriteFile(StdInPipeWrite,
- &Byte,
- 1,
- &BytesWritten,
- NULL);
- if ((Result == FALSE) || (BytesWritten != 1)) {
- DbgOut("Error: could not send byte to stdin.\n");
- }
- return;
- }
- VOID
- InitializeProfilerControls (
- VOID
- )
- /*++
- Routine Description:
- This routine initializes the controls used by the profiler.
- Arguments:
- None.
- Return Value:
- None.
- --*/
- {
- LPTSTR ColumnHeader;
- ULONG Index;
- LVCOLUMN ListViewColumn;
- HWND MemoryProfiler;
- MemoryProfiler = GetDlgItem(DialogWindow, IDC_MEMORY_PROFILER);
- //
- // Set full row select.
- //
- ListView_SetExtendedListViewStyle(MemoryProfiler, LVS_EX_FULLROWSELECT);
- //
- // Add the columns.
- //
- RtlZeroMemory(&ListViewColumn, sizeof(LVCOLUMN));
- ListViewColumn.mask = LVCF_TEXT | LVCF_FMT;
- ListViewColumn.fmt = LVCFMT_RIGHT;
- for (Index = 0; Index < MEMORY_STATISTICS_COLUMN_COUNT; Index += 1) {
- ColumnHeader = MemoryStatisticsColumns[Index].Header;
- ListViewColumn.pszText = ColumnHeader;
- ListViewColumn.cchTextMax = strlen(ColumnHeader) + 1;
- ListView_InsertColumn(MemoryProfiler, Index, &ListViewColumn);
- ListView_SetColumnWidth(MemoryProfiler,
- Index,
- LVSCW_AUTOSIZE_USEHEADER);
- }
- //
- // With all the columns width's now appropriately sized, reset the width of
- // the first column. Since it was the only column present when inserted, it
- // greedily consumed the whole control width before others were added.
- //
- ListView_SetColumnWidth(MemoryProfiler, 0, LVSCW_AUTOSIZE_USEHEADER);
- //
- // Enable group mode.
- //
- ListView_EnableGroupView(MemoryProfiler, TRUE);
- return;
- }
- VOID
- UpdateProfilerWindowType (
- HWND Dialog,
- PROFILER_DATA_TYPE DataType
- )
- /*++
- Routine Description:
- This routine updates the profiler window to show the data of the supplied
- type.
- Arguments:
- Dialog - Supplies the handle to the main dialog window.
- DataType - Supplies the type of profiler data whose profiler window should
- be shown.
- Return Value:
- None.
- --*/
- {
- ProfilerWindowType = DataType;
- HandleResize(Dialog);
- return;
- }
- VOID
- HandleProfilerTreeViewCommand (
- HWND Dialog,
- LPARAM LParam
- )
- /*++
- Routine Description:
- This routine handles tree view commands.
- Arguments:
- Dialog - Supplies a handle to the main dialog window.
- LParam - Supplies the L Parameter passed in with the message.
- Return Value:
- None.
- --*/
- {
- UINT Code;
- PSTACK_DATA_ENTRY StackData;
- LPNMTREEVIEW TreeView;
- Code = ((LPNMHDR)LParam)->code;
- switch (Code) {
- //
- // A tree item was selected.
- //
- case TVN_SELCHANGED:
- TreeView = (LPNMTREEVIEW)LParam;
- if (TreeView->itemNew.hItem == NULL) {
- break;
- }
- AcquireDebuggerLock(StackTreeLock);
- StackData = FindStackDataEntryByHandle(StackTreeRoot,
- TreeView->itemNew.hItem);
- ReleaseDebuggerLock(StackTreeLock);
- //
- // Save the selection.
- //
- TreeViewSelection = TreeView->itemNew.hItem;
- TreeViewSelectionVisible = TRUE;
- DbgrProfilerStackEntrySelected(StackData);
- break;
- default:
- break;
- }
- return;
- }
- PSTACK_DATA_ENTRY
- FindStackDataEntryByHandle (
- PSTACK_DATA_ENTRY Root,
- HTREEITEM Handle
- )
- /*++
- Routine Description:
- This routine searches the provided call stack tree to find the entry
- belonging to the given tree item handle.
- Arguments:
- Root - Supplies a pointer to the root entry of the call stack tree.
- Handle - Supplies the handle to be matched.
- Return Value:
- Returns a pointer to the call stack entry belonging to the given handle on
- success, or NULL on failure.
- --*/
- {
- PLIST_ENTRY CurrentEntry;
- PSTACK_DATA_ENTRY StackData;
- //
- // If the handle matches, return immediately.
- //
- if (Root->UiHandle == Handle) {
- return Root;
- }
- //
- // Recursively search all the children of the tree. Exit if any tree finds
- // a result.
- //
- CurrentEntry = Root->Children.Flink;
- while (CurrentEntry != &(Root->Children)) {
- StackData = CONTAINING_RECORD(CurrentEntry,
- STACK_DATA_ENTRY,
- SiblingEntry);
- StackData = FindStackDataEntryByHandle(StackData, Handle);
- if (StackData != NULL) {
- return StackData;
- }
- CurrentEntry = CurrentEntry->Flink;
- }
- return NULL;
- }
- VOID
- HandleProfilerListViewCommand (
- HWND Dialog,
- LPARAM LParam
- )
- /*++
- Routine Description:
- This routine handles list view commands.
- Arguments:
- Dialog - Supplies a handle to the main dialog window.
- LParam - Supplies the L Parameter passed in with the message.
- Return Value:
- None.
- --*/
- {
- UINT Code;
- LPNMLISTVIEW ListView;
- HWND MemoryProfiler;
- Code = ((LPNMHDR)LParam)->code;
- switch (Code) {
- //
- // A list view column was clicked.
- //
- case LVN_COLUMNCLICK:
- //
- // Prevent the list from updating during the sort operation as that can
- // result in incorrectly sorted columns.
- //
- AcquireDebuggerLock(MemoryListLock);
- ListView = (LPNMLISTVIEW)LParam;
- if (ListView->iSubItem == CurrentSortColumn) {
- if (SortAscending == FALSE) {
- SortAscending = TRUE;
- } else {
- SortAscending = FALSE;
- }
- } else {
- CurrentSortColumn = ListView->iSubItem;
- SortAscending = TRUE;
- }
- MemoryProfiler = GetDlgItem(Dialog, IDC_MEMORY_PROFILER);
- ListView_SortItems(MemoryProfiler, MemoryProfilerListViewCompare, 0);
- ReleaseDebuggerLock(MemoryListLock);
- break;
- default:
- break;
- }
- return;
- }
- VOID
- SetProfilerTimer (
- PROFILER_DATA_TYPE DataType
- )
- /*++
- Routine Description:
- This routine sets the profiler timer for the given profiler type and
- prepares the profiler window to display the data.
- Arguments:
- DataType - Supplies the profiler data type for which the timer should be
- set.
- Return Value:
- None.
- --*/
- {
- UINT_PTR Result;
- //
- // Set this profiler type's window to come to the front.
- //
- UpdateProfilerWindowType(DialogWindow, DataType);
- //
- // Make this data type update when the timer expires.
- //
- ProfilerTimerTypes[DataType] = TRUE;
- //
- // Set the timer. It's OK if the timer is already set.
- //
- Result = SetTimer(DialogWindow,
- PROFILER_TIMER_ID,
- PROFILER_TIMER_PERIOD,
- ProfilerTimerCallback);
- if (Result == 0) {
- DbgOut("Error: failed to set the profiler update timer.\n");
- }
- return;
- }
- VOID
- KillProfilerTimer (
- PROFILER_DATA_TYPE DataType
- )
- /*++
- Routine Description:
- This routine kills the profiler timer for the given profiler type and
- hides the data from the profiler window.
- Arguments:
- DataType - Supplies the profiler data type for which the timer should be
- set.
- Return Value:
- None.
- --*/
- {
- ULONG Index;
- BOOL TimerInUse;
- //
- // Disable this type for the timer callback.
- //
- ProfilerTimerTypes[DataType] = FALSE;
- //
- // Since this data type is no longer using the timer, determine if another
- // type is using the timer.
- //
- TimerInUse = FALSE;
- for (Index = 0; Index < ProfilerDataTypeMax; Index += 1) {
- if (ProfilerTimerTypes[Index] != 0) {
- TimerInUse = TRUE;
- break;
- }
- }
- //
- // If the timer is still in use, toggle the profiler window to show the
- // still running profiler data.
- //
- if (TimerInUse != FALSE) {
- UpdateProfilerWindowType(DialogWindow, Index);
- //
- // If the timer is not in use, kill it.
- //
- } else {
- KillTimer(DialogWindow, PROFILER_TIMER_ID);
- UpdateProfilerWindowType(DialogWindow, ProfilerDataTypeMax);
- }
- return;
- }
- VOID
- PauseProfilerTimer (
- VOID
- )
- /*++
- Routine Description:
- This routine pauses the profile timer.
- Arguments:
- None.
- Return Value:
- None.
- --*/
- {
- RECT DialogRect;
- ULONG Index;
- MSG Message;
- BOOL Result;
- BOOL TimerInUse;
- //
- // Determine if there is any work to be done.
- //
- TimerInUse = FALSE;
- for (Index = 0; Index < ProfilerDataTypeMax; Index += 1) {
- if (ProfilerTimerTypes[Index] != 0) {
- TimerInUse = TRUE;
- break;
- }
- }
- //
- // If the timer is enabled, then kill it and flush it.
- //
- if (TimerInUse != FALSE) {
- KillTimer(DialogWindow, PROFILER_TIMER_ID);
- RtlZeroMemory(&Message, sizeof(MSG));
- while (Message.message != WM_QUIT) {
- Result = PeekMessage(&Message,
- DialogWindow,
- WM_TIMER,
- WM_TIMER,
- PM_REMOVE);
- if (Result == FALSE) {
- break;
- }
- }
- //
- // Flush out any timer message that was in the middle of running by
- // calling a routine that generates a window message.
- //
- GetWindowRect(DialogWindow, &DialogRect);
- }
- return;
- }
- VOID
- ResumeProfilerTimer (
- VOID
- )
- /*++
- Routine Description:
- This routine resumes the profiler timer.
- Arguments:
- None.
- Return Value:
- None.
- --*/
- {
- ULONG Index;
- UINT_PTR Result;
- BOOL TimerInUse;
- //
- // Determine if any of the profile timers are in use.
- //
- TimerInUse = FALSE;
- for (Index = 0; Index < ProfilerDataTypeMax; Index += 1) {
- if (ProfilerTimerTypes[Index] != 0) {
- TimerInUse = TRUE;
- break;
- }
- }
- //
- // Set the timer. It's OK if the timer is already set.
- //
- if (TimerInUse != FALSE) {
- Result = SetTimer(DialogWindow,
- PROFILER_TIMER_ID,
- PROFILER_TIMER_PERIOD,
- ProfilerTimerCallback);
- if (Result == 0) {
- DbgOut("Error: failed to set the profiler update timer.\n");
- }
- }
- return;
- }
- VOID
- CALLBACK
- ProfilerTimerCallback (
- HWND DialogHandle,
- UINT Message,
- UINT_PTR EventId,
- DWORD Time
- )
- /*++
- Routine Description:
- This routine handles profiler timer callbacks.
- Arguments:
- DialogHandle - Supplies a handle to the window dialog associated with the
- timer.
- Message - Supplies the message associated with this callback. It should be
- the timer message.
- EventId - Supplies the ID of the callback event. It should be the profiler
- timer event ID.
- Time - Supplies the number of milliseconds that have elapsed since the
- system was started.
- Return Value:
- None.
- --*/
- {
- ULONG Index;
- assert(Message == WM_TIMER);
- assert(EventId == PROFILER_TIMER_ID);
- //
- // Update the display for every profiler type that is registered with the
- // timer.
- //
- for (Index = 0; Index < ProfilerDataTypeMax; Index += 1) {
- if (ProfilerTimerTypes[Index] != FALSE) {
- UpdateProfilerDisplay(Index, ProfilerDisplayOneTime, 0);
- }
- }
- return;
- }
- BOOL
- UpdateProfilerDisplay (
- PROFILER_DATA_TYPE DataType,
- PROFILER_DISPLAY_REQUEST DisplayRequest,
- ULONG Threshold
- )
- /*++
- Routine Description:
- This routine updates the profiler display. It collects the updated data
- from the common debugger code and then displays it.
- Arguments:
- DataType - Supplies the type of profiler data that is to be displayed.
- DisplayRequest - Supplies a value requesting a display action, which can
- either be to display data once, continually, or to stop continually
- displaying data.
- Threshold - Supplies the minimum percentage a stack entry hit must be in
- order to be displayed.
- Return Value:
- Returns TRUE if new data was display, or FALSE otherwise.
- --*/
- {
- PLIST_ENTRY PoolListHead;
- BOOL Result;
- PLIST_ENTRY ResultPoolListHead;
- BOOL StackTreeLockHeld;
- StackTreeLockHeld = FALSE;
- switch (DataType) {
- case ProfilerDataTypeStack:
- //
- // Acquire the stack tree lock to protect accesses between the profiler
- // timer, run on the UI thread, and console requests from the main
- // debugger thread.
- //
- AcquireDebuggerLock(StackTreeLock);
- StackTreeLockHeld = TRUE;
- //
- // Attempt to get the most up-to-date profiler data.
- //
- Result = DbgrGetProfilerStackData(&StackTreeRoot);
- if (Result == FALSE) {
- goto UpdateProfilerDisplayEnd;
- }
- //
- // If a threshold was specified, then print the stack contents to the
- // display console.
- //
- if (DisplayRequest == ProfilerDisplayOneTimeThreshold) {
- DbgrPrintProfilerStackData(StackTreeRoot, Threshold);
- //
- // Otherwise update the GUI stack tree display.
- //
- } else {
- UpdateCallStackTree(NULL, StackTreeRoot, StackTreeRoot->Count);
- }
- ReleaseDebuggerLock(StackTreeLock);
- StackTreeLockHeld = FALSE;
- break;
- case ProfilerDataTypeMemory:
- Result = DbgrGetProfilerMemoryData(&PoolListHead);
- if ((Result == FALSE) &&
- (DisplayRequest != ProfilerDisplayOneTimeThreshold)) {
- goto UpdateProfilerDisplayEnd;
- }
- //
- // If a threshold was specified, then print the memory contents to the
- // display console, using the saved data if nothing new was returned.
- //
- // N.B. This cannot delete any of the global lists because the UI is
- // still using them for sorting.
- //
- AcquireDebuggerLock(MemoryListLock);
- if (DisplayRequest == ProfilerDisplayOneTimeThreshold) {
- if (Result == FALSE) {
- PoolListHead = MemoryPoolListHead;
- }
- ResultPoolListHead = DbgrSubtractMemoryStatistics(
- PoolListHead,
- MemoryBaseListHead);
- DbgrPrintProfilerMemoryData(ResultPoolListHead,
- MemoryDeltaModeEnabled,
- Threshold);
- if (ResultPoolListHead != PoolListHead) {
- DbgrDestroyProfilerMemoryData(ResultPoolListHead);
- }
- if (PoolListHead != MemoryPoolListHead) {
- DbgrDestroyProfilerMemoryData(PoolListHead);
- }
- //
- // Otherwise update the GUI memory list view.
- //
- } else {
- UpdateMemoryStatisticsListView(PoolListHead);
- }
- ReleaseDebuggerLock(MemoryListLock);
- break;
- default:
- DbgOut("Error: invalid profiler data type %d.\n", DataType);
- break;
- }
- Result = TRUE;
- UpdateProfilerDisplayEnd:
- if (StackTreeLockHeld != FALSE) {
- ReleaseDebuggerLock(StackTreeLock);
- }
- return Result;
- }
- VOID
- UpdateCallStackTree (
- HTREEITEM Parent,
- PSTACK_DATA_ENTRY Root,
- ULONG TotalCount
- )
- /*++
- Routine Description:
- This routine updates the tree view for the provided call stack tree entry.
- It will either create a new element for this entry or update the count and
- text associated with the entry. It then operates on the entry's children.
- Once it completes the update of the children, it sorts the children based
- on their count and address.
- Arguments:
- Parent - Supplies a handle to the stack entry's parent tree view item.
- Root - Supplies a pointer to the root stack entry of this tree.
- TotalCount - Supplies the total number of stack traces observed.
- Return Value:
- None.
- --*/
- {
- PLIST_ENTRY CurrentEntry;
- PSTR FunctionString;
- LPTSTR ItemString;
- ULONG Percent;
- HWND Profiler;
- BOOL Result;
- LPTSTR ScratchString;
- TVSORTCB Sort;
- PSTACK_DATA_ENTRY StackData;
- HTREEITEM TreeItem;
- TV_INSERTSTRUCT TreeView;
- TVITEM UpdateItem;
- //
- // Return if the total count is zero. There is nothing to do.
- //
- if (TotalCount == 0) {
- return;
- }
- //
- // Calculate the percentage of stack traces in which this entry has been
- // observed.
- //
- Percent = (Root->Count * 100) / TotalCount;
- //
- // Get the symbol string associated with this stack entry. If there is no
- // parent, then it is the root.
- //
- if (Parent == NULL) {
- FunctionString = CALL_STACK_TREE_ROOT_STRING;
- } else {
- FunctionString = Root->AddressSymbol;
- }
- //
- // Get the string for this tree view item.
- //
- ItemString = GetFormattedMessageA("%1: %2!lu!%%, %3!lu!",
- FunctionString,
- Percent,
- Root->Count);
- if (ItemString == NULL) {
- DbgOut("Formatted message failed with status 0x%x\n", GetLastError());
- goto UpdateCallStackTreeEnd;
- }
- //
- // If the treeview item has never been created for this entry, then create
- // a treeview item, supplying display text and a pointer to the stack entry.
- //
- Profiler = GetDlgItem(DialogWindow, IDC_STACK_PROFILER);
- if (Root->UiHandle == NULL) {
- TreeView.hParent = Parent;
- TreeView.item.mask = TVIF_TEXT | TVIF_PARAM;
- TreeView.item.pszText = ItemString;
- TreeView.item.cchTextMax = strlen(ItemString) + 1;
- TreeView.item.lParam = (LONG_PTR)Root;
- TreeItem = TreeView_InsertItem(Profiler, &TreeView);
- if (TreeItem == NULL) {
- DbgOut("Failed to insert item: %s\n", ItemString);
- goto UpdateCallStackTreeEnd;
- }
- //
- // Save the tree item handle for future updates.
- //
- Root->UiHandle = TreeItem;
- //
- // If a treeview item exists, then update its text if necessary. The stack
- // entry should be the same.
- //
- } else {
- ScratchString = LocalAlloc(0, strlen(ItemString) + 1);
- if (ScratchString == NULL) {
- DbgOut("Failed to update item text: %s\n", ItemString);
- goto UpdateCallStackTreeEnd;
- }
- UpdateItem.mask = TVIF_TEXT;
- UpdateItem.pszText = ScratchString;
- UpdateItem.cchTextMax = strlen(ItemString) + 1;
- UpdateItem.hItem = Root->UiHandle;
- Result = TreeView_GetItem(Profiler, &UpdateItem);
- //
- // If the current text could not be retrieved or it does not match the
- // update text, then update the item.
- //
- if ((Result == FALSE) || (strcmp(ScratchString, ItemString) != 0)) {
- LocalFree(ScratchString);
- UpdateItem.mask = TVIF_TEXT;
- UpdateItem.pszText = ItemString;
- UpdateItem.cchTextMax = strlen(ItemString) + 1;
- UpdateItem.hItem = Root->UiHandle;
- Result = TreeView_SetItem(Profiler, &UpdateItem);
- if (Result == FALSE) {
- DbgOut("Failed to update item text %s\n", ItemString);
- goto UpdateCallStackTreeEnd;
- }
- } else {
- LocalFree(ScratchString);
- }
- TreeItem = Root->UiHandle;
- }
- //
- // Release the formatted message string. The insert and set calls above
- // cause the tree view to copy the string.
- //
- LocalFree(ItemString);
- ItemString = NULL;
- //
- // Update the child tree entries.
- //
- CurrentEntry = Root->Children.Flink;
- while (CurrentEntry != &(Root->Children)) {
- StackData = CONTAINING_RECORD(CurrentEntry,
- STACK_DATA_ENTRY,
- SiblingEntry);
- UpdateCallStackTree(TreeItem, StackData, TotalCount);
- CurrentEntry = CurrentEntry->Flink;
- }
- //
- // Since the children have been updated, sort them by hit count.
- //
- Sort.hParent = TreeItem;
- Sort.lpfnCompare = StackProfilerTreeCompare;
- Sort.lParam = 0;
- TreeView_SortChildrenCB(Profiler, &Sort, FALSE);
- UpdateCallStackTreeEnd:
- if (ItemString != NULL) {
- LocalFree(ItemString);
- }
- return;
- }
- INT
- CALLBACK
- StackProfilerTreeCompare (
- LPARAM LParamOne,
- LPARAM LParamTwo,
- LPARAM LParamSort
- )
- /*++
- Routine Description:
- This routine compares two profiler stack entries and determines the order
- in which they should be listed in the tree. This is used to sort a tree
- item's children.
- Arguments:
- LParamOne - Supplies a pointer to the stack data entry for the first tree
- item.
- LParamTwo - Supplies a pointer to the stack data entry for the second tree
- item.
- LParamSort - Supplies an unused parameter that is supplied by the parent
- whose children are being sorted.
- Return Value:
- Returns a negative value if the first stack entry should precede the second.
- Returns a positive value if the second stack entry should preced the first.
- --*/
- {
- PSTACK_DATA_ENTRY DataOne;
- PSTACK_DATA_ENTRY DataTwo;
- DataOne = (PSTACK_DATA_ENTRY)LParamOne;
- DataTwo = (PSTACK_DATA_ENTRY)LParamTwo;
- //
- // If the first entry's count is greater, return a negative number to
- // indicate that it should come first.
- //
- if (DataOne->Count > DataTwo->Count) {
- return -1;
- //
- // If the first entry's count is less, return a positive number to indicate
- // that it should come second.
- //
- } else if (DataOne->Count < DataTwo->Count) {
- return 1;
- //
- // If the counts are equal, then compare the entries' addresses. The lower
- // address comes first.
- //
- } else {
- if (DataOne->Address < DataTwo->Address) {
- return -1;
- }
- }
- return 1;
- }
- VOID
- UpdateMemoryStatisticsListView (
- PLIST_ENTRY PoolListHead
- )
- /*++
- Routine Description:
- This routine updates the memory statistics list view control with the
- newest data returned by the profiling target.
- Arguments:
- PoolListHead - Supplies a pointer to the head of the list of new memory
- pool data.
- Return Value:
- None.
- --*/
- {
- PLIST_ENTRY CurrentEntry;
- PLIST_ENTRY CurrentListHead;
- INT GroupId;
- ULONG Index;
- INT ListViewIndex;
- PPROFILER_MEMORY_POOL MemoryPool;
- PMEMORY_POOL_ENTRY MemoryPoolEntry;
- BOOL ReenableDeltaMode;
- BOOL Result;
- PPROFILER_MEMORY_POOL_TAG_STATISTIC Statistic;
- ULONG TagCount;
- //
- // Subtract the baseline memory statsitics from the current statistics.
- //
- CurrentListHead = DbgrSubtractMemoryStatistics(PoolListHead,
- MemoryBaseListHead);
- //
- // If the subtraction didn't go succeed, temporarily disable delta mode.
- //
- if ((CurrentListHead == PoolListHead) &&
- (MemoryDeltaModeEnabled != FALSE)) {
- MemoryDeltaModeEnabled = TRUE;
- ReenableDeltaMode = TRUE;
- } else {
- ReenableDeltaMode = FALSE;
- }
- //
- // Display the memory statistics for each memory pool.
- //
- CurrentEntry = CurrentListHead->Flink;
- while (CurrentEntry != CurrentListHead) {
- MemoryPoolEntry = CONTAINING_RECORD(CurrentEntry,
- MEMORY_POOL_ENTRY,
- ListEntry);
- CurrentEntry = CurrentEntry->Flink;
- //
- // Make sure the group exists for this memory pool. If a group does not
- // exist, create one.
- //
- MemoryPool = &(MemoryPoolEntry->MemoryPool);
- Result = DoesMemoryPoolListViewGroupExist(MemoryPool, &GroupId);
- if (Result == FALSE) {
- Result = CreateMemoryPoolListViewGroup(MemoryPool, &GroupId);
- if (Result == FALSE) {
- continue;
- }
- }
- //
- // Update the list view group based on the current memory pool data.
- //
- Result = UpdateMemoryPoolListViewGroup(MemoryPool, GroupId);
- if (Result == FALSE) {
- continue;
- }
- //
- // Create and update list view items for each tag in this memory pool.
- //
- TagCount = MemoryPoolEntry->MemoryPool.TagCount;
- for (Index = 0; Index < TagCount; Index += 1) {
- Statistic = &(MemoryPoolEntry->TagStatistics[Index]);
- //
- // If the subtraction above resulted in a tag with no deltas, then
- // do not display it.
- //
- if ((Statistic->ActiveSize == 0) &&
- (Statistic->ActiveAllocationCount == 0) &&
- (Statistic->LifetimeAllocationSize == 0) &&
- (Statistic->LargestAllocation == 0) &&
- (Statistic->LargestActiveAllocationCount == 0) &&
- (Statistic->LargestActiveSize == 0)) {
- //
- // If, however, the tag already exists, remove it!
- //
- Result = DoesMemoryPoolTagListViewItemExist(Statistic,
- GroupId,
- &ListViewIndex);
- if (Result != FALSE) {
- DeleteMemoryPoolTagListViewItem(ListViewIndex);
- }
- continue;
- }
- //
- // If there is not already a list view item for these tag
- // statistics, then create one.
- //
- Result = DoesMemoryPoolTagListViewItemExist(Statistic,
- GroupId,
- &ListViewIndex);
- if (Result == FALSE) {
- Result = CreateMemoryPoolTagListViewItem(Statistic->Tag,
- GroupId,
- &ListViewIndex);
- if (Result == FALSE) {
- continue;
- }
- }
- //
- // Update the list view item for the current tag statistics.
- //
- Result = UpdateMemoryPoolTagListViewItem(ListViewIndex,
- GroupId,
- Statistic);
- if (Result == FALSE) {
- continue;
- }
- }
- }
- //
- // Re-enable delta mode if necessary.
- //
- if (ReenableDeltaMode != FALSE) {
- MemoryDeltaModeEnabled = TRUE;
- }
- //
- // If delta mode is enabled, but no baseline has been established, use the
- // most recent data.
- //
- if ((MemoryDeltaModeEnabled != FALSE) && (MemoryBaseListHead == NULL)) {
- MemoryBaseListHead = PoolListHead;
- }
- //
- // Destroy the saved memory list unless it is acting as the base line list.
- //
- if (MemoryPoolListHead != MemoryBaseListHead) {
- DbgrDestroyProfilerMemoryData(MemoryPoolListHead);
- }
- //
- // Always save the newest pool list.
- //
- MemoryPoolListHead = PoolListHead;
- //
- // If the base list was subtracted from the pool list, then delete the old
- // delta list, saving the current list as the new delta list.
- //
- if (CurrentListHead != PoolListHead) {
- DbgrDestroyProfilerMemoryData(MemoryDeltaListHead);
- MemoryDeltaListHead = CurrentListHead;
- }
- return;
- }
- BOOL
- CreateMemoryPoolListViewGroup (
- PPROFILER_MEMORY_POOL MemoryPool,
- PINT GroupId
- )
- /*++
- Routine Description:
- This routine creates a new list view group for the given memory pool.
- Arguments:
- MemoryPool - Supplies a pointer to the memory pool for which the group will
- be created.
- GroupId - Supplies a pointer that receives the ID of the new group.
- Return Value:
- Returns TRUE on success, or FALSE on failure.
- --*/
- {
- LVGROUP Group;
- INT GroupIndex;
- LPWSTR HeaderString;
- HWND MemoryProfiler;
- BOOL Result;
- *GroupId = GetMemoryPoolGroupId(MemoryPool);
- //
- // Get the header string for this memory pool.
- //
- HeaderString = MemoryStatisticsPoolHeaders[MemoryPool->ProfilerMemoryType];
- //
- // Initialize the list view group, providing a group ID, state, and a
- // header. The header is based on the pool type.
- //
- RtlZeroMemory(&Group, sizeof(LVGROUP));
- Group.cbSize = sizeof(LVGROUP);
- Group.mask = LVGF_HEADER | LVGF_STATE | LVGF_GROUPID;
- Group.iGroupId = MemoryPool->ProfilerMemoryType;
- Group.pszHeader = HeaderString;
- Group.cchHeader = wcslen(HeaderString) + sizeof(WCHAR);
- Group.stateMask = LVGS_COLLAPSIBLE | LVGS_NORMAL;
- Group.state = LVGS_COLLAPSIBLE | LVGS_NORMAL;
- //
- // Insert the group into the memory profiler's list view.
- //
- Result = TRUE;
- MemoryProfiler = GetDlgItem(DialogWindow, IDC_MEMORY_PROFILER);
- GroupIndex = ListView_InsertGroup(MemoryProfiler, -1, &Group);
- if (GroupIndex == -1) {
- DbgOut("Error: failed to create memory group for pool type "
- "%d.\n",
- MemoryPool->ProfilerMemoryType);
- Result = FALSE;
- goto CreateMemoryPoolListViewGroupEnd;
- }
- *GroupId = GetMemoryPoolGroupId(MemoryPool);
- CreateMemoryPoolListViewGroupEnd:
- return Result;
- }
- BOOL
- DoesMemoryPoolListViewGroupExist (
- PPROFILER_MEMORY_POOL MemoryPool,
- PINT GroupId
- )
- /*++
- Routine Description:
- This routine returns whether or not a list view group already exists for
- the given memory pool. If it exists, then it returns the ID of the group.
- Arguments:
- MemoryPool - Supplies a pointer to the memory pool whose list view group
- status is to be tested.
- GroupId - Supplies a pointer that receives the ID of the memory pool group,
- if it exists.
- Return Value:
- Returns TRUE if a list view group exists for the memory pool, or FALSE if
- if does not.
- --*/
- {
- INT LocalGroupId;
- HWND MemoryProfiler;
- BOOL Result;
- //
- // Determine if there is already a group for this memory pool. The pool
- // memory type is used as the group ID.
- //
- LocalGroupId = GetMemoryPoolGroupId(MemoryPool);
- MemoryProfiler = GetDlgItem(DialogWindow, IDC_MEMORY_PROFILER);
- Result = ListView_HasGroup(MemoryProfiler, LocalGroupId);
- if (Result == FALSE) {
- return FALSE;
- }
- *GroupId = LocalGroupId;
- return TRUE;
- }
- BOOL
- UpdateMemoryPoolListViewGroup (
- PPROFILER_MEMORY_POOL MemoryPool,
- INT GroupId
- )
- /*++
- Routine Description:
- This routine updates the memory pool list view group for the given group ID
- with the given memory pool data.
- Arguments:
- MemoryPool - Supplies a pointer to the memory pool data to be used to
- update the list view group.
- GroupId - Supplies the ID of the list view group that is to be updated.
- Return Value:
- Returns TRUE on success, or FALSE on failure.
- --*/
- {
- ULONGLONG FreePercentage;
- LVGROUP Group;
- INT GroupIndex;
- LPWSTR GroupSubtitle;
- HWND MemoryProfiler;
- BOOL Result;
- //
- // Create the wide character string for the group's subtitle.
- //
- if (MemoryPool->TotalPoolSize != 0) {
- FreePercentage = MemoryPool->FreeListSize * 100;
- FreePercentage /= MemoryPool->TotalPoolSize;
- GroupSubtitle = GetFormattedMessageW(L"Size: %1!#I64x!, "
- L"Allocs: %2!I64u!, "
- L"Frees: %3!I64u!, "
- L"Failed: %4!I64u!, "
- L"Percent Free: %5!I64u!%%, "
- L"Free: %6!#I64x!",
- MemoryPool->TotalPoolSize,
- MemoryPool->TotalAllocationCalls,
- MemoryPool->TotalFreeCalls,
- MemoryPool->FailedAllocations,
- FreePercentage,
- MemoryPool->FreeListSize);
- } else {
- assert(MemoryPool->FreeListSize == 0);
- GroupSubtitle = GetFormattedMessageW(L"Size: -, "
- L"Allocs: %1!I64u!, "
- L"Frees: %2!I64u!, "
- L"Failed: %3!I64u!, "
- L"Percent Free: -, "
- L"Free: -",
- MemoryPool->TotalAllocationCalls,
- MemoryPool->TotalFreeCalls,
- MemoryPool->FailedAllocations);
- }
- if (GroupSubtitle == NULL) {
- DbgOut("Error: failed to create subtitle for group %d\n", GroupId);
- Result = FALSE;
- goto UpdateMemoryPoolListViewGroupEnd;
- }
- //
- // Initialize the group with the new subtitle.
- //
- Group.mask = LVGF_SUBTITLE;
- Group.cbSize = sizeof(LVGROUP);
- Group.pszSubtitle = GroupSubtitle;
- Group.cchSubtitle = wcslen(GroupSubtitle) + sizeof(WCHAR);
- //
- // Set the group information for the group with the given ID.
- //
- MemoryProfiler = GetDlgItem(DialogWindow, IDC_MEMORY_PROFILER);
- GroupIndex = ListView_SetGroupInfo(MemoryProfiler, GroupId, &Group);
- if (GroupIndex == -1) {
- DbgOut("Error: failed to update the subtitle for group %d.\n", GroupId);
- Result = FALSE;
- goto UpdateMemoryPoolListViewGroupEnd;
- }
- Result = TRUE;
- UpdateMemoryPoolListViewGroupEnd:
- if (GroupSubtitle == NULL) {
- LocalFree(GroupSubtitle);
- }
- return Result;
- }
- INT
- GetMemoryPoolGroupId (
- PPROFILER_MEMORY_POOL MemoryPool
- )
- /*++
- Routine Description:
- This routine gets the group ID for the given memory pool. This should
- return a unique value for each pool type.
- Arguments:
- MemoryPool - Supplies a pointer to the memory pool for which the group ID
- is to be returned.
- Return Value:
- Returns the group ID.
- --*/
- {
- //
- // The group ID is simply the memory pool type.
- //
- return MemoryPool->ProfilerMemoryType;
- }
- BOOL
- CreateMemoryPoolTagListViewItem (
- ULONG Tag,
- INT GroupId,
- PINT ItemIndex
- )
- /*++
- Routine Description:
- This routine creates a new item in the memory profiler's list view. The new
- item is added to the given group with the provided tag. The index of the
- item is return.
- Arguments:
- Tag - Supplies the pool tag of the new memory list item.
- GroupId - Supplies the ID of the group to which this item will belong.
- ItemIndex - Supplies a pointer that receives the list view index of the new
- item.
- Return Value:
- Returns TRUE on success, or FALSE on failure.
- --*/
- {
- INT Index;
- LPTSTR ItemString;
- LVITEM ListItem;
- HWND MemoryProfiler;
- BOOL Result;
- ItemString = GetFormattedMessageA("%1!c!%2!c!%3!c!%4!c!",
- (UCHAR)Tag,
- (UCHAR)(Tag >> 8),
- (UCHAR)(Tag >> 16),
- (UCHAR)(Tag >> 24));
- if (ItemString == NULL) {
- Result = FALSE;
- goto CreateNewListItemEnd;
- }
- //
- // Initialize the new list item to set the first column text and group ID.
- //
- RtlZeroMemory(&ListItem, sizeof(LVITEM));
- ListItem.mask = LVIF_TEXT | LVIF_GROUPID;
- ListItem.iItem = INT_MAX;
- ListItem.iSubItem = 0;
- ListItem.iGroupId = GroupId;
- ListItem.pszText = ItemString;
- ListItem.cchTextMax = strlen(ItemString) + 1;
- //
- // Insert the item in the list view.
- //
- MemoryProfiler = GetDlgItem(DialogWindow, IDC_MEMORY_PROFILER);
- Index = ListView_InsertItem(MemoryProfiler, &ListItem);
- if (Index == -1) {
- DbgOut("Error: failed to insert memory item: %s\n", ItemString);
- Result = FALSE;
- goto CreateNewListItemEnd;
- }
- //
- // Adjust the column width to make sure the new text fits.
- //
- ListView_SetColumnWidth(MemoryProfiler, 0, LVSCW_AUTOSIZE);
- *ItemIndex = Index;
- Result = TRUE;
- CreateNewListItemEnd:
- if (ItemString != NULL) {
- LocalFree(ItemString);
- }
- return Result;
- }
- VOID
- DeleteMemoryPoolTagListViewItem (
- INT ListViewIndex
- )
- /*++
- Routine Description:
- This routine deletes a single memory list view item at the given index.
- Arguments:
- ListViewIndex - Supplies the index of the list view item that is to be
- deleted.
- Return Value:
- None.
- --*/
- {
- HWND MemoryProfiler;
- MemoryProfiler = GetDlgItem(DialogWindow, IDC_MEMORY_PROFILER);
- ListView_DeleteItem(MemoryProfiler, ListViewIndex);
- return;
- }
- BOOL
- DoesMemoryPoolTagListViewItemExist (
- PPROFILER_MEMORY_POOL_TAG_STATISTIC Statistic,
- INT GroupId,
- PINT ListViewIndex
- )
- /*++
- Routine Description:
- This routine determines whether or not a list view item exists for the
- given tag statistic within the given group. If the list view item is found,
- then the routine returns the item's index.
- Arguments:
- Statistic - Supplies a pointer to the pool tag's statistics.
- GroupId - Supplies the ID of the group to which the list item belongs.
- ListViewIndex - Supplies a pointer that receives the index of the list view
- item if it is found.
- Return Value:
- Returns TRUE if a list view item does exist for the provided tag and group.
- Returns FALSE if no such list view item can be found.
- --*/
- {
- PLIST_ENTRY CurrentEntry;
- LVFINDINFO FindInformation;
- ULONG Index;
- LPARAM LParam;
- PMEMORY_POOL_ENTRY MemoryPoolEntry;
- HWND MemoryProfiler;
- INT PoolGroupId;
- PLIST_ENTRY PoolListHead;
- ULONG Tag;
- ULONG TagCount;
- INT ViewIndex;
- //
- // Determine which list to use. If no lists are available, then there is
- // nothing on the screen and no items exist, return FALSE.
- //
- if (MemoryDeltaListHead != NULL) {
- PoolListHead = MemoryDeltaListHead;
- } else if (MemoryPoolListHead != NULL) {
- PoolListHead = MemoryPoolListHead;
- } else {
- return FALSE;
- }
- //
- // Search through the previously displayed pool statistics for an entry
- // that has the same tag as the given statistics and the same group ID.
- //
- Tag = Statistic->Tag;
- CurrentEntry = PoolListHead->Flink;
- while (CurrentEntry != PoolListHead) {
- MemoryPoolEntry = CONTAINING_RECORD(CurrentEntry,
- MEMORY_POOL_ENTRY,
- ListEntry);
- //
- // Skip to the next memory pool if the group IDs do not match.
- //
- CurrentEntry = CurrentEntry->Flink;
- PoolGroupId = GetMemoryPoolGroupId(&(MemoryPoolEntry->MemoryPool));
- if (PoolGroupId != GroupId) {
- continue;
- }
- //
- // Search through the memory pool for the correct tag.
- //
- TagCount = MemoryPoolEntry->MemoryPool.TagCount;
- for (Index = 0; Index < TagCount; Index += 1) {
- //
- // If the tags are equal, try to find a list item with the LParam
- // for the current tag. The LParam is the pointer to the tag
- // statistic.
- //
- if (MemoryPoolEntry->TagStatistics[Index].Tag == Tag) {
- MemoryProfiler = GetDlgItem(DialogWindow, IDC_MEMORY_PROFILER);
- LParam = (LPARAM)&(MemoryPoolEntry->TagStatistics[Index]);
- RtlZeroMemory(&FindInformation, sizeof(LVFINDINFO));
- FindInformation.flags = LVFI_PARAM;
- FindInformation.lParam = LParam;
- ViewIndex = ListView_FindItem(MemoryProfiler,
- -1,
- &FindInformation);
- if (ViewIndex == -1) {
- return FALSE;
- } else {
- *ListViewIndex = ViewIndex;
- return TRUE;
- }
- }
- }
- }
- return FALSE;
- }
- BOOL
- UpdateMemoryPoolTagListViewItem (
- INT ItemIndex,
- INT GroupId,
- PPROFILER_MEMORY_POOL_TAG_STATISTIC Statistic
- )
- /*++
- Routine Description:
- This routine updates a memory list view item and the given index for the
- given group. The given statistics are used to update the columns for the
- item.
- Arguments:
- ItemIndex - Supplies the list view index of the item.
- GroupId - Supplies the ID of the group to which the item belongs.
- Statistic - Supplies the profiler memory statistics to use for updating the
- item.
- Return Value:
- Returns TRUE on success, or FALSE on failure.
- --*/
- {
- LPTSTR Format;
- PGETCOLUMNVALUE GetColumnValueRoutine;
- ULONG Index;
- LPTSTR ItemString;
- LVITEM ListItem;
- PMEMORY_COLUMN MemoryColumn;
- HWND MemoryProfiler;
- BOOL Result;
- ULONGLONG Value;
- //
- // Zero the list item and set any fields that will not change throughout
- // the duration of this routine.
- //
- ItemString = NULL;
- RtlZeroMemory(&ListItem, sizeof(LVITEM));
- ListItem.iItem = ItemIndex;
- ListItem.iGroupId = GroupId;
- //
- // Get the profiler memory window.
- //
- MemoryProfiler = GetDlgItem(DialogWindow, IDC_MEMORY_PROFILER);
- //
- // Update the LParam for the item to point to the latest statistics. This
- // is used when sorting on column clicks.
- //
- ListItem.mask = LVIF_PARAM;
- ListItem.iSubItem = 0;
- ListItem.lParam = (LPARAM)Statistic;
- Result = ListView_SetItem(MemoryProfiler, &ListItem);
- if (Result == FALSE) {
- DbgOut("Error: failed to set LParam for pool tag %c%c%c%c.\n",
- (UCHAR)Statistic->Tag,
- (UCHAR)(Statistic->Tag >> 8),
- (UCHAR)(Statistic->Tag >> 16),
- (UCHAR)(Statistic->Tag >> 24));
- goto UpdateListViewItemEnd;
- }
- //
- // Update the value of each subitem.
- //
- ListItem.mask = LVIF_TEXT;
- for (Index = 1; Index < MEMORY_STATISTICS_COLUMN_COUNT; Index += 1) {
- MemoryColumn = &(MemoryStatisticsColumns[Index]);
- //
- // Get the new string based on the size of the column and the format.
- // Skip the column is there is no data to display.
- //
- if (MemoryDeltaModeEnabled != FALSE) {
- Format = MemoryColumn->DeltaFormat;
- } else {
- Format = MemoryColumn->Format;
- }
- GetColumnValueRoutine = MemoryColumn->GetColumnValueRoutine;
- Value = GetColumnValueRoutine(Statistic, MemoryColumn->Offset);
- if ((MemoryBaseListHead != NULL) && (Value == 0)) {
- ListViewSetItemText(MemoryProfiler, ListItem.iItem, Index, "");
- continue;
- }
- ItemString = GetFormattedMessageA(Format, Value);
- if (ItemString == NULL) {
- Result = FALSE;
- DbgOut("Error: failed to allocate string for pool tag "
- "statistics.\n");
- goto UpdateListViewItemEnd;
- }
- //
- // Set the new string at the correct subitem index.
- //
- ListItem.iSubItem = Index;
- ListItem.pszText = ItemString;
- ListItem.cchTextMax = strlen(ItemString) + 1;
- Result = ListView_SetItem(MemoryProfiler, &ListItem);
- if (Result == FALSE) {
- DbgOut("Error: failed to insert memory subitem (%d, %d): %s\n",
- ItemIndex,
- Index,
- ItemString);
- goto UpdateListViewItemEnd;
- }
- LocalFree(ItemString);
- }
- UpdateListViewItemEnd:
- if (ItemString != NULL) {
- LocalFree(ItemString);
- }
- return Result;
- }
- INT
- CALLBACK
- MemoryProfilerListViewCompare (
- LPARAM LParamOne,
- LPARAM LParamTwo,
- LPARAM LParamSort
- )
- /*++
- Routine Description:
- This routine compares two memory profiler list view rows by the values in
- the column by which they are being sorted. It returns a negative value if
- the first parameter should be before the second, zero if they are equal,
- and a positive value if the first parameter should be after the second. It
- accounts for whether or not the sort is ascending or descending.
- Arguments:
- LParamOne - Supplies the LParam value for the first list item. This is a
- pointer to the item's memory statistics.
- LParamTwo - Supplies the LParam value for the second list item. This is a
- pointer to the item's memory statistics.
- LParamSort - Supplies an LParam value for the entire sort operation. This
- is not used.
- Return Value:
- Returns -1 if LParamOne should be before LParamTwo, 0 if they are equal,
- and 1 if LParamOne should be after LParamTwo.
- --*/
- {
- PNTDBGCOMPAREROUTINE CompareRoutine;
- PGETCOLUMNVALUE GetColumnValueRoutine;
- PMEMORY_COLUMN MemoryColumn;
- INT Result;
- PPROFILER_MEMORY_POOL_TAG_STATISTIC StatisticOne;
- PPROFILER_MEMORY_POOL_TAG_STATISTIC StatisticTwo;
- ULONGLONG ValueOne;
- ULONGLONG ValueTwo;
- assert(CurrentSortColumn < MEMORY_STATISTICS_COLUMN_COUNT);
- //
- // Compare the list view items based on the compare routine and field value
- // for the current sort column.
- //
- StatisticOne = (PPROFILER_MEMORY_POOL_TAG_STATISTIC)LParamOne;
- StatisticTwo = (PPROFILER_MEMORY_POOL_TAG_STATISTIC)LParamTwo;
- MemoryColumn = &(MemoryStatisticsColumns[CurrentSortColumn]);
- if (MemoryBaseListHead != NULL) {
- CompareRoutine = MemoryColumn->DeltaCompareRoutine;
- } else {
- CompareRoutine = MemoryColumn->CompareRoutine;
- }
- GetColumnValueRoutine = MemoryColumn->GetColumnValueRoutine;
- ValueOne = GetColumnValueRoutine(StatisticOne, MemoryColumn->Offset);
- ValueTwo = GetColumnValueRoutine(StatisticTwo, MemoryColumn->Offset);
- Result = CompareRoutine(ValueOne, ValueTwo);
- if (SortAscending == FALSE) {
- Result = 0 - Result;
- }
- return Result;
- }
- BOOL
- TreeViewIsTreeItemVisible (
- HWND TreeViewWindow,
- HTREEITEM TreeItem
- )
- /*++
- Routine Description:
- This routine determines whether or not the given tree item is currently
- visible in the provided Tree View window.
- Arguments:
- TreeViewWindow - Supplies a handle to a Tree View window.
- TreeItem - Supplies a handle to a tree item.
- Return Value:
- Returns TRUE if the tree item is visible in the window, or FALSE otherwise.
- --*/
- {
- HTREEITEM FirstVisible;
- RECT FirstVisibleRect;
- INT ItemHeight;
- BOOL Result;
- RECT TreeItemRect;
- LONG VisibleBottom;
- UINT VisibleCount;
- if (TreeItem == NULL) {
- return FALSE;
- }
- //
- // If the given tree item is the first visible, then the job is simple. If
- // not, then the position the the item needs to be analyzed.
- //
- FirstVisible = TreeView_GetFirstVisible(TreeViewWindow);
- if (FirstVisible == NULL) {
- return FALSE;
- }
- if (FirstVisible == TreeItem) {
- return TRUE;
- }
- //
- // Get the current position of the first visible item, the give tree item,
- // and calculate the bottom of the visible items. Oddly,
- // TreeView_GetLastVisible does not return the last visible item. It just
- // returns the last expanded item.
- //
- ItemHeight = TreeView_GetItemHeight(TreeViewWindow);
- VisibleCount = TreeView_GetVisibleCount(TreeViewWindow);
- Result = TreeViewGetItemRect(TreeViewWindow,
- TreeItem,
- &TreeItemRect,
- FALSE);
- if (Result == FALSE) {
- return FALSE;
- }
- Result = TreeViewGetItemRect(TreeViewWindow,
- FirstVisible,
- &FirstVisibleRect,
- FALSE);
- if (Result == FALSE) {
- return FALSE;
- }
- //
- // Compare the values to see if the given tree item is in or out of view.
- //
- VisibleBottom = (ItemHeight * VisibleCount) + FirstVisibleRect.top;
- if ((TreeItemRect.top < FirstVisibleRect.top) ||
- (TreeItemRect.bottom > VisibleBottom)) {
- return FALSE;
- }
- return TRUE;
- }
- BOOL
- TreeViewGetItemRect (
- HWND Window,
- HTREEITEM Item,
- LPRECT Rect,
- BOOL ItemRect
- )
- /*++
- Routine Description:
- This routine retrieves the bounding rectangle for a tree-view item and
- indicates whether the item is visible.
- Arguments:
- Window - Supplies the window handle to the tree-view control.
- Item - Supplies the handle to the tree-view item.
- Rect - Supplies a pointer to the rect structure that receives the bounding
- rectangle. The coordinates are relative to the upper-left corner of
- the tree-view control.
- ItemRect - Supplies a boolean indicating whether the bounding rectangle
- includes only the text of the item (TRUE) or the entire line the item
- occupies in the tree view (FALSE).
- Return Value:
- TRUE on success.
- FALSE on failure.
- --*/
- {
- //
- // The input to the message is in the same parameter as the output
- // rectangle. Don't use the commctrl.h macro as it violates strict-aliasing
- // rules.
- //
- memcpy(Rect, Item, sizeof(HTREEITEM));
- return SendMessage(Window, TVM_GETITEMRECT, ItemRect, (LPARAM)Rect);
- }
- LPTSTR
- GetFormattedMessageA (
- LPTSTR Message,
- ...
- )
- /*++
- Routine Description:
- This routine takes a formatted message string with an argument list and
- returns the expanded message string. This routine operates on ASCII
- strings.
- Arguments:
- Message - Supplies a pointer to a formatted message string.
- ... - Supplies any arguments needed to conver the formatted string.
- Return Value:
- Returns a pointer to the expanded message string.
- --*/
- {
- va_list ArgumentList;
- LPTSTR Buffer;
- Buffer = NULL;
- ArgumentList = NULL;
- va_start(ArgumentList, Message);
- FormatMessage(FORMAT_MESSAGE_FROM_STRING |
- FORMAT_MESSAGE_ALLOCATE_BUFFER,
- Message,
- 0,
- 0,
- (LPTSTR)&Buffer,
- 0,
- &ArgumentList);
- va_end(ArgumentList);
- return Buffer;
- }
- LPWSTR
- GetFormattedMessageW (
- LPWSTR Message,
- ...
- )
- /*++
- Routine Description:
- This routine takes a formatted message string with an argument list and
- returns the expanded message string. This routine operates on UNICODE wide
- character strings.
- Arguments:
- Message - Supplies a pointer to a formatted message string.
- ... - Supplies any arguments needed to conver the formatted string.
- Return Value:
- Returns a pointer to the expanded message string.
- --*/
- {
- va_list ArgumentList;
- LPWSTR Buffer;
- Buffer = NULL;
- ArgumentList = NULL;
- va_start(ArgumentList, Message);
- FormatMessageW(FORMAT_MESSAGE_FROM_STRING |
- FORMAT_MESSAGE_ALLOCATE_BUFFER,
- Message,
- 0,
- 0,
- (LPWSTR)&Buffer,
- 0,
- &ArgumentList);
- va_end(ArgumentList);
- return Buffer;
- }
- VOID
- ListViewSetItemText (
- HWND Window,
- int Item,
- int SubItem,
- LPTSTR Text
- )
- /*++
- Routine Description:
- This routine changes the text of a list-view item or subitem.
- Arguments:
- Window - Supplies the window handle to the list-view control.
- Item - Supplies the zero-based index of the list-view item.
- SubItem - Supplies the one-based index of the subitem. To set the item
- label, supply zero here.
- Text - Supplies a pointer to a null-terminated string containing the new
- text. This parameter can be LPSTR_TEXTCALLBACK to indicate a callback
- item for which the parent window stores the text. This parameter can
- be NULL.
- Return Value:
- None.
- --*/
- {
- ListView_SetItemText(Window, Item, SubItem, Text);
- return;
- }
- INT
- ComparePoolTag (
- ULONGLONG ValueOne,
- ULONGLONG ValueTwo
- )
- /*++
- Routine Description:
- This routine compares two pool tag values. It is given the numeric value of
- the pool tags, converts them to a string of four characters and the
- compares them alphabeticall, ignoring case.
- Arguments:
- ValueOne - Supplies the numeric value of the first pool tag to compare.
- ValueTwo - Supplies the numeric value of the second pool tag to compare.
- Return Value:
- Returns -1 if ValueOne is less than ValueTwo, 0 if they are equal, and 1
- if ValueOne is greater than ValueTwo.
- --*/
- {
- INT Result;
- CHAR TagOne[5];
- CHAR TagTwo[5];
- sprintf(TagOne,
- "%c%c%c%c",
- (UCHAR)ValueOne,
- (UCHAR)(ValueOne >> 8),
- (UCHAR)(ValueOne >> 16),
- (UCHAR)(ValueOne >> 24));
- sprintf(TagTwo,
- "%c%c%c%c",
- (UCHAR)ValueTwo,
- (UCHAR)(ValueTwo >> 8),
- (UCHAR)(ValueTwo >> 16),
- (UCHAR)(ValueTwo >> 24));
- Result = strcasecmp(TagOne, TagTwo);
- if (Result < 0) {
- Result = -1;
- } else if (Result > 0) {
- Result = 1;
- } else {
- Result = 0;
- }
- return Result;
- }
- INT
- CompareUlong (
- ULONGLONG ValueOne,
- ULONGLONG ValueTwo
- )
- /*++
- Routine Description:
- This routine compares two ULONG values, casting the input parameters to
- ULONGs.
- Arguments:
- ValueOne - Supplies the first ULONG to compare.
- ValueTwo - Supplies the second ULONG to compare.
- Return Value:
- Returns -1 if ValueOne is less than ValueTwo, 0 if they are equal, and 1
- if ValueOne is greater than ValueTwo.
- --*/
- {
- INT Result;
- if ((ULONG)ValueOne < (ULONG)ValueTwo) {
- Result = -1;
- } else if ((ULONG)ValueOne == (ULONG)ValueTwo) {
- Result = 0;
- } else {
- Result = 1;
- }
- return Result;
- }
- INT
- CompareLong (
- ULONGLONG ValueOne,
- ULONGLONG ValueTwo
- )
- /*++
- Routine Description:
- This routine compares two LONG values, casting the input parameters to
- LONGs.
- Arguments:
- ValueOne - Supplies the first LONG to compare.
- ValueTwo - Supplies the second LONG to compare.
- Return Value:
- Returns -1 if ValueOne is less than ValueTwo, 0 if they are equal, and 1
- if ValueOne is greater than ValueTwo.
- --*/
- {
- INT Result;
- if ((LONG)ValueOne < (LONG)ValueTwo) {
- Result = -1;
- } else if ((LONG)ValueOne == (LONG)ValueTwo) {
- Result = 0;
- } else {
- Result = 1;
- }
- return Result;
- }
- INT
- CompareUlonglong (
- ULONGLONG ValueOne,
- ULONGLONG ValueTwo
- )
- /*++
- Routine Description:
- This routine compares two ULONGLONG values.
- Arguments:
- ValueOne - Supplies the first ULONGLONG to compare.
- ValueTwo - Supplies the second ULONGLONG to compare.
- Return Value:
- Returns -1 if ValueOne is less than ValueTwo, 0 if they are equal, and 1
- if ValueOne is greater than ValueTwo.
- --*/
- {
- INT Result;
- if (ValueOne < ValueTwo) {
- Result = -1;
- } else if (ValueOne == ValueTwo) {
- Result = 0;
- } else {
- Result = 1;
- }
- return Result;
- }
- INT
- CompareLonglong (
- ULONGLONG ValueOne,
- ULONGLONG ValueTwo
- )
- /*++
- Routine Description:
- This routine compares two LONGLONG values, casting the input parameters to
- LONGLONGs.
- Arguments:
- ValueOne - Supplies the first LONGLONG to compare.
- ValueTwo - Supplies the second LONGLONG to compare.
- Return Value:
- Returns -1 if ValueOne is less than ValueTwo, 0 if they are equal, and 1
- if ValueOne is greater than ValueTwo.
- --*/
- {
- INT Result;
- if ((LONGLONG)ValueOne < (LONGLONG)ValueTwo) {
- Result = -1;
- } else if ((LONGLONG)ValueOne == (LONGLONG)ValueTwo) {
- Result = 0;
- } else {
- Result = 1;
- }
- return Result;
- }
- ULONGLONG
- GetUlonglongValue (
- PVOID Structure,
- ULONG Offset
- )
- /*++
- Routine Description:
- This routine returns a ULONGLONG value at the given offset from within the
- given structure.
- Arguments:
- Structure - Supplies a pointer to the structure that contains the ULONGLONG
- value.
- Offset - Supplies the offset within the structure where the value is stored.
- Return Value:
- Returns a ULONGLONG value.
- --*/
- {
- return *(PULONGLONG)((PBYTE)Structure + Offset);
- }
- ULONGLONG
- GetUlongValue (
- PVOID Structure,
- ULONG Offset
- )
- /*++
- Routine Description:
- This routine returns a ULONG value at the given offset from within the
- given structure.
- Arguments:
- Structure - Supplies a pointer to the structure that contains the ULONGLONG
- value.
- Offset - Supplies the offset within the structure where the value is stored.
- Return Value:
- Returns a ULONG value.
- --*/
- {
- return *(PULONG)((PBYTE)Structure + Offset);
- }
- VOID
- UiGetWindowPreferences (
- HWND Dialog
- )
- /*++
- Routine Description:
- This routine saves the given window's current rect information so that it
- can be written to the preferences file on exit.
- Arguments:
- Dialog - Supplies the dialog window handle.
- Return Value:
- None.
- --*/
- {
- RECT WindowRect;
- //
- // Only save the window rect if it has a non-zero height and width.
- //
- GetWindowRect(Dialog, &WindowRect);
- if ((WindowRect.left != WindowRect.right) &&
- (WindowRect.top != WindowRect.bottom)) {
- memcpy(&CurrentWindowRect, &WindowRect, sizeof(RECT));
- }
- return;
- }
- VOID
- UiLoadPreferences (
- HWND Dialog
- )
- /*++
- Routine Description:
- This routine attempts to load up the previously saved debugger preferences.
- Arguments:
- Dialog - Supplies the dialog window handle.
- Return Value:
- None.
- --*/
- {
- DEBUGGER_UI_PREFERENCES Preferences;
- BOOL Result;
- Result = UiReadPreferences(&Preferences);
- if (Result == FALSE) {
- return;
- }
- if (Preferences.Version < DEBUGGER_UI_PREFERENCES_VERSION) {
- return;
- }
- if ((Preferences.WindowWidth != 0) && (Preferences.WindowHeight != 0)) {
- MainPaneXPosition = Preferences.MainPaneXPosition;
- MainPaneXPositionWidth = Preferences.MainPaneXPositionWidth;
- ProfilerPaneYPosition = Preferences.ProfilerPaneYPosition;
- ProfilerPaneYPositionHeight = Preferences.ProfilerPaneYPositionHeight;
- SetWindowPos(Dialog,
- HWND_TOP,
- Preferences.WindowX,
- Preferences.WindowY,
- Preferences.WindowWidth,
- Preferences.WindowHeight,
- 0);
- WindowSizesInitialized = TRUE;
- }
- //
- // Save the initial UI preferences. In case the window is never moved.
- //
- UiGetWindowPreferences(Dialog);
- return;
- }
- VOID
- UiSavePreferences (
- HWND Dialog
- )
- /*++
- Routine Description:
- This routine attempts to save the current UI features into the preferences
- file.
- Arguments:
- Dialog - Supplies the dialog window handle.
- Return Value:
- None.
- --*/
- {
- DEBUGGER_UI_PREFERENCES Preferences;
- memset(&Preferences, 0, sizeof(DEBUGGER_UI_PREFERENCES));
- Preferences.Version = DEBUGGER_UI_PREFERENCES_VERSION;
- Preferences.WindowX = CurrentWindowRect.left;
- Preferences.WindowY = CurrentWindowRect.top;
- Preferences.WindowWidth = CurrentWindowRect.right - CurrentWindowRect.left;
- Preferences.WindowHeight = CurrentWindowRect.bottom - CurrentWindowRect.top;
- Preferences.MainPaneXPosition = MainPaneXPosition;
- Preferences.MainPaneXPositionWidth = MainPaneXPositionWidth;
- Preferences.ProfilerPaneYPosition = ProfilerPaneYPosition;
- Preferences.ProfilerPaneYPositionHeight = ProfilerPaneYPositionHeight;
- UiWritePreferences(&Preferences);
- return;
- }
- BOOL
- UiReadPreferences (
- PDEBUGGER_UI_PREFERENCES Preferences
- )
- /*++
- Routine Description:
- This routine attempts to open and read the preferences file.
- Arguments:
- Preferences - Supplies a pointer where the preferences will be returned on
- success.
- Return Value:
- TRUE on success.
- FALSE on failure.
- --*/
- {
- DWORD BytesRead;
- HANDLE File;
- BOOL Result;
- memset(Preferences, 0, sizeof(DEBUGGER_UI_PREFERENCES));
- Result = FALSE;
- File = UiOpenPreferences();
- if (File == INVALID_HANDLE_VALUE) {
- goto ReadPreferencesEnd;
- }
- Result = ReadFile(File,
- Preferences,
- sizeof(DEBUGGER_UI_PREFERENCES),
- &BytesRead,
- NULL);
- if (Result == FALSE) {
- goto ReadPreferencesEnd;
- }
- ReadPreferencesEnd:
- if (File != INVALID_HANDLE_VALUE) {
- CloseHandle(File);
- }
- return Result;
- }
- BOOL
- UiWritePreferences (
- PDEBUGGER_UI_PREFERENCES Preferences
- )
- /*++
- Routine Description:
- This routine attempts to open and write the preferences file.
- Arguments:
- Preferences - Supplies a pointer to the preferences to write.
- Return Value:
- TRUE on success.
- FALSE on failure.
- --*/
- {
- DWORD BytesWritten;
- HANDLE File;
- BOOL Result;
- Result = FALSE;
- File = UiOpenPreferences();
- if (File == INVALID_HANDLE_VALUE) {
- goto WritePreferencesEnd;
- }
- Result = WriteFile(File,
- Preferences,
- sizeof(DEBUGGER_UI_PREFERENCES),
- &BytesWritten,
- NULL);
- if (Result == FALSE) {
- goto WritePreferencesEnd;
- }
- WritePreferencesEnd:
- if (File != INVALID_HANDLE_VALUE) {
- CloseHandle(File);
- }
- return Result;
- }
- HANDLE
- UiOpenPreferences (
- VOID
- )
- /*++
- Routine Description:
- This routine attempts to open the preferences file.
- Arguments:
- None.
- Return Value:
- Returns an open handle to the preferences file on success.
- INVALID_HANDLE_VALUE on failure.
- --*/
- {
- HANDLE File;
- TCHAR Path[MAX_PATH];
- HRESULT Result;
- Result = SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, 0, Path);
- if (!SUCCEEDED(Result)) {
- return INVALID_HANDLE_VALUE;
- }
- PathAppend(Path, TEXT("\\Minoca"));
- CreateDirectory(Path, NULL);
- PathAppend(Path, TEXT("\\DebugUI"));
- CreateDirectory(Path, NULL);
- PathAppend(Path, TEXT("prefs"));
- File = CreateFile(Path,
- GENERIC_WRITE | GENERIC_READ,
- 0,
- NULL,
- OPEN_ALWAYS,
- FILE_ATTRIBUTE_NORMAL,
- NULL);
- return File;
- }
|