<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Thoughts from Mirality</title>
	<atom:link href="http://lambert.geek.nz/feed/" rel="self" type="application/rss+xml" />
	<link>http://lambert.geek.nz</link>
	<description>Random thoughts and musings from Miral at Mirality Systems.</description>
	<lastBuildDate>Fri, 30 Mar 2012 22:01:37 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>Mass Effect 3</title>
		<link>http://lambert.geek.nz/2012/03/30/mass-effect-3/</link>
		<comments>http://lambert.geek.nz/2012/03/30/mass-effect-3/#comments</comments>
		<pubDate>Thu, 29 Mar 2012 14:30:15 +0000</pubDate>
		<dc:creator>Miral</dc:creator>
				<category><![CDATA[Games]]></category>
		<category><![CDATA[Rants]]></category>
		<category><![CDATA[BioWare]]></category>
		<category><![CDATA[DLC]]></category>
		<category><![CDATA[Mass Effect]]></category>

		<guid isPermaLink="false">http://lambert.geek.nz/?p=225</guid>
		<description><![CDATA[<p>I recently completed my first playthrough of Mass Effect 3, and I feel the urge to share some thoughts with the world.  Not that anyone&#8217;s listening, of course. </p> <p>I&#8217;ve previously played the earlier games, of course (all three on PC), although unlike many others so far I&#8217;ve only really done one complete playthrough of [...]]]></description>
			<content:encoded><![CDATA[<p>I recently completed my first playthrough of Mass Effect 3, and I feel the urge to share some thoughts with the world.  Not that anyone&#8217;s listening, of course. <img src='http://lambert.geek.nz/wpdata/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>I&#8217;ve previously played the earlier games, of course (all three on PC), although unlike many others so far I&#8217;ve only really done one complete playthrough of each.  (I keep meaning to go back and try some different choices, but my pile of games I haven&#8217;t even played yet just keeps getting bigger&#8230;)</p>
<p>Note that (for reasons which will become apparent later) unlike my normal review style (where I try to avoid spoilers as much as possible), this one is going to be a bit spoileriffic.  I will make a point of mentioning this again just before I get too blatant, though.</p>
<p><span id="more-225"></span></p>
<h2>The Introduction</h2>
<p>The start of the game was a bit weird for me, as I hadn&#8217;t played the <em>Arrival</em> DLC for ME2, and a fair amount of the starting situation is dependent on that.  From what I gather, after the events in the finale of ME2, Shepard decided to return to the Alliance and has been cooling his/her heels in something sort of like house arrest (no actual detention, but there did seem to be some sort of enquiry going on).</p>
<p>I suppose this&#8217;d make more sense if you did actually play the DLC (again, from what I heard, there was something about a Batarian planet and an exploding mass relay), but without that context it seemed a bit nonsensical.  Shepard is a Spectre, completely outside of Alliance authority by definition, in charge of a non-Alliance ship with a mixture of ex-Alliance and ex-Cerberus crew, who spent most of the previous game being ignored and marginalised by both Alliance and Council.  And yet apparently prior to the start of the game you&#8217;ve run back tail between your legs and turned yourself and your ship over to the Alliance and are awaiting trial (for whatever).  Fate of your ex-Cerberus crew unknown.  What the heck?</p>
<h2>Main Gameplay</h2>
<p>But, once you get past all that weirdness and get into the game proper, things get better.  Galactic exploration has been both simplified and made more exciting &#8212; the scanning minigame from ME2 is back but this time there&#8217;s only one thing of interest on each of a specific subset of planets, and you can find out which ones fairly quickly &#8212; although doing so attracts the attention of the Reapers, who you have to dodge (which is pretty easy, if you&#8217;re paying attention).  It does sort of break realism a little &#8212; you&#8217;ll find yourself narrowly escaping a Reaper ship, only to turn around and immediately re-enter the system for a bit more scanning, or to try to reach something you found earlier, dodging the ships again until you eventually make it &#8212; but it&#8217;s forgivable as a reasonable game mechanic.</p>
<p>There are a lot of cameos from past crew and acquaintances, both from ME1 and ME2 (at least, the ones that survived your previous adventures).  And you discover what&#8217;s been happening with your ex-Cerberus crew (and can even re-recruit some of them), which helps to reduce some of the issues from the introduction.  In classic BioWare style, the characterisations are detailed and there are lots of opportunity for interaction, and they&#8217;re all pretty interesting.  There are also a few new crewmembers; a few of these have gotten a bit of flack from some reviews but I never really had a problem with any of them.</p>
<p>The overarching goal of ME3 is to gather &#8220;war assets&#8221;, both to fund and help the construction of the superweapon you discovered blueprints for early on in the game, and to enhance the strength of the fleet you&#8217;re trying to build to Retake Earth (as the slogan would have it).  To that end, you explore around various systems and complete missions to gather intelligence, resources, or to convince a particular alien race to lend their support.  Ultimately you can end up building a huge fleet consisting of most of the warships from most of the races, although in some cases it&#8217;s a little unclear why everyone is so focused on Earth &#8212; although it is implied that the Reapers are hitting there harder or something, perhaps due to their apparent fascination with humans (as shown in ME2).</p>
<p>The missions are broken up fairly naturally; there&#8217;s a major mission for each of the major races (with a little crossover in some cases), and in between there are several side missions you can do.  I didn&#8217;t really measure but it feels like there are fewer total missions than in ME2, but each mission is a little longer, so it works out about the same.  In the end I think I sunk in about 30-40 hours for a 100% playthrough.</p>
<p>The main core of the game is awesomely fun.  Combat is basically the same as in ME2 (although it feels a bit harder for some reason), but they&#8217;ve improved the weapon management significantly and sprinkled ammo around more liberally &#8212; as a consequence the sniper rifle (which I felt was nerfed to the point of unusability in ME2) is back as a viable combat option this time around.  Additionally, the enemy AI seems to be improved a bit and the environment arranged suitably that there are several times you&#8217;ll find yourself getting flanked if you&#8217;re not careful.  Each mission is set in a unique location with fairly unique goals and challenges (yes, even the side missions), so there&#8217;s no shortage of fun, and no onset of repetitive boredom (which happened a little in ME2 and a bit more in DA2).</p>
<p>As before, in between each mission (also including most side missions, this time) you can wander the ship and check in on your companions, who will usually have something interesting to say.  An interesting difference is that you&#8217;ll also periodically find little scripted scenes, where you&#8217;ll walk into a room and overhear a conversation between two or more people, or see them engaged in some normal activity.  (And yes, Mordin sings again.  Which is a good thing.)  One slightly annoying aspect of this is that sometimes when you talk to someone it&#8217;ll immediately give you control back (which is good if you&#8217;ve heard it before and want to walk away), but this lets you accidentally activate them again and they&#8217;ll skip to the next dialogue.  This is particularly problematic when there&#8217;s a bit of a pause after they say a line and you <em>think</em> they&#8217;re done, so you hit activate again only to end up interrupting their following line, skipping ahead to the next conversation path.</p>
<p>Whoever decided to include the forcefield thing between the war room and CIC, however, needs to get slapped very hard.  It&#8217;s <em>very</em> annoying (especially since it&#8217;s the only scanner field thing in the game that forces you to stop while it plays its scanning animation).  You can&#8217;t avoid it when doing the rounds of the ship, and it doesn&#8217;t even seem to serve any useful function, since there aren&#8217;t even any airlocks over in that part of the ship anyway, so there shouldn&#8217;t be anything that needs to be scanned.  (I have my suspicions that it&#8217;s some kind of background-loading-gate for the consoles, but the level isn&#8217;t really all <em>that</em> large.)</p>
<p>But your choices from both previous games are woven in expertly; some only in flavour text, some in which characters you&#8217;ll be able to meet or recruit.  It&#8217;s good at making you feel that your past choices matter, so you&#8217;ll be careful in your choices this time around too.  (Although&#8230;)</p>
<h2>Approaching Spoilers</h2>
<p>(Some medium-level spoilers in this section.)</p>
<p>Another thing that happens with disturbing regularity during the course of the main missions: your friends get killed.  A lot.  Including some major characters that you&#8217;d much rather didn&#8217;t.  (A few of these you can avert if you make the right choices, but many are unavoidable.)  Now, this is not a bad thing &#8212; you <strong>are</strong> in a war against an overwhelming force, after all, and (at least from what I recall) each ending is suitably epic; so it just serves to drive things home a bit better.  Another nice touch is the various memorial walls (there&#8217;s one on the Normandy and a couple at the Citadel); not only are there some appropriate scripted events at each, when you do lose someone major their name will get added to the Normandy memorial.  Despite a personal desire to have the characters survive, ultimately it does make sense in the context of the game and I regard it as a positive.</p>
<h2>The Ending</h2>
<p>(Caution: unbelievably massive, complete, and total spoilers!)</p>
<p>You may have already heard from other sources that the ending of ME3 is a bit controversial.  And that&#8217;s correct.  The ending is a complete and total piece of piss, utterly unworthy of the rest of the game.  (Given my tendency to go for silly titles for my blog posts, I nearly called this entry &#8220;Mass Defect 3&#8243;; I decided not to in the end because that joke has been done to death, and because it&#8217;s not really fair on the rest of the game.)</p>
<p>The problems start when you finish the first &#8220;finale&#8221; mission &#8212; the assault on the Cerberus base.  (Some would argue that the problems start slightly earlier, with the boss fight at the end of that mission against someone who decides to squat in the open to recharge their shields.)  At the end of that mission, you&#8217;re told (fairly abruptly and without any commentary) that the Reapers have taken control of the Citadel and moved it to Earth.  There are several problems with this.  First, you&#8217;ve most likely just spent a good part of the game beefing up the security forces of the Citadel (with the express purpose of defending against the Reapers).  Second, the Citadel has been defined as fairly immune to attack with its arms closed, even against Reapers (in fact this was a large part of what ME1 was about), especially since the Keepers are no longer under their control.  Both of these together mean that it shouldn&#8217;t have been easy for the Reapers to take over the Citadel in the first place.  (And as a side note: again in ME1 you learn that the standard invasion plan is to take over the Citadel first thing and use it to shut down all the mass relays to make it easier to divide and conquer &#8212; but nothing like that happened in ME3.)  There are also some logistical problems &#8212; the Citadel is huge; how did the Reapers manage to move it so quickly?  Even if it were itself a mass relay (which I seem to vaguely recall reading somewhere), a relay can&#8217;t be used to move itself over that sort of distance, and the regular mass relays have a much smaller mass limit (as defined in the codex).</p>
<p>But the biggest problem with that is that so little emotional attention is paid to it (and all the lives lost during the capture), when again, you&#8217;ve just spent most of the game beefing up the defences, and you&#8217;ve spent much more time in all three games on the Citadel than anywhere else, so in many respects its inhabitants would be more important to Shepard than anything on Earth &#8212; especially for a non-Earthborn Shepard.</p>
<p>The problems don&#8217;t end there, though.  After that there&#8217;s a fairly epic cutscene showing the fleet arriving at Earth; this is undeniably cool, although it&#8217;s a little dubious given the lore restrictions on relay arrival patterns (but this can be hand-waved a little based on the Normandy still having a Reaper IFF &#8212; maybe that can unlock improved performance for the whole fleet).  The following mission to Earth starts out decently enough, and at the midway point you get to have a nice farewell speech with all your companions (both present and elsewhere), albeit with a fairly pointless turret battle thrown in the middle.</p>
<p>The next phase of the mission is a bit painful &#8212; towards the end it involves holding a position while waiting for an arbitrary countdown, against an endless influx of some of the most annoying (and hard to kill) enemies in the game.  Once the timer is up, you basically just have to clear out sufficient enemies to make a run for the panel you need to activate (they&#8217;re still infinitely respawning) and rely on the plot to magically destroy any remaining enemies.  After that, the climax of the mission is a foot charge towards the conduit, dodging blasts from the main cannon of our old friend Harbinger.  (It&#8217;s a little unclear to me why they don&#8217;t try to air-strike the vulnerable spot, as has been shown several times in the past; or why the Reapers don&#8217;t just turn off the conduit, for that matter.)</p>
<p>But this is where everything goes dodgy.  You&#8217;re hit by the beam, yet survive (albeit with scorched armour and massive injuries) &#8212; but as you&#8217;re getting up again, you see Harbinger depart, and over the radio you hear a retreat order, along with a statement that everyone was killed.  (Apparently neither of them noticed you.)  You make your way to the beam, facing only token resistance (which is convenient since you can only put up a token defence), and black out when you reach the Citadel.  On waking up again, you&#8217;re told that Anderson followed you up (apparently he ignored the retreat order, and the conduit had been left unguarded?) and is now a little ahead of you.</p>
<p>You make your way up to the control console and are confronted by the Illusive Man, who has figured out some aspects of indoctrination control; at least enough to control both yourself and Anderson.  This part I don&#8217;t really have a problem with; some people find it strange that the Illusive Man is there, but bear in mind that he&#8217;s already indoctrinated and was responsible for the Reapers wanting to take over and move the Citadel in the first place, so it makes sense.  Others have a problem with him being able to control you, but that&#8217;s explained by an earlier mission where he was studying indoctrination (and had successfully discovered a key technique).  It&#8217;s a little harder to explain why Anderson is there and didn&#8217;t see or help you on the way, but it&#8217;s not unreasonable.</p>
<p>Anyway, stuff happens, and eventually you collapse in front of the console while trying to get the Crucible to fire, apparently having lost either the will or the strength to go on.  At this point, the utter insanity begins.  A mysterious platform rises and brings you to the apparent outside of the Citadel (with no obvious way to keep in breathable air), and you meet a VI hologram (or something that looks like that) who claims to have created the Reapers in order to stop synthetics from destroying all organic life.  (Based on the assertion that synthetics will always turn against their creators.)</p>
<p><img class="aligncenter size-medium wp-image-226" title="Yo dawg, I heard you like synthetics" src="http://lambert.geek.nz/wpdata/wp-content/uploads/2012/03/yo-dawg-synthetics-300x193.jpg" alt="Yo dawg, I heard you don't wanna be killed by Synthetics, so I made some Synthetics to kill you every 50k years, so you won't be killed by Synthetics" width="300" height="193" /></p>
<p>I would hope that the problems with this logic are obvious.  Even assuming that the original assertion is correct, why not just kill off the dangerous synthetics and leave the rest alone?  The only remotely plausible explanation I could come up with was that the Reapers (or their creators) thought that if they&#8217;re left alone too long then the organic races might make a synthetic race powerful enough that the Reapers wouldn&#8217;t be able to stop them.  But that seems like a bit of a stretch.</p>
<p>The utterly unforgivable failure here, though, is that despite Shepard&#8217;s own personal experience (especially with the Geth and EDI, depending on your choices), which very strongly suggest that the VI&#8217;s core assertion is incorrect, you don&#8217;t even get the option to challenge this.</p>
<p>In the end, you&#8217;re presented with (up to) three choices:</p>
<ol>
<li>To Destroy the Reapers (and also apparently all synthetic life, including the Geth, and yourself, since you have a lot of implants).</li>
<li>To Control the Reapers (and get dissolved yourself; I wasn&#8217;t entirely clear on this when I saw it but others have said that as a result of this you&#8217;re transferred into a Reaper body).</li>
<li>To Synergise all organic and synthetic life into one, so there&#8217;s no longer a distinction (and get dissolved in the process).</li>
</ol>
<p>Note that in all options, you die (although there&#8217;s one possible exception; more on that later).  Also note that option #2 is what the Illusive Man has been encouraging the whole time (and he is very obviously indoctrinated, which suggests that the Reapers <em>want</em> you to pick that option).  And also note that option #3 sounds much like what Saren claimed to want in ME1 (and again, he was indoctrinated).  (And also, DNA doesn&#8217;t work like that.)</p>
<p>Afterwards, you get one cinematic ending.  And it&#8217;s the <strong>same</strong> cinematic for all choices &#8212; the only difference is the colour of the explosions, and some minor variations (things being destroyed or Reapers departing, or people and plants getting shiny partially-synthetic skins).  In total there are exactly six almost identical ending sequences.  (And if you like, you can <a title="YouTube: All the ME3 Endings" href="http://www.youtube.com/watch?v=rPelM2hwhJA" target="_blank">compare them side-by-side</a>.)</p>
<p>And that&#8217;s pretty much it.  Not much in the way of closure.  Another thing that&#8217;s conspicuous in its absence is any overt acknowledgement of those war assets you&#8217;ve been gathering.  Several of the races are optional, and even those that I don&#8217;t think you can avoid getting would probably be in different strengths, and yet other than the original arrival at the relay you don&#8217;t really see any action from your various troops during any of the battle sequences; you get the distinct impression that the only purpose they served was to fill up a progress bar, which is disappointing.  (The level of that progress bar does have a bit of influence on which ending you get; but another thing that I regard as a failure is that to get the highest progress levels [and presumably the best endings] you are required to either play multiplayer or a non-free iOS game.  Which is bound to piss off those people like me who don&#8217;t have an iOS device or don&#8217;t like or can&#8217;t play multiplayer.)</p>
<h2>The Problems</h2>
<p>This video sums up the problems with the ending fairly handily:</p>
<p>[There is a video that cannot be displayed in this feed. <a href="http://lambert.geek.nz/2012/03/30/mass-effect-3/">Visit the blog entry to see the video.]</a></p>
<p>3. I&#8217;m ok with these relay explosions being &#8220;different&#8221; &#8212; presumably the broadcast effect is draining most of the energy of the relay first, so there&#8217;s nothing much left to cause damage.</p>
<p>4. But the secondary problem remains &#8212; with most of the relays gone there are going to be a great deal of problems, with most of the galaxy&#8217;s starships in orbit (or destroyed) around Earth.  Granted they still do have basic FTL, and there are other &#8220;locked&#8221; relays in the galaxy which don&#8217;t appear to have been affected, but it&#8217;s still going to take everyone a very long time to make it home.</p>
<p>9.  Most definitely.  When the godkid finished talking, I immediately tried to just walk away and not pick any of those choices.  Sadly it didn&#8217;t let me.</p>
<p>(Otherwise I agree with all of those points, to a greater or lesser extent.)</p>
<p>A potentially interesting sidenote that came up during discussions of the problems with the ending: someone claiming to be one of the BioWare writers came forward and said that the ending was essentially written and produced entirely by the producer and lead writer in a closed session, instead of following their normal peer review procedure.  Furthermore, the lead writer of ME3 (who was <strong>not</strong> the lead writer on ME1 and ME2) was also the author of the new ME book that was widely criticised for its lore-breaking plot holes.  How much of that is actually true, I can&#8217;t say of my own experience, not having seen the original post nor read the book.  But it&#8217;s interesting.</p>
<h2>The Solution?</h2>
<p>[There is a video that cannot be displayed in this feed. <a href="http://lambert.geek.nz/2012/03/30/mass-effect-3/">Visit the blog entry to see the video.]</a></p>
<p>Some of the issues brought up in this video I don&#8217;t really have a problem with; I&#8217;ve already said that I&#8217;m ok with Anderson and the Illusive Man reaching the Citadel control room before Shepard.  As for the radio, it could easily be an implant or even just an earbud (which would probably survive if Shepard&#8217;s ear did), and Hackett could take a reasonable guess that Shepard was still alive since he just saw the Citadel&#8217;s arms opening up and the Crucible docking &#8212; or possibly he just heard Shepard and Anderson talking to each other earlier (although if <em>that</em> were the case, it&#8217;s a little odd there wasn&#8217;t an earlier &#8220;Shepard!  We thought you were dead!&#8221; when they first started talking; I suppose Anderson could have called it in before following Shepard through the conduit).  And I&#8217;ve already said that there is a potential explanation for the Illusive Man suddenly developing the powers of partial indoctrination.  As for the rest of it though, I agree with the reasons why the Indoctrination Theory seems plausible.</p>
<p>Another objection to this theory that&#8217;s sometimes raised is that if you don&#8217;t have a high enough EMS, your only option is to Destroy, which is the only anti-indoctrination option, right?  Why would the Reapers stage this elaborate hallucination only to give you no option than to escape their control?  My answer to that is that the lower your EMS, the less time you&#8217;ve spent on the Normandy gallivanting about.  What if there was a Reaper artifact on board &#8212; it&#8217;s not like it&#8217;d be hard, given the number of them you&#8217;ve come across, or during the Normandy&#8217;s refit on Earth.  This would mean that the more time you spent on board, the more indoctrinated you were and the easier it would be for the Reapers to convince you of the more outlandish options; consequently the less time you spent on board, the easier it would be to break their control and not be convinced of any solution but destruction.  Although it&#8217;s important to note that if you&#8217;re in this situation you&#8217;ll get the worst ending anyway &#8212; Earth is destroyed, Shepard and crew dies&#8230; but then, that may just be what the Reapers want you to think.  (An alternative explanation is that Shepard has been implanted with something that lets him/her be gradually indoctrinated over the course of the game &#8212; perhaps in the original recovery at the start of ME2, perhaps during some of the missing time in <em>Arrival</em> &#8211; same result, but this time only affecting Shepard; although one point in favour of the general indoc idea is the hum mentioned by James on the flight deck&#8230;)</p>
<p>[There is a video that cannot be displayed in this feed. <a href="http://lambert.geek.nz/2012/03/30/mass-effect-3/">Visit the blog entry to see the video.]</a></p>
<p>The &#8220;Indoctrination Theory&#8221; is a bit of fan fiction cobbled together by several different people, based on a bit of wishful thinking and some supporting scenes from the game itself.  It&#8217;s unclear at this point whether that supporting evidence indicates that BioWare really was planning this all along, or if these are just leftovers from other bits that were cut out of the game, or if people are just interpreting them in the wrong context.  Given the publicity of the bad endings, and that BioWare are actually losing money as a result (due to people not wanting to buy the game, or returning it), and some equivocating announcements from BioWare (the public announcements imply not, the Twitter statements imply yes, but neither is conclusive), the general consensus is that they did <strong>not</strong> plan for this.  (Which is a little sad, as it means that they&#8217;re idiots instead of mad geniuses.)  Still, even if it wasn&#8217;t planned (which would still be amazing in itself, as the pieces of the puzzle fit too well), the theory offers a brilliant way out of the pit that BioWare have dug for themselves.</p>
<p>The key component of the Indoctrination Theory is that Shepard has been getting gradually indoctrinated throughout the whole series (especially this last game), and that everything after getting hit by Harbinger&#8217;s beam is actually a hallucination projected by Harbinger himself; as a result, you&#8217;re not really deciding whether to destroy or control the Reapers, you&#8217;re deciding whether to fight off or give into the indoctrination.  It&#8217;s also important to note that <em>by itself</em>, the Theory is actually <strong>worse</strong> than the endings we have now, as it means that the last five minutes of the game were all a dream and everything is even less resolved than the bare-minimum we actually got.  But the assumption is that it can be extended with some &#8220;real ending&#8221; DLC which starts when Shepard wakes up in the rubble back on Earth and can then proceed to kick the Reaper&#8217;s collective butts again (this time for real).</p>
<h2>Changing the Ending</h2>
<p>BioWare have already indicated that they&#8217;re planning some ending DLC (although the way they&#8217;ve worded it suggests that they&#8217;re just going to add some minor cutscenes to the existing endings, without taking the Indoctrination Theory on board); we&#8217;ll hopefully know more in April (presumably after PAX).</p>
<p>What worries me a lot is that if they do end up taking the criticism on board and developing a more complete ending DLC (probably incorporating the Theory), they&#8217;ll try to charge extra for it.  (This isn&#8217;t unprecedented; see the <em>Prince of Persia Epilogue</em>, or <em>Fallout 3: Broken Steel</em>.)  Some people argue that this is the way it should be, as they need to pay their developers to work on the new endings if they&#8217;re going to be any decent quality.  I disagree with this, for a very simple reason &#8212; it was their mistake, and they should pay for it, otherwise they learned nothing.  In fact, what they learned might be worse than nothing &#8212; if we show that we&#8217;re willing to pay to fix their mistaken ending and get the &#8220;real&#8221; ending to a story, then what&#8217;s to stop the next game from intentionally not releasing the ending except as paid DLC?  What&#8217;s to stop the game after that from releasing the entire second half of the game as snippets of paid DLC?</p>
<p>Some people say that it&#8217;s &#8220;entitled&#8221; to expect BioWare to replace the endings for free.  Maybe that&#8217;s true, but I don&#8217;t think that&#8217;s a bad thing.  We&#8217;ve already paid for the game, for all three games, and beforehand we were promised that the ending to the trilogy would <strong>not</strong> be the very thing that it ended up being, and that our choices <strong>would</strong> matter (which they didn&#8217;t).  If that&#8217;s &#8220;entitled&#8221; thinking to expect the game we paid for to live up to the promises made for it, then ok, I&#8217;m entitled.  I don&#8217;t see a problem with that.  (And ok, counterexample: <em>Fable</em>.  But everyone knows not to take Peter Molyneux seriously, he just gets over-excited.  The same reasoning doesn&#8217;t excuse BioWare, especially with two games in this series already under their belt, and a long and glorious history before that.)</p>
<p>Some people are arguing that asking BioWare to change their ending violates &#8220;artistic integrity&#8221;.  I don&#8217;t believe that for a second.  For a start, the game is already designed to be extended with DLC, which inherently changes part of the story anyway.  But the main reason is that the endings as they are now simply don&#8217;t have any artistic integrity to begin with &#8212; they&#8217;re full of plot holes, contradictions to the lore, and go completely against the entire spirit and message of the rest of the games.  If anything, artistic integrity would demand that the endings get changed.  And again, it&#8217;s hardly unprecedented for a game&#8217;s ending to be changed after release; it&#8217;s not uncommon in other artistic media either.</p>
<p>At the end of the day, though, it <strong>is</strong> BioWare&#8217;s game, and it&#8217;s up to them whether or how much to change things.  They just need to bear in mind that a lot is riding on those choices; apart from anything else, how they handle this will decide if I ever preorder another BioWare game again.  (I won&#8217;t go to extremes and state that I&#8217;ll never buy another BioWare game again, although some people have said that too.)</p>
<h2>Conclusion</h2>
<p>In its current state, I just can&#8217;t bring myself to recommend this game as a purchase to anyone who&#8217;s on the fence; in fact I strongly recommend against it if you haven&#8217;t played the previous games.  While it&#8217;s true that the majority of the game is awesome (if you&#8217;re invested in the characters already), the ending so completely undermines everything you were doing that it utterly destroys any desire to replay the game.  This may change once we know what&#8217;s happening with the DLC.</p>
<h2>Other Points of Interest</h2>
<ul>
<li><a href="http://www.escapistmagazine.com/articles/view/columns/experienced-points/9506-Mass-Effect-3-Ending-Controversy" target="_blank">The Mass Effect 3 Ending Controversy</a></li>
<li><a href="http://www.shamusyoung.com/twentysidedtale/?p=15395" target="_blank">Mass Effect 3 Ending Deconstruction</a> (from the same person as the previous link)</li>
<li><a href="http://www.tampabay.com/features/popculture/mass-effect-3s-ho-hum-finale-is-now-a-low-point-in-video-games/1222399" target="_blank">Mass Effect 3&#8242;s ho-hum finale is now a low point in video games</a></li>
<li>YouTube: <a href="http://www.youtube.com/results?search_query=mass+effect+3+ending" target="_blank">Mass Effect 3 Ending</a></li>
<li>Google: <a href="http://www.google.com/&amp;q=mass+effect+3+ending" target="_blank">Mass Effect 3 Ending</a></li>
<li><a href="http://www.cinemablend.com/games/want-real-ending-asura-wrath-cough-up-6-99-40917.html" target="_blank">Want The Real Ending To Asura&#8217;s Wrath? Cough Up $6.99</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://lambert.geek.nz/2012/03/30/mass-effect-3/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Gaming Update: Dec 2011</title>
		<link>http://lambert.geek.nz/2011/12/21/gaming-update-dec-2011/</link>
		<comments>http://lambert.geek.nz/2011/12/21/gaming-update-dec-2011/#comments</comments>
		<pubDate>Tue, 20 Dec 2011 23:21:53 +0000</pubDate>
		<dc:creator>Miral</dc:creator>
				<category><![CDATA[Games]]></category>
		<category><![CDATA[Alice]]></category>
		<category><![CDATA[Batman]]></category>
		<category><![CDATA[Dragon Age]]></category>
		<category><![CDATA[Minecraft]]></category>
		<category><![CDATA[Portal]]></category>
		<category><![CDATA[Saints Row]]></category>
		<category><![CDATA[Skyrim]]></category>
		<category><![CDATA[Terraria]]></category>

		<guid isPermaLink="false">http://lambert.geek.nz/?p=202</guid>
		<description><![CDATA[<p>Well, it&#8217;s been a while since I last posted about games, and in that time I&#8217;ve played quite a lot of them. I&#8217;m not going to mention all of them (I&#8217;m sure I&#8217;ve forgotten quite a few), but I will say a few words about some of the more notable ones. In no particular order: [...]]]></description>
			<content:encoded><![CDATA[<p>Well, it&#8217;s been a while since I last posted about games, and in that time I&#8217;ve played quite a lot of them. I&#8217;m not going to mention all of them (I&#8217;m sure I&#8217;ve forgotten quite a few), but I will say a few words about some of the more notable ones. In no particular order:<br />
<span id="more-202"></span></p>
<h2>Skyrim</h2>
<p>&#8230; nah, just kidding. Unlike apparently about two-thirds of the whole Internet, I don&#8217;t have this and aren&#8217;t playing it. I have little doubt that I will pick it up at some point, but I&#8217;m holding out for the inevitable GotY edition which includes all the DLC, and for the modding community to fix some of the more annoying bugs that undoubtedly survived the original release. Don&#8217;t get me wrong: I know that BethSoft do squash a large number of bugs, and that in such a large world it&#8217;s impossible to get them all before release, and that most of the ones remaining end up being cosmetic rather than game-breaking. But I do find it a bit odd that once they have been identified they only patch a few of the worst, leaving the modding community to deal with the rest. I guess it&#8217;s cheaper that way though. (And besides, I still haven&#8217;t finished the main story in Oblivion.)</p>
<h2><strong>Saints Row the Third</strong> (<a href="http://www.amazon.com/gp/product/B004QEWVTO?ie=UTF8&amp;tag=thougfrommira-20&amp;linkCode=as2&amp;camp=1789&amp;creative=9325&amp;creativeASIN=B004QEWVTO" target="_blank">Amazon</a><img src="http://www.assoc-amazon.com/e/ir?t=thougfrommira-20&amp;l=as2&amp;o=1&amp;a=B004QEWVTO" class="amazon-assoc" border="0" height="1" width="1" />, <a href="http://www.mightyape.co.nz/product/PC-Games/Saints-Row-The-Third/10183969/?r=1529217" target="_blank">Mighty Ape</a>, <a href="http://store.steampowered.com/app/55230/" target="_blank">Steam</a>)</h2>
<p>I&#8217;m still playing this one (about 30 hours in, and about two-thirds of the way through the storyline), so maybe it&#8217;s too early to call it, but this is definitely a blast. If you&#8217;re familiar with Saints Row 2, it&#8217;s basically more of the same. They&#8217;ve increased the graphics quality, decreased some of the flexibility (clothing options are more basic, and there isn&#8217;t as much variety in activities and diversions), removed the requirement to perform a certain number of diversions before doing missions (although they&#8217;re still important), and ratcheted up the absurdity factor by several thousand notches. If you&#8217;re not familiar with the series, then it&#8217;s basically in the same sort of style as GTA: Vice City, before that series started getting all serious about itself (and seemingly wanting you to not play the game while playing it, with the in-game TV and frequent calls to play pool and darts etc.) &#8212; basically an open-world free-roam crime/gang simulation, except insanely over-the-top. I might revisit this in another post once I&#8217;m done, but it&#8217;s a great deal of fun so far. Especially the Decker missions and activities.</p>
<h2><strong>Batman Arkham City</strong> (<a href="http://www.amazon.com/gp/product/B004H80TUC?ie=UTF8&amp;tag=thougfrommira-20&amp;linkCode=as2&amp;camp=1789&amp;creative=9325&amp;creativeASIN=B004H80TUC" target="_blank">Amazon</a><img src="http://www.assoc-amazon.com/e/ir?t=thougfrommira-20&amp;l=as2&amp;o=1&amp;a=B004H80TUC" class="amazon-assoc" border="0" height="1" width="1" />, <a href="http://www.mightyape.co.nz/product/PC-Games/Batman-Arkham-City/8230891/?r=1529217" target="_blank">Mighty Ape</a>, <a href="http://store.steampowered.com/app/57400/" target="_blank">Steam</a>)</h2>
<p>Long-awaited sequel to Arkham Asylum, and essentially pure awesomeness presented in game form. I&#8217;ve apparently pumped about 43 hours into this one, and I&#8217;m basically done now &#8212; I&#8217;ve completed the storyline and all the side missions, found all the Riddler trophies and riddles, and have only a couple of the physical challenges remaining. I haven&#8217;t yet done any of the challenge maps or New Game Plus, though; no doubt I&#8217;ll be back to try some of those later, after I&#8217;ve played something else for a while. But anyway: the premise is fairly basic; once again Batman is plunged into a den of iniquity populated by a rogues gallery of his classic opponents (both major and minor), and it&#8217;s up to him (and on occasion, also Catwoman, who is a playable character for some small segments of the game) to save the day, generally by beating a lot of people into the ground (but not killing them), preferably in a stealthy manner (since you get XP bonuses for instilling fear in your opponents and taking them down silently). The main difference is that now the game world is larger &#8212; instead of being confined to a small island, you now have a whole city district to roam over &#8212; and since you have the Batclaw right from the start and its range has been extended, you can get around quite quickly despite the larger size.</p>
<p>The Riddler makes an appearance in this one as well, but this time around there&#8217;s only a few riddles (and in particular, only one of the &#8220;use detective vision to match up an invisible question mark&#8221; riddles per area, which is a good change). Instead most of the time you&#8217;ll be collecting little question-mark trophies. Some of them are simply in obscure places, but often you&#8217;ll require a particular gadget or a certain combination of skilled moves or timing to unlock (in particular there are a few where you have to jump or glide from pressure pad to pressure pad without touching anything else in between, and a couple where you have to hit a pad with a lot of force, generally requiring a dive bomb from a height, which can be tricky to aim properly, and others where you have to hit pads or switches in a certain order or timing). There&#8217;s also (as a side mission) some special puzzle-laden rooms to solve to rescue various hostages. The variety is interesting, though, and overall I think it&#8217;s an improvement from the previous game. Plus, the Riddler is actually inside the prison this time, so you&#8217;ll get a chance to take him down directly rather than just over the radio, as before. And if you&#8217;re really struggling to find the trophies, or the other Riddler objects, you can get your in-game map updated to show where they are once you&#8217;re about half-way through the game (and after doing something else I&#8217;d rather not spoil, but it&#8217;s much more interesting than stumbling across the maps as in the first game).</p>
<p>Another improvement is that despite the game still requiring GFWL (which wasn&#8217;t unexpected, since its predecessor did too), this time around if you bought it via Steam then you simultaneously get both Steam and GFWL achievements, instead of only one or the other (which is what most other games do). Which is good if you&#8217;re into that sort of thing.</p>
<p>I&#8217;m not going to comment much on the story (since I don&#8217;t like giving spoilers), but it seemed to me that this game was a lot darker than its predecessor, especially given the reason behind Arkham City being built in the first place, and how things end up, particularly withso many characters dying. Still, this is based on a comic universe after all, and as one of the inmates points out during the after-end-game gameplay,&#8221;How many times has Joker died already?&#8221;, so it&#8217;s likely that the inevitable sequel will see the return ofmost of those who &#8220;died&#8221; this time. I&#8217;m looking forward to it.</p>
<h2><strong>Alice: Madness Returns</strong> (<a href="http://www.amazon.com/gp/product/B004CD9X2W?ie=UTF8&amp;tag=thougfrommira-20&amp;linkCode=as2&amp;camp=1789&amp;creative=9325&amp;creativeASIN=B004CD9X2W" target="_blank">Amazon</a><img src="http://www.assoc-amazon.com/e/ir?t=thougfrommira-20&amp;l=as2&amp;o=1&amp;a=B004CD9X2W" class="amazon-assoc" border="0" height="1" width="1" />, <a href="http://www.mightyape.co.nz/product/PC-Games/Alice-Madness-Returns/10338413/?r=1529217" target="_blank">Mighty Ape</a>, <a href="http://store.steampowered.com/app/19680/" target="_blank">Steam</a>)</h2>
<p>Another sequel game, this time to <strong>American McGee&#8217;s Alice</strong>, a decade-old darker reimagining of the characters from <em>Alice in Wonderland</em> (which <a href="http://lambert.geek.nz/2008/01/11/gaming-summer/">I&#8217;ve discussed before</a>). This game continues on the same theme, this time with a slightly older Alice, now outside of the asylum and trying to piece her memories back together. And in the end you do discover what really happened to her and her family, which is a little predictable in some ways but it does provide good closure. The gameplay and world is just as twisted and brilliant as before; for those unfamiliar, it&#8217;s essentially a puzzle-platformer in gorgeous madness-inspired environments sprinked with a bit of equally madness-inspired opponents. There are even a few places where you get a bit of a paradigm shift, such as a few 2D side-scrolling sections and one in which a giant Alice rampages through a group of smaller opponents while dodging cannon blasts; these help to keep things interesting.</p>
<p>There&#8217;s also a bit of a collection dynamic as well; along the way (usually in hidden locations) there are bottles and &#8220;memories&#8221; to collect; each memory unlocks a snippet of background conversation (some from before and some from after the events that caused Alice&#8217;s madness), while finding all of the bottles in a chapter will unlock bonus concept art. Unfortunately, quite a few of these are on side-routes off one-way paths, so if you happen to go the &#8220;right&#8221; way first you won&#8217;t be able to go back and collect everything. There&#8217;s a bit of mitigation for this in that you can replay chapters to collect anything you missed the first time around, but since each chapter is fairly long and the items are often hidden quite well this can be quite a chore, unless you cave in and use a walkthrough. (Or aren&#8217;t the type to care if you miss collecting something.)</p>
<p>Overall, though, a fun and interesting game, especially if you&#8217;ve played the original.</p>
<h2><strong>Dragon Age II</strong> (<a href="http://www.amazon.com/gp/product/B0047THYWC?ie=UTF8&amp;tag=thougfrommira-20&amp;linkCode=as2&amp;camp=1789&amp;creative=9325&amp;creativeASIN=B0047THYWC" target="_blank">Amazon</a><img src="http://www.assoc-amazon.com/e/ir?t=thougfrommira-20&amp;l=as2&amp;o=1&amp;a=B0047THYWC" class="amazon-assoc" border="0" height="1" width="1" />, <a href="http://www.mightyape.co.nz/product/PC-Games/Dragon-Age-II/10049833/?r=1529217" target="_blank">Mighty Ape</a>)</h2>
<p>Oh look, another sequel. <img src='http://lambert.geek.nz/wpdata/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  I&#8217;ve completed the base game and the Legacy DLC; I&#8217;m planning to play Mark of the Assassin at some point (yay, Felicia Day!) but haven&#8217;t yet done so. There&#8217;s probably not a lot that I can add to this that hasn&#8217;t been said elsewhere &#8212; the game is a lot of fun, the story and combat elements remain strong from the first game. I particularly like that you&#8217;re <em>not</em> out to save the world this time &#8212; just your own little corner of it. That&#8217;s something we don&#8217;t see enough of. It&#8217;s also told in an interesting fashion &#8212; it&#8217;s a <em>framed story</em>, ie. it&#8217;s being told by one of the participants, rather than happening directly. This allows for some hilarious moments, such as when during the narrator&#8217;s personal quest you first experience it as the single character in a heroic battle against an endless swarm of one-hit-kill opponents, before being called out on it and then things returning to normal gameplay.</p>
<p>The biggest downsides to the game were the way that the enemies tended to come in contrived waves (especially given that the subsequent waves would simply teleport in most of the time), and the ridiculously over-reused maps. Granted that there&#8217;s occasional justification for the latter (often you are revisiting the same locations at a later time, since most of the story happens in and around of a single city), but most of the time there&#8217;s no reason for &#8220;random cave A&#8221; to be absolutely identical to &#8220;random cave B&#8221; except for the placement of a few of the permanently-locked doors. Obviously this is cheaper and easier for the developers, but during gameplay it just seems like laziness. Fortunately, both of these flaws were remedied in the new DLC content (enemies still come in waves occasionally, but at least they do it by coming in through doors or over walls now, instead of teleporting), so hopefully the developers have learned their lesson.</p>
<h2><strong><a href="http://www.minecraft.net/">Minecraft</a></strong></h2>
<p>Ah, Minecraft. I&#8217;ve actually had this for over a year now (I got in during Alpha), and have been resisting the urge to post about it for all this time because I&#8217;ve never been entirely sure what to say about it. That&#8217;s still true today, but I felt it at least deserves a mention, now that it&#8217;s been officially released. <img src='http://lambert.geek.nz/wpdata/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  To be honest, I&#8217;m not really spending much time playing the game itself any more, but I do still spend quite a lot of time watching other people play it via YouTube LP videos (sometimes on special player-created adventure maps, sometimes on the regular game, just building interesting things). Some people have compared it to LEGO, and that&#8217;s a pretty good comparison &#8212; it&#8217;s a sandbox game that lets you build whatever you can imagine (within constraints, of course), even giving you the option to choose between a creative mode that gives you infinite resources to just go nuts and build whatever you want, or a survival mode where you have to gather the resources yourself, while fending off attacks from the monsters that come out at night. And some of the interesting interactions between its block physics systems and its redstone circuitry let you build some quite elaborate things &#8212; if you look around, you can find people who have built models of the entire globe, or secret doorways, or playable minigames, or even a working virtual computer.</p>
<h2><strong>Terraria</strong> (<a href="http://store.steampowered.com/app/105600/" target="_blank">Steam</a>)</h2>
<p>Some have called it a 2D version of Minecraft, and there are indeed some similarities (and in some respects the two games have been getting closer to equivalence &#8212; Terraria was the first to have potion brewing, and Minecraft was the first to have a wiring system &#8212; but I think this is more a case of convergent evolution than actual copying). In many respects, Terraria is the more structured and less pure-sandboxy of the two games; it has distinct areas of increasing difficulty and &#8220;tiers&#8221; of equipment, eg. you have to beat certain bosses to get enough resources to craft certain items that will enable you to successfully fight or acquire resources in other zones, and each zone has unique enemies which have different levels of health and provide different resources (Minecraft does have a bit of this too, but there&#8217;s only three zones, one of which most players won&#8217;t see for quite a long time, and it&#8217;s easier to acquire the highest tiers of equipment, since they wear out over time instead). Unlike Minecraft, it has fixed-size worlds, but it provides a way to take a character (and their inventory, unlike Minecraft) between worlds, so once you&#8217;ve spent some time conquering one world and gathering its resources, you can take those to a new world and find some more. Since there&#8217;s quite a large number of unique items (some quite rare), and they&#8217;re scattered around the world in chests that you may never find the first time around, starting over like this can be quite beneficial, letting you find some of the items you never discovered previously. And additionally, of course, it allows you to build your house/base with much better resources and planning than you could the first time around.</p>
<h2><strong>Portal 2</strong> (<a href="http://www.amazon.com/gp/product/B002I0JIQW?ie=UTF8&amp;tag=thougfrommira-20&amp;linkCode=as2&amp;camp=1789&amp;creative=9325&amp;creativeASIN=B002I0JIQW" target="_blank">Amazon</a><img src="http://www.assoc-amazon.com/e/ir?t=thougfrommira-20&amp;l=as2&amp;o=1&amp;a=B002I0JIQW" class="amazon-assoc" border="0" height="1" width="1" />, <a href="http://www.mightyape.co.nz/product/PC-Games/Portal-2/10221912/?r=1529217" target="_blank">Mighty Ape</a>, <a href="http://store.steampowered.com/app/620/" target="_blank">Steam</a>)</h2>
<p>Buy it. Play it. Now. What more needs to be said? (Well, ok: play the first one first, if you&#8217;ve been hiding under a rock. You don&#8217;t <em>have</em> to, but it makes things a lot better if you do.) And I still haven&#8217;t really played the co-op mode yet.</p>
<h2>Afterword</h2>
<p>I think that&#8217;s enough for now. As always, I&#8217;ve played quite a few more than I&#8217;ve listed here, so if anyone out there actually cares about my opinions, feel free to suggest a game (either in the comments or the Suggestion Box) and I&#8217;ll respond or post about that too, if I&#8217;ve played it. You can even suggest one that I&#8217;ve already talked about, if there&#8217;s something more you want to know about it, or my opinion of it.</p>
]]></content:encoded>
			<wfw:commentRss>http://lambert.geek.nz/2011/12/21/gaming-update-dec-2011/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>AppDomains and unmanaged callbacks, redux</title>
		<link>http://lambert.geek.nz/2011/12/19/appdomains-and-unmanaged-callbacks-redux/</link>
		<comments>http://lambert.geek.nz/2011/12/19/appdomains-and-unmanaged-callbacks-redux/#comments</comments>
		<pubDate>Sun, 18 Dec 2011 23:19:14 +0000</pubDate>
		<dc:creator>Miral</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[.NET]]></category>
		<category><![CDATA[C++]]></category>
		<category><![CDATA[callback]]></category>
		<category><![CDATA[interop]]></category>
		<category><![CDATA[native]]></category>

		<guid isPermaLink="false">http://lambert.geek.nz/?p=118</guid>
		<description><![CDATA[<p>Quite a while back, I posted an article about getting native callbacks to work across AppDomains. Since then, I&#8217;ve gotten quite a few comments with varying levels of confusion, and seen a few implementations that appear to have missed something along the way. So I thought it&#8217;d be a good idea to post a clarification.</p> [...]]]></description>
			<content:encoded><![CDATA[<p>Quite a while back, I posted an article about <a href="http://lambert.geek.nz/2007/05/29/unmanaged-appdomain-callback/">getting native callbacks to work across AppDomains</a>.  Since then, I&#8217;ve gotten quite a few comments with varying levels of confusion, and seen a few implementations that appear to have missed something along the way.  So I thought it&#8217;d be a good idea to post a clarification.</p>
<p>Fundamentally, there are just a few things that you need to remember:</p>
<ul>
<li>You cannot access managed objects (including <code>GCHandle</code>s and <code>gcroot</code>s) outside of the AppDomain in which they were created.</li>
<li>Each thread which has executed managed code has a &#8220;history&#8221; linking it to a particular AppDomain.  If a thread has never executed managed code before, though, then the first time it tries it will be assumed to be in the first AppDomain.</li>
<li>Delegates contain information about which AppDomain they should be executed in, so they can &#8220;cross the line&#8221; when an otherwise pure native thread has no idea which AppDomain it should be using.</li>
<li>Managed delegates can be turned into native function pointers via the <code>Marshal::GetFunctionPointerForDelegate</code> method.</li>
<li>If you create a function pointer from a delegate, you must keep the delegate alive (by keeping a reference to it) for as long as the native pointer exists.</li>
<li>Native functions can only have native types as parameters (but they don&#8217;t have to just be primitive types).  (Actually, there are some limited exceptions to this, which I cover below.)</li>
</ul>
<p>So, here&#8217;s a few example scenarios, to get your head around the ideas.  Note that none of these care whether you&#8217;re crossing AppDomain boundaries or not (they&#8217;re cross-AppDomain-safe, but can be used within the same AppDomain too), so they can also serve as good examples for regular interop scenarios as well.<br />
<span id="more-118"></span></p>
<h2>Direct-use callbacks</h2>
<p>This is where you&#8217;ve started in managed code, but dropped into native code for a moment in order to use a native callback, but that callback is used immediately and not stored anywhere.  A simple example of this is the WinAPI function <code>EnumWindows</code>.  In this case, you don&#8217;t have to do anything fancy:</p>

<div class="wp_syntax"><div class="code"><pre class="cpp" style="font-family:monospace;">delegate BOOL WndEnumProc<span style="color: #008000;">&#40;</span>HWND hwnd, LPARAM lParam<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
&nbsp;
<span style="color: #0000ff;">public</span> ref <span style="color: #0000ff;">class</span> NativeMethods abstract sealed
<span style="color: #008000;">&#123;</span>
<span style="color: #0000ff;">public</span><span style="color: #008080;">:</span>
    <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">void</span> Test<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>
    <span style="color: #008000;">&#123;</span>
        WndEnumProc<span style="color: #000040;">^</span> callback <span style="color: #000080;">=</span> gcnew WndEnumProc<span style="color: #008000;">&#40;</span><span style="color: #000040;">&amp;</span>NativeMethods<span style="color: #008080;">::</span><span style="color: #007788;">WindowCallback</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
        EnumWindows<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#40;</span>WNDENUMPROC<span style="color: #008000;">&#41;</span>Marshal<span style="color: #008080;">::</span><span style="color: #007788;">GetFunctionPointerForDelegate</span><span style="color: #008000;">&#40;</span>callback<span style="color: #008000;">&#41;</span>.<span style="color: #007788;">ToPointer</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>, <span style="color: #0000dd;">0</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span>
&nbsp;
<span style="color: #0000ff;">private</span><span style="color: #008080;">:</span>
    <span style="color: #0000ff;">static</span> BOOL CALLBACK WindowCallback<span style="color: #008000;">&#40;</span>HWND hwnd, LPARAM lParam<span style="color: #008000;">&#41;</span>
    <span style="color: #008000;">&#123;</span>
        _TCHAR title<span style="color: #008000;">&#91;</span><span style="color: #0000dd;">1024</span><span style="color: #008000;">&#93;</span><span style="color: #008080;">;</span>
        <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span>GetWindowText<span style="color: #008000;">&#40;</span>hwnd, title, <span style="color: #0000dd;">1024</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span>
        <span style="color: #008000;">&#123;</span>
            Console<span style="color: #008080;">::</span><span style="color: #007788;">WriteLine</span><span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot;<span style="color: #000099; font-weight: bold;">\&quot;</span>{0}<span style="color: #000099; font-weight: bold;">\&quot;</span>&quot;</span>, marshal_as<span style="color: #000080;">&lt;</span>String<span style="color: #000040;">^</span><span style="color: #000080;">&gt;</span><span style="color: #008000;">&#40;</span>title<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
        <span style="color: #008000;">&#125;</span>
        <span style="color: #0000ff;">return</span> TRUE<span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span>
<span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span></pre></div></div>

<p>(Of course it&#8217;s possible to do this sort of thing directly from C# with P/Invoke, too.  But for these examples I&#8217;m sticking with C++/CLI to be consistent with some of the more complicated examples below.)</p>
<h2>Longer-term parameter-based callbacks</h2>
<p>When the callback function isn&#8217;t used immediately, but is saved for later use by some external code, then you must ensure that the delegate is kept alive just as long as that external code has a reference to the callback.  For this example, I&#8217;m assuming that you already have some external library which provides this API:</p>

<div class="wp_syntax"><div class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">typedef</span> <span style="color: #0000ff;">void</span> <span style="color: #008000;">&#40;</span>CALLBACK <span style="color: #000040;">*</span>NLibLogFn<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">const</span> std<span style="color: #008080;">::</span><span style="color: #007788;">string</span><span style="color: #000040;">&amp;</span> message<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
<span style="color: #0000ff;">void</span> NLibSetLogger<span style="color: #008000;">&#40;</span>NLibLogFn logger<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></pre></div></div>

<p>(Note that this assumes that the external API is already <code>__stdcall</code>, which is the case with <code>CALLBACK</code>; if your external API is <code>__cdecl</code> or something else instead, then you&#8217;ll need to make some changes to the code.  This is discussed in more detail below.)</p>
<p>Now we want to write a logging class which can log messages both from managed code and this native library.  We do that like so:</p>

<div class="wp_syntax"><div class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">public</span> ref <span style="color: #0000ff;">class</span> Logger
<span style="color: #008000;">&#123;</span>
<span style="color: #0000ff;">public</span><span style="color: #008080;">:</span>
    Logger<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>
    <span style="color: #008000;">&#123;</span>
        m_Delegate <span style="color: #000080;">=</span> gcnew LogDelegate<span style="color: #008000;">&#40;</span><span style="color: #0000dd;">this</span>, <span style="color: #000040;">&amp;</span>Logger<span style="color: #008080;">::</span><span style="color: #007788;">Log</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
        NLibSetLogger<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#40;</span>NLibLogFn<span style="color: #008000;">&#41;</span>Marshal<span style="color: #008080;">::</span><span style="color: #007788;">GetFunctionPointerForDelegate</span><span style="color: #008000;">&#40;</span>m_Delegate<span style="color: #008000;">&#41;</span>.<span style="color: #007788;">ToPointer</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span>
    ~Logger<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>
    <span style="color: #008000;">&#123;</span>
        this<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span><span style="color: #000040;">!</span>Logger<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span>
    <span style="color: #000040;">!</span>Logger<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>
    <span style="color: #008000;">&#123;</span>
        NLibSetLogger<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">NULL</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span>
&nbsp;
    <span style="color: #0000ff;">void</span> Log<span style="color: #008000;">&#40;</span>String<span style="color: #000040;">^</span> message<span style="color: #008000;">&#41;</span>
    <span style="color: #008000;">&#123;</span>
        Console<span style="color: #008080;">::</span><span style="color: #007788;">WriteLine</span><span style="color: #008000;">&#40;</span>message<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span>
&nbsp;
<span style="color: #0000ff;">private</span><span style="color: #008080;">:</span>
    delegate <span style="color: #0000ff;">void</span> LogDelegate<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">const</span> std<span style="color: #008080;">::</span><span style="color: #007788;">string</span><span style="color: #000040;">&amp;</span> message<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #0000ff;">void</span> Log<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">const</span> std<span style="color: #008080;">::</span><span style="color: #007788;">string</span><span style="color: #000040;">&amp;</span> message<span style="color: #008000;">&#41;</span>
    <span style="color: #008000;">&#123;</span>
        Log<span style="color: #008000;">&#40;</span>marshal_as<span style="color: #000080;">&lt;</span>String<span style="color: #000040;">^</span><span style="color: #000080;">&gt;</span><span style="color: #008000;">&#40;</span>message<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span>
&nbsp;
<span style="color: #0000ff;">private</span><span style="color: #008080;">:</span>
    LogDelegate<span style="color: #000040;">^</span> m_Delegate<span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span></pre></div></div>

<p>(Note that if the native library can call the callback from multiple threads, then you&#8217;ll have to use standard thread-safety features such as <code>Monitor</code> as normal.)</p>
<p>To use this, we simply need to create an instance of <code>Logger</code> from managed code, and keep it alive for as long as we want the logging to be available (typically the entire lifetime of the application).  Don&#8217;t forget to call <code>delete</code> (or <code>Dispose</code> from other languages) on it when you&#8217;re done, otherwise there&#8217;s a slight risk that the external library will try to log something while the GC is trying to collect the object, which can lead to undefined behaviour.  (Using the finalizer will help reduce the danger window, but it won&#8217;t eliminate it.)</p>
<p>Note that in this case we&#8217;re assuming that the external library only supports having a single active logger via <code>NLibSetLogger</code>; if it supported multiple loggers (eg. the interface had the pair <code>NLibAddLogger</code> and <code>NLibRemoveLogger</code> instead), then we would have had to store a copy of the native function pointer ourselves for use at unregistration time.</p>
<h2>Longer-term class-based callbacks</h2>
<p>This is the scenario which <a href="http://lambert.geek.nz/2007/05/29/unmanaged-appdomain-callback/">I blogged about earlier</a>, but I&#8217;ll use a slightly different example this time for clarity.  In this case, you have an existing external native framework which provides some callback API (again, we&#8217;ll assume that this is for logging, but the principle applies to anything); but unlike the example above, this one uses the <em>Functor</em> or <em>Observer</em> patterns to call methods on a provided callback class, instead of calling a function pointer directly.  We&#8217;ll assume that the external API looks like this:</p>

<div class="wp_syntax"><div class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #0000ff;">namespace</span> NativeFramework
<span style="color: #008000;">&#123;</span>
    <span style="color: #0000ff;">class</span> ILogger
    <span style="color: #008000;">&#123;</span>
    <span style="color: #0000ff;">public</span><span style="color: #008080;">:</span>
        <span style="color: #0000ff;">virtual</span> ~ILogger<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
        <span style="color: #0000ff;">virtual</span> <span style="color: #0000ff;">void</span> Log<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">const</span> std<span style="color: #008080;">::</span><span style="color: #007788;">string</span><span style="color: #000040;">&amp;</span> message<span style="color: #008000;">&#41;</span> <span style="color: #000080;">=</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span>
&nbsp;
    <span style="color: #0000ff;">void</span> RegisterLogger<span style="color: #008000;">&#40;</span>ILogger <span style="color: #000040;">*</span>logger<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #0000ff;">void</span> UnregisterLogger<span style="color: #008000;">&#40;</span>ILogger <span style="color: #000040;">*</span>logger<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
&nbsp;
    <span style="color: #0000ff;">inline</span> ILogger<span style="color: #008080;">::</span>~ILogger<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>
    <span style="color: #008000;">&#123;</span>
        UnregisterLogger<span style="color: #008000;">&#40;</span><span style="color: #0000dd;">this</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span>
<span style="color: #008000;">&#125;</span></pre></div></div>

<p>For this case, we can construct the same managed-or-native Logger class as in the above example, but we need to define an additional helper class to do so:</p>

<div class="wp_syntax"><div class="code"><pre class="cpp" style="font-family:monospace;">delegate <span style="color: #0000ff;">void</span> LogDelegate<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">const</span> std<span style="color: #008080;">::</span><span style="color: #007788;">string</span><span style="color: #000040;">&amp;</span> message<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
&nbsp;
<span style="color: #0000ff;">class</span> NativeLogger <span style="color: #008080;">:</span> <span style="color: #0000ff;">public</span> NativeFramework<span style="color: #008080;">::</span><span style="color: #007788;">ILogger</span>
<span style="color: #008000;">&#123;</span>
<span style="color: #0000ff;">public</span><span style="color: #008080;">:</span>
    <span style="color: #0000ff;">explicit</span> NativeLogger<span style="color: #008000;">&#40;</span>LogDelegate<span style="color: #000040;">^</span> logger<span style="color: #008000;">&#41;</span>
      <span style="color: #008080;">:</span> m_Delegate<span style="color: #008000;">&#40;</span>logger<span style="color: #008000;">&#41;</span>
    <span style="color: #008000;">&#123;</span>
        m_Native <span style="color: #000080;">=</span> <span style="color: #008000;">&#40;</span>LogNative<span style="color: #008000;">&#41;</span>Marshal<span style="color: #008080;">::</span><span style="color: #007788;">GetFunctionPointerForDelegate</span><span style="color: #008000;">&#40;</span>logger<span style="color: #008000;">&#41;</span>.<span style="color: #007788;">ToPointer</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span>
&nbsp;
    <span style="color: #0000ff;">virtual</span> <span style="color: #0000ff;">void</span> Log<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">const</span> std<span style="color: #008080;">::</span><span style="color: #007788;">string</span><span style="color: #000040;">&amp;</span> message<span style="color: #008000;">&#41;</span> override
    <span style="color: #008000;">&#123;</span>
        m_Native<span style="color: #008000;">&#40;</span>message<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span>
&nbsp;
<span style="color: #0000ff;">private</span><span style="color: #008080;">:</span>
    <span style="color: #0000ff;">typedef</span> <span style="color: #0000ff;">void</span> <span style="color: #008000;">&#40;</span>__stdcall <span style="color: #000040;">*</span>LogNative<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">const</span> std<span style="color: #008080;">::</span><span style="color: #007788;">string</span><span style="color: #000040;">&amp;</span> message<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
&nbsp;
<span style="color: #0000ff;">private</span><span style="color: #008080;">:</span>
    gcroot<span style="color: #000080;">&lt;</span>LogDelegate<span style="color: #000040;">^</span><span style="color: #000080;">&gt;</span> m_Delegate<span style="color: #008080;">;</span>
    LogNative m_Native<span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span>
&nbsp;
<span style="color: #0000ff;">public</span> ref <span style="color: #0000ff;">class</span> Logger
<span style="color: #008000;">&#123;</span>
<span style="color: #0000ff;">public</span><span style="color: #008080;">:</span>
    Logger<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>
    <span style="color: #008000;">&#123;</span>
        m_Logger <span style="color: #000080;">=</span> <span style="color: #0000dd;">new</span> NativeLogger<span style="color: #008000;">&#40;</span>gcnew LogDelegate<span style="color: #008000;">&#40;</span><span style="color: #0000dd;">this</span>, <span style="color: #000040;">&amp;</span>Logger<span style="color: #008080;">::</span><span style="color: #007788;">Log</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
        NativeFramework<span style="color: #008080;">::</span><span style="color: #007788;">RegisterLogger</span><span style="color: #008000;">&#40;</span>m_Logger<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span>
    ~Logger<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>
    <span style="color: #008000;">&#123;</span>
        this<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span><span style="color: #000040;">!</span>Logger<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span>
    <span style="color: #000040;">!</span>Logger<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>
    <span style="color: #008000;">&#123;</span>
        <span style="color: #0000dd;">delete</span> m_Logger<span style="color: #008080;">;</span>
        m_Logger <span style="color: #000080;">=</span> <span style="color: #0000ff;">NULL</span><span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span>
&nbsp;
    <span style="color: #0000ff;">void</span> Log<span style="color: #008000;">&#40;</span>String<span style="color: #000040;">^</span> message<span style="color: #008000;">&#41;</span>
    <span style="color: #008000;">&#123;</span>
        Console<span style="color: #008080;">::</span><span style="color: #007788;">WriteLine</span><span style="color: #008000;">&#40;</span>message<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span>
&nbsp;
<span style="color: #0000ff;">private</span><span style="color: #008080;">:</span>
    <span style="color: #0000ff;">void</span> Log<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">const</span> std<span style="color: #008080;">::</span><span style="color: #007788;">string</span><span style="color: #000040;">&amp;</span> message<span style="color: #008000;">&#41;</span>
    <span style="color: #008000;">&#123;</span>
        Log<span style="color: #008000;">&#40;</span>marshal_as<span style="color: #000080;">&lt;</span>String<span style="color: #000040;">^</span><span style="color: #000080;">&gt;</span><span style="color: #008000;">&#40;</span>message<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span>
&nbsp;
<span style="color: #0000ff;">private</span><span style="color: #008080;">:</span>
    NativeLogger <span style="color: #000040;">*</span>m_Logger<span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span></pre></div></div>

<p>Of particular note here is that <code>NativeLogger::Log</code> must not call through the delegate directly, even though it appears to have access to it &#8212; if you are in a cross-AppDomain scenario then an attempt to get the delegate out of the <code>gcroot</code> will fail.  This is why the call through the native function pointer is required.  Also note that in this case the native function pointer is being stored by our code; this is to avoid calling <code>GetFunctionPointerForDelegate</code> more than once, which is potentially wasteful.  (In the previous example, the native library would have stored this pointer for us.)</p>
<h3>Using managed signatures</h3>
<p>But wait, there&#8217;s more!  Not only is <code>GetFunctionPointerForDelegate</code> not limited to primitive types (as some people seemed to think from my previous post), it&#8217;s not even limited to native types.  In some situations, you can include managed parameters in your native signatures and simplify the code a bit.  Which situations?  Essentially, it will work if the managed objects can be <em>constructed</em> within the native handler, and where those types are <code>[Serializable]</code>; it will end up constructing the objects in one AppDomain, serialising them, and then deserialising them in the &#8220;real&#8221; AppDomain at the other end.  (It will <strong>not</strong> work for non-serializable types, or for existing objects fetched via <code>gcroot</code>; also, using this trick for complex types will mean that these types have to get loaded in the first AppDomain, which may defeat the point of using multiple AppDomains in the first place.)</p>
<p>Note that this does imply that there&#8217;s a bit of additional overhead here, so the slight improvement to code tidiness (specifically, the elimination of the native variant of the <code>Log</code> method in the <code>Logger</code> class) may not be worth it for complex types, especially for high-use code paths.  In the case of our example, though, the cost of serializing a String (or even a wrapper class that contains a single String) is so minimal that it makes no difference.</p>
<p>Applying this technique to our example, we get this:</p>

<div class="wp_syntax"><div class="code"><pre class="cpp" style="font-family:monospace;">delegate <span style="color: #0000ff;">void</span> LogDelegate<span style="color: #008000;">&#40;</span>String<span style="color: #000040;">^</span> message<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
&nbsp;
<span style="color: #0000ff;">class</span> NativeLogger <span style="color: #008080;">:</span> <span style="color: #0000ff;">public</span> NativeFramework<span style="color: #008080;">::</span><span style="color: #007788;">ILogger</span>
<span style="color: #008000;">&#123;</span>
<span style="color: #0000ff;">public</span><span style="color: #008080;">:</span>
    <span style="color: #0000ff;">explicit</span> NativeLogger<span style="color: #008000;">&#40;</span>LogDelegate<span style="color: #000040;">^</span> logger<span style="color: #008000;">&#41;</span>
      <span style="color: #008080;">:</span> m_Delegate<span style="color: #008000;">&#40;</span>logger<span style="color: #008000;">&#41;</span>
    <span style="color: #008000;">&#123;</span>
        m_Native <span style="color: #000080;">=</span> <span style="color: #008000;">&#40;</span>LogNative<span style="color: #008000;">&#41;</span>Marshal<span style="color: #008080;">::</span><span style="color: #007788;">GetFunctionPointerForDelegate</span><span style="color: #008000;">&#40;</span>logger<span style="color: #008000;">&#41;</span>.<span style="color: #007788;">ToPointer</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span>
&nbsp;
    <span style="color: #0000ff;">virtual</span> <span style="color: #0000ff;">void</span> Log<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">const</span> std<span style="color: #008080;">::</span><span style="color: #007788;">string</span><span style="color: #000040;">&amp;</span> message<span style="color: #008000;">&#41;</span> override
    <span style="color: #008000;">&#123;</span>
        m_Native<span style="color: #008000;">&#40;</span>marshal_as<span style="color: #000080;">&lt;</span>String<span style="color: #000040;">^</span><span style="color: #000080;">&gt;</span><span style="color: #008000;">&#40;</span>message<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span>
&nbsp;
<span style="color: #0000ff;">private</span><span style="color: #008080;">:</span>
    <span style="color: #0000ff;">typedef</span> <span style="color: #0000ff;">void</span> <span style="color: #008000;">&#40;</span>__stdcall <span style="color: #000040;">*</span>LogNative<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#40;</span>String<span style="color: #000040;">^</span> message<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
&nbsp;
<span style="color: #0000ff;">private</span><span style="color: #008080;">:</span>
    gcroot<span style="color: #000080;">&lt;</span>LogDelegate<span style="color: #000040;">^</span><span style="color: #000080;">&gt;</span> m_Delegate<span style="color: #008080;">;</span>
    LogNative m_Native<span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span>
&nbsp;
<span style="color: #0000ff;">public</span> ref <span style="color: #0000ff;">class</span> Logger
<span style="color: #008000;">&#123;</span>
<span style="color: #0000ff;">public</span><span style="color: #008080;">:</span>
    Logger<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>
    <span style="color: #008000;">&#123;</span>
        m_Logger <span style="color: #000080;">=</span> <span style="color: #0000dd;">new</span> NativeLogger<span style="color: #008000;">&#40;</span>gcnew LogDelegate<span style="color: #008000;">&#40;</span><span style="color: #0000dd;">this</span>, <span style="color: #000040;">&amp;</span>Logger<span style="color: #008080;">::</span><span style="color: #007788;">Log</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
        NativeFramework<span style="color: #008080;">::</span><span style="color: #007788;">RegisterLogger</span><span style="color: #008000;">&#40;</span>m_Logger<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span>
    ~Logger<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>
    <span style="color: #008000;">&#123;</span>
        this<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span><span style="color: #000040;">!</span>Logger<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span>
    <span style="color: #000040;">!</span>Logger<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>
    <span style="color: #008000;">&#123;</span>
        <span style="color: #0000dd;">delete</span> m_Logger<span style="color: #008080;">;</span>
        m_Logger <span style="color: #000080;">=</span> <span style="color: #0000ff;">NULL</span><span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span>
&nbsp;
    <span style="color: #0000ff;">void</span> Log<span style="color: #008000;">&#40;</span>String<span style="color: #000040;">^</span> message<span style="color: #008000;">&#41;</span>
    <span style="color: #008000;">&#123;</span>
        Console<span style="color: #008080;">::</span><span style="color: #007788;">WriteLine</span><span style="color: #008000;">&#40;</span>message<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span>
&nbsp;
<span style="color: #0000ff;">private</span><span style="color: #008080;">:</span>
    NativeLogger <span style="color: #000040;">*</span>m_Logger<span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span></pre></div></div>

<h2>Calling Conventions and other tweaks</h2>
<p>One snag that you might run into when using this technique to interop with native code is that by default <code>GetFunctionPointerForDelegate</code> will return a function pointer with stdcall calling conventions.  This is usually fine when you&#8217;re trying to use WinAPI callbacks, but sometimes you&#8217;ll need cdecl or one of the other conventions instead.  (You&#8217;ll note that all of the examples above used <code>__stdcall</code> functions.)</p>
<p>One way to handle this, using C++/CLI at least, is to define a native <code>__cdecl</code> (or whatever) function which you pass to the native API and which internally calls the native function pointer, thereby side-stepping the issue.  In some respects, this is similar to how the class-based callback example above works.</p>
<p>But there&#8217;s another way &#8212; the <code>UnmanagedFunctionPointer</code> attribute can be applied to the delegate type, and this allows you to specify options such as the calling convention and ANSI/Unicode string conversion.  For example, if <code>CALLBACK</code> had been missing from the longer-term parameter-based callback example (thereby making the callback function <code>__cdecl</code>), you could use exactly the same code but define the delegate like this:</p>

<div class="wp_syntax"><div class="code"><pre class="cpp" style="font-family:monospace;">    <span style="color: #008000;">&#91;</span>UnmanagedFunctionPointer<span style="color: #008000;">&#40;</span>CallingConvention <span style="color: #000080;">=</span> CallingConvention.<span style="color: #007788;">Cdecl</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#93;</span>
    delegate <span style="color: #0000ff;">void</span> LogDelegate<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">const</span> std<span style="color: #008080;">::</span><span style="color: #007788;">string</span><span style="color: #000040;">&amp;</span> message<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></pre></div></div>

<p>(And just like with P/Invoke, you can apply <code>MarshalAs</code> attributes to the parameters of the delegate to influence how the unmanaged function signature will appear and how data will be transferred across the boundary.)</p>
<p>It&#8217;s important to remember this &#8212; bugs involving calling conventions can manifest quite subtly, especially between stdcall and cdecl and if (as by default) functions use standard &#8220;stack frames&#8221; (because that often hides the problem) &#8212; and in fact if you actually try it, you&#8217;ll find that the example above is simple enough that it&#8217;ll still <em>appear</em> to work perfectly without the attribute.  (I once <a href="http://pueblo.sourceforge.net/doc/exclamation.php">posted a bit of a rant</a> on a particularly irritating example I encountered.)</p>
<h2>Afterword</h2>
<p>Hopefully this has cleared up some of the confusion and misconceptions stemming from my earlier post.  In particular one of the common mistakes I saw was to assume that only primitive types could be used, simply because I was using a BYTE array and count as my parameters in the previous post.  This was actually due to the requirements of the specific native library I was using; there&#8217;s no trouble at all in passing any native types through, even complex C++ classes; and in some cases it&#8217;s even possible to use managed types, as shown above.</p>
<p>As always, if there&#8217;s any more remaining confusion or other things that you&#8217;d like me to clarify, then please comment below (or in the Suggestion Box).</p>
]]></content:encoded>
			<wfw:commentRss>http://lambert.geek.nz/2011/12/19/appdomains-and-unmanaged-callbacks-redux/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>111111111111</title>
		<link>http://lambert.geek.nz/2011/11/11/111111/</link>
		<comments>http://lambert.geek.nz/2011/11/11/111111/#comments</comments>
		<pubDate>Thu, 10 Nov 2011 22:11:54 +0000</pubDate>
		<dc:creator>Miral</dc:creator>
				<category><![CDATA[Random]]></category>

		<guid isPermaLink="false">http://lambert.geek.nz/?p=197</guid>
		<description><![CDATA[<p>I&#8217;m retroactively declaring this as a significant post date. (Hey, it&#8217;s been two years since I last did this.)</p> <p>Historical Significance.</p> ]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m retroactively declaring this as a significant post date. <img src='http://lambert.geek.nz/wpdata/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />   (Hey, it&#8217;s been two years since I last did this.)</p>
<p><a href="http://en.wikipedia.org/wiki/November_11">Historical Significance</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://lambert.geek.nz/2011/11/11/111111/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Conversion Filter</title>
		<link>http://lambert.geek.nz/2011/10/05/conversion-filter/</link>
		<comments>http://lambert.geek.nz/2011/10/05/conversion-filter/#comments</comments>
		<pubDate>Tue, 04 Oct 2011 21:05:15 +0000</pubDate>
		<dc:creator>Miral</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[.NET]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[conversion]]></category>
		<category><![CDATA[WPF]]></category>

		<guid isPermaLink="false">http://lambert.geek.nz/?p=177</guid>
		<description><![CDATA[<p>Finally, the last post in my series about conversion and the LookupConverter.</p> <p>This is just a quick addition to extend the capabilities of the LookupConverter, specifically to allow it to run a bit of code to determine which resulting value to use. I&#8217;ve actually never used this in a real-world scenario myself (I&#8217;ve always found [...]]]></description>
			<content:encoded><![CDATA[<p>Finally, the last post in my series about conversion and <a href="http://lambert.geek.nz/2011/06/10/a-tableau-of-conversion/">the <code>LookupConverter</code></a>.</p>
<p>This is just a quick addition to extend the capabilities of the <code>LookupConverter</code>, specifically to allow it to run a bit of code to determine which resulting value to use.  I&#8217;ve actually never used this in a real-world scenario myself (I&#8217;ve always found alternatives), since the goal of the <code>LookupConverter</code> in the first place was to <em>avoid</em> having to write code, and because for obvious reasons this will only work in a one-way scenario.  But some people might find it useful.<br />
<span id="more-177"></span><br />
To start with, the <code>LookupConversion</code> class from the previous post needs this added to it:</p>

<div class="wp_syntax"><div class="code"><pre class="csharp" style="font-family:monospace;">    <span style="color: #008080; font-style: italic;">/// &lt;summary&gt;</span>
    <span style="color: #008080; font-style: italic;">/// If this accepts the incoming object, then the conversion applies.</span>
    <span style="color: #008080; font-style: italic;">/// &lt;/summary&gt;</span>
    <span style="color: #0600FF; font-weight: bold;">public</span> <span style="color: #0600FF; font-weight: bold;">event</span> FilterEventHandler Filter<span style="color: #008000;">;</span>
    <span style="color: #0600FF; font-weight: bold;">private</span> <span style="color: #6666cc; font-weight: bold;">void</span> OnFilter<span style="color: #008000;">&#40;</span>FilterEventArgs e<span style="color: #008000;">&#41;</span>
    <span style="color: #008000;">&#123;</span>
        var handler <span style="color: #008000;">=</span> Filter<span style="color: #008000;">;</span>
        <span style="color: #0600FF; font-weight: bold;">if</span> <span style="color: #008000;">&#40;</span>handler <span style="color: #008000;">!=</span> <span style="color: #0600FF; font-weight: bold;">null</span><span style="color: #008000;">&#41;</span>
        <span style="color: #008000;">&#123;</span>
            handler<span style="color: #008000;">&#40;</span><span style="color: #0600FF; font-weight: bold;">this</span>, e<span style="color: #008000;">&#41;</span><span style="color: #008000;">;</span>
        <span style="color: #008000;">&#125;</span>
    <span style="color: #008000;">&#125;</span></pre></div></div>

<p>Fairly basic event stuff.  Finally, the <code>Matches</code> method needs to be changed to:</p>

<div class="wp_syntax"><div class="code"><pre class="csharp" style="font-family:monospace;">    <span style="color: #0600FF; font-weight: bold;">public</span> <span style="color: #6666cc; font-weight: bold;">bool</span> Matches<span style="color: #008000;">&#40;</span><span style="color: #6666cc; font-weight: bold;">object</span> value<span style="color: #008000;">&#41;</span>
    <span style="color: #008000;">&#123;</span>
        <span style="color: #0600FF; font-weight: bold;">if</span> <span style="color: #008000;">&#40;</span>Filter <span style="color: #008000;">!=</span> <span style="color: #0600FF; font-weight: bold;">null</span><span style="color: #008000;">&#41;</span>
        <span style="color: #008000;">&#123;</span>
            <span style="color: #008080; font-style: italic;">// this little hack is because the irritating WPF designers gave it an internal constructor... (grumble)</span>
            var e <span style="color: #008000;">=</span> <span style="color: #008000;">&#40;</span>FilterEventArgs<span style="color: #008000;">&#41;</span> Activator<span style="color: #008000;">.</span><span style="color: #0000FF;">CreateInstance</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">typeof</span><span style="color: #008000;">&#40;</span>FilterEventArgs<span style="color: #008000;">&#41;</span>, BindingFlags<span style="color: #008000;">.</span><span style="color: #0000FF;">NonPublic</span>,
                                                               <span style="color: #0600FF; font-weight: bold;">null</span>, <span style="color: #008000;">new</span><span style="color: #008000;">&#91;</span><span style="color: #008000;">&#93;</span> <span style="color: #008000;">&#123;</span> value <span style="color: #008000;">&#125;</span>, <span style="color: #0600FF; font-weight: bold;">null</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">;</span>
            OnFilter<span style="color: #008000;">&#40;</span>e<span style="color: #008000;">&#41;</span><span style="color: #008000;">;</span>
            <span style="color: #0600FF; font-weight: bold;">if</span> <span style="color: #008000;">&#40;</span>e<span style="color: #008000;">.</span><span style="color: #0000FF;">Accepted</span><span style="color: #008000;">&#41;</span>
            <span style="color: #008000;">&#123;</span>
                <span style="color: #0600FF; font-weight: bold;">return</span> <span style="color: #0600FF; font-weight: bold;">true</span><span style="color: #008000;">;</span>
            <span style="color: #008000;">&#125;</span>
        <span style="color: #008000;">&#125;</span>
        <span style="color: #0600FF; font-weight: bold;">if</span> <span style="color: #008000;">&#40;</span><span style="color: #0600FF; font-weight: bold;">From</span> <span style="color: #008000;">==</span> DependencyProperty<span style="color: #008000;">.</span><span style="color: #0000FF;">UnsetValue</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span> <span style="color: #0600FF; font-weight: bold;">return</span> <span style="color: #0600FF; font-weight: bold;">true</span><span style="color: #008000;">;</span> <span style="color: #008000;">&#125;</span>
        <span style="color: #0600FF; font-weight: bold;">return</span> ConversionUtilities<span style="color: #008000;">.</span><span style="color: #0000FF;">EqualsWithConversion</span><span style="color: #008000;">&#40;</span><span style="color: #0600FF; font-weight: bold;">From</span>, value<span style="color: #008000;">&#41;</span><span style="color: #008000;">;</span>
    <span style="color: #008000;">&#125;</span></pre></div></div>

<p>One caveat with this is that since <code>FilterEventArgs</code> only has an internal constructor, full trust is required to create an instance via reflection instead (silly library designers!).  This shouldn&#8217;t be an issue for most WPF apps, but if you&#8217;re targeting Silverlight or some other partial-trust scenario then you may need to create your own duplicate of the <code>FilterEventArgs</code> class and use that instead.</p>
<p>Well, that about wraps it up for this particular conversion topic.  Next time, I can finally post that unrelated topic I&#8217;ve had sitting as a draft for over a year. <img src='http://lambert.geek.nz/wpdata/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://lambert.geek.nz/2011/10/05/conversion-filter/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>A Tableau of Conversion</title>
		<link>http://lambert.geek.nz/2011/06/10/a-tableau-of-conversion/</link>
		<comments>http://lambert.geek.nz/2011/06/10/a-tableau-of-conversion/#comments</comments>
		<pubDate>Thu, 09 Jun 2011 17:10:37 +0000</pubDate>
		<dc:creator>Miral</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[.NET]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[conversion]]></category>
		<category><![CDATA[WPF]]></category>
		<category><![CDATA[XAML]]></category>

		<guid isPermaLink="false">http://lambert.geek.nz/?p=144</guid>
		<description><![CDATA[<p>Some people might be wondering why I said that the last two Programming posts were part of a series &#8212; after all, the first one was a utility class to help out with type conversion, while the second one focused on using enumerations in the UI. How is that a series? Well, it&#8217;s this post [...]]]></description>
			<content:encoded><![CDATA[<p>Some people might be wondering why I said that the last two Programming posts were part of a series &#8212; after all, the <a href="http://lambert.geek.nz/2011/03/01/clever-conversion/">first one</a> was a utility class to help out with type conversion, while the <a href="http://lambert.geek.nz/2011/06/03/combos-of-enums/">second one</a> focused on using enumerations in the UI.  How is that a series?  Well, it&#8217;s this post which should help to tie everything together.</p>
<p>I mentioned in the last post that a significant drawback of the technique presented there was that it presents the internal names from the code directly to the user.  Sometimes that&#8217;s ok, if you&#8217;re writing something for internal use, or if the names are short enough (a single word) and intended for an audience that speaks a single language.  But that still eliminates a lot of potential usefulness.</p>
<p>As a reminder, the (somewhat contrived) example from the previous post went something like this:</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;Window.Resources<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;ObjectDataProvider</span> <span style="color: #000066;">x:Key</span>=<span style="color: #ff0000;">&quot;ReportTypes&quot;</span> <span style="color: #000066;">ObjectType</span>=<span style="color: #ff0000;">&quot;{x:Type System:Enum}&quot;</span> <span style="color: #000066;">MethodName</span>=<span style="color: #ff0000;">&quot;GetValues&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;ObjectDataProvider.MethodParameters<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
            <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;x:Type</span> <span style="color: #000066;">TypeName</span>=<span style="color: #ff0000;">&quot;app:ReportType&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/ObjectDataProvider.MethodParameters<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/ObjectDataProvider<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;app:ReportTypesConverter</span> <span style="color: #000066;">x:Key</span>=<span style="color: #ff0000;">&quot;ReportTypesConverter&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;DataTemplate</span> <span style="color: #000066;">DataType</span>=<span style="color: #ff0000;">&quot;{x:Type app:ReportTypes}&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;TextBlock</span> <span style="color: #000066;">Text</span>=<span style="color: #ff0000;">&quot;{Binding Converter={StaticResource ReportTypesConverter}}&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/DataTemplate<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/Window.Resources<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
...
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;ComboBox</span> <span style="color: #000066;">ItemsSource</span>=<span style="color: #ff0000;">&quot;{Binding Source={StaticResource ReportTypes}}&quot;</span> <span style="color: #000066;">SelectedItem</span>=<span style="color: #ff0000;">&quot;{Binding ReportType, Mode=TwoWay}&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span></pre></div></div>

<p>But the <code>ReportTypesConverter</code> isn&#8217;t very satisfactory there &#8212; it requires specific code to be written for each enum type for each set of different text you want to provide (which can potentially mean that in some cases you&#8217;ll need more than one converter for a single enum type, if it&#8217;s used in different contexts where you want to use different text).  And something just feels wrong about putting something so fundamentally UI-related as what text to display in the combo box in the code of a converter class rather than in the view itself.</p>
<p>So I went looking for a better way. <span id="more-144"></span> And just for a change of pace, I&#8217;ll present the usage cases for my solution first:</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;Window.Resources<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;lib:LookupConverter</span> <span style="color: #000066;">x:Key</span>=<span style="color: #ff0000;">&quot;ReportTypesConverter&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;lib:LookupConversion</span> <span style="color: #000066;">From</span>=<span style="color: #ff0000;">&quot;Basic&quot;</span> <span style="color: #000066;">To</span>=<span style="color: #ff0000;">&quot;Basic Report&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;lib:LookupConversion</span> <span style="color: #000066;">From</span>=<span style="color: #ff0000;">&quot;Extended&quot;</span> <span style="color: #000066;">To</span>=<span style="color: #ff0000;">&quot;Enhanced Report (includes section B)&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
        ...
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/lib:LookupConversion<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/Window.Resources<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></div></div>

<p>It&#8217;s still a converter, but the values to be returned for each source value are given in table form within the XAML itself, instead of having to be listed in the code.  This means that the same converter can be used for lots of different conversions.  The real beauty of it though is that thanks to the conversion helper from the first post in the series, the actual values to be converted enjoy the same automatic type conversion benefits as XAML normally provides for fixed-type properties, despite being variable-type properties.  This allows you to just list &#8220;Basic&#8221; instead of &#8220;{x:Static app:ReportTypes.Basic}&#8221;, and so on.</p>
<p>And this isn&#8217;t limited to just producing text values, either.  Let&#8217;s say you have a control presenting log information; each entry has a type (info, warning, error, etc) and a message, and you want to use different colours to denote the different types of messages.  Again, you <em>could</em> write a custom converter for this job, but it&#8217;s easier to use a <code>LookupConverter</code>:</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;Window.Resources<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;lib:LookupConverter</span> <span style="color: #000066;">x:Key</span>=<span style="color: #ff0000;">&quot;LogColourConverter&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;lib:LookupConversion</span> <span style="color: #000066;">From</span>=<span style="color: #ff0000;">&quot;Warning&quot;</span> <span style="color: #000066;">To</span>=<span style="color: #ff0000;">&quot;Orange&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;lib:LookupConversion</span> <span style="color: #000066;">From</span>=<span style="color: #ff0000;">&quot;Error&quot;</span> <span style="color: #000066;">To</span>=<span style="color: #ff0000;">&quot;Red&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/lib:LookupConverter<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;DataTemplate</span> <span style="color: #000066;">x:Key</span>=<span style="color: #ff0000;">&quot;LogEntryTemplate&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;TextBlock</span> <span style="color: #000066;">Foreground</span>=<span style="color: #ff0000;">&quot;{Binding MessageType, Converter={StaticResource LogColourConverter}}&quot;</span></span>
<span style="color: #009900;">                   <span style="color: #000066;">Text</span>=<span style="color: #ff0000;">&quot;{Binding Message}&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/DataTemplate</span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/Window.Resources<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></div></div>

<p>Note that again, <code>MessageType</code> is an enum, but this time we&#8217;re not covering all the possible values &#8212; anything that&#8217;s not listed in the table (ie. anything that&#8217;s not a <code>Warning</code> or <code>Error</code>) will make WPF pretend the binding wasn&#8217;t present, and thereby use the default <code>Foreground</code> from parent controls, styles, or the user&#8217;s theme.  And if you did want to specify a default, then it&#8217;s as simple as adding a final entry to the table which omits the <code>From</code> clause &#8212; the converter will assume that this matches anything:</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;">        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;lib:LookupConversion</span> <span style="color: #000066;">To</span>=<span style="color: #ff0000;">&quot;Black&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span></pre></div></div>

<p>(Another way to define a default value is to set a <code>FallbackValue</code> on the binding that references the converter.)</p>
<p>There is another use of this converter which is a particular favourite of mine. In <a href="http://lambert.geek.nz/2010/02/25/templates-galore/">an earlier post</a> I talked about the <code>DataTemplateSelector</code> and how much of a pain in the butt it was, and showed a way to use styles to select templates instead.  Well, this converter can help with that too.  The case shown on that page, selecting between one template and another depending on a single boolean property, is probably simple enough that styles make the most sense, but it can be rewritten using a <code>LookupConverter</code> if you like:</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;Window.Resources<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;DataTemplate</span> <span style="color: #000066;">x:Key</span>=<span style="color: #ff0000;">&quot;ReadOnlyTemplate&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>...<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/DataTemplate<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;DataTemplate</span> <span style="color: #000066;">x:Key</span>=<span style="color: #ff0000;">&quot;EditableTemplate&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>...<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/DataTemplate<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;lib:LookupConverter</span> <span style="color: #000066;">x:Key</span>=<span style="color: #ff0000;">&quot;EditableTemplateSelector&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;lib:LookupConversion</span> <span style="color: #000066;">From</span>=<span style="color: #ff0000;">&quot;False&quot;</span> <span style="color: #000066;">To</span>=<span style="color: #ff0000;">&quot;{StaticResource EditableTemplate}&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;lib:LookupConversion</span> <span style="color: #000066;">From</span>=<span style="color: #ff0000;">&quot;True&quot;</span> <span style="color: #000066;">To</span>=<span style="color: #ff0000;">&quot;{StaticResource ReadOnlyTemplate}&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/lib:LookupConverter<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;DataTemplate</span> <span style="color: #000066;">x:Key</span>=<span style="color: #ff0000;">&quot;FooTemplate&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;ContentPresenter</span> <span style="color: #000066;">Content</span>=<span style="color: #ff0000;">&quot;{Binding}&quot;</span></span>
<span style="color: #009900;">                          <span style="color: #000066;">ContentTemplate</span>=<span style="color: #ff0000;">&quot;{Binding IsReadOnly, Converter={StaticResource EditableTemplateSelector}}&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/DataTemplate<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/Window.Resources<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></div></div>

<p>Where this converter excels is if you have a larger group of templates to select between &#8212; for example if you wanted to use a different template for all 5 possible <code>ReportTypes</code>.</p>
<p>As with any other property assignment in XAML, you&#8217;re not limited to simple values &#8212; you can use XAML&#8217;s extended assignment syntax to assign entire trees of objects to either of <code>From</code> or <code>To</code> if you so require; for example you can inline the templates above rather than specifying them as separate resources if you want:</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;Window.Resources<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;lib:LookupConverter</span> <span style="color: #000066;">x:Key</span>=<span style="color: #ff0000;">&quot;EditableTemplateSelector&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;lib:LookupConversion</span> <span style="color: #000066;">From</span>=<span style="color: #ff0000;">&quot;False&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
            <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;lib:LookupConversion.To<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
                <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;DataTemplate<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>... editable template ...<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/DataTemplate<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
            <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/lib:LookupConversion.To<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/lib:LookupConversion<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;lib:LookupConversion</span> <span style="color: #000066;">From</span>=<span style="color: #ff0000;">&quot;True&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
            <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;lib:LookupConversion.To<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
                <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;DataTemplate<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>... read-only template ...<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/DataTemplate<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
            <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/lib:LookupConversion.To<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/lib:LookupConversion<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/lib:LookupConverter<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/Window.Resources<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></div></div>

<p>Of course, this converter still has some limitations.  Because of the way the conversion helper works, it needs to know the types of both the <code>From</code> and <code>To</code> values, and it&#8217;s limited to one auto-conversion step.  It handles the former with the help of the binding itself &#8212; it assumes that the <code>From</code> value is convertible to the binding&#8217;s source and that the <code>To</code> value is convertible to the binding&#8217;s target.  The second is a safety measure, so that you don&#8217;t get hit with surprise conversions to completely the wrong values &#8212; usually it won&#8217;t be an issue especially with the standard WPF types, since they&#8217;re usually smart enough to handle the edge cases themselves; for example, you&#8217;ll notice above that you can use &#8220;Red&#8221; (a string describing a <code>Color</code>) to bind to <code>Background</code> (which takes a <code>Brush</code>), because WPF itself defines a conversion between string and <code>Brush</code> (by creating a <code>SolidColorBrush</code> with that colour).  But occasionally these limits may bite you (eg. when binding to a property of type <code>object</code>, thereby providing no type hints for the conversion); that doesn&#8217;t mean that you can&#8217;t use the converter, but you may need to supply an object of the exact type you want (via <code>{x:Static}</code> or extended property assignment) rather than relying on type inference.</p>
<p>And in its current form you can&#8217;t use bindings, although you can use resources (as shown above).  This is because the conversions aren&#8217;t defined as <code>DependencyObject</code>s, so can&#8217;t support a <code>DependencyProperty</code>; while it could be possible to change that, unless you start getting <em>really</em> tricky with the WPF code you can&#8217;t use bindings anyway, since a converter is usually in the resources and items in the resources typically don&#8217;t have access to the binding context of their containers.  And usually when you start to want to get things that complicated you ought to be using view-model properties instead of complex bindings anyway.</p>
<p>Finally, there are some performance consequences.  Whenever the source property changes, the converter is consulted and it has to attempt conversion and comparison on each entry in turn.  These are usually too fast to notice, and property changes are usually infrequent enough for this to not matter, but it is something to bear in mind.  (Also note that this is potentially not much different from the rest of the property binding and styling system in WPF, although there are some potential optimisation opportunities available there which this converter can&#8217;t take advantage of.)</p>
<p>But it&#8217;s still quite a handy converter to have in the toolbelt. <img src='http://lambert.geek.nz/wpdata/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />   I&#8217;m interested to hear about any other interesting uses people can come up with.</p>
<p>And so at last, here&#8217;s the code.  Remember, you&#8217;ll also need <a href="http://lambert.geek.nz/2011/03/01/clever-conversion/">the <code>ConversionUtilities</code> class</a>:</p>

<div class="wp_syntax"><div class="code"><pre class="csharp" style="font-family:monospace;"><span style="color: #008080; font-style: italic;">/// &lt;summary&gt;Conversion specifier class for the LookupConverter.&lt;/summary&gt;</span>
<span style="color: #0600FF; font-weight: bold;">public</span> <span style="color: #6666cc; font-weight: bold;">class</span> LookupConversion
<span style="color: #008000;">&#123;</span>
    <span style="color: #0600FF; font-weight: bold;">public</span> LookupConversion<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>
    <span style="color: #008000;">&#123;</span>
        <span style="color: #0600FF; font-weight: bold;">From</span> <span style="color: #008000;">=</span> To <span style="color: #008000;">=</span> DependencyProperty<span style="color: #008000;">.</span><span style="color: #0000FF;">UnsetValue</span><span style="color: #008000;">;</span>
    <span style="color: #008000;">&#125;</span>
&nbsp;
    <span style="color: #008080; font-style: italic;">/// &lt;summary&gt;If the incoming object compares equal to this, then the conversion applies.&lt;/summary&gt;</span>
    <span style="color: #0600FF; font-weight: bold;">public</span> <span style="color: #6666cc; font-weight: bold;">object</span> <span style="color: #0600FF; font-weight: bold;">From</span> <span style="color: #008000;">&#123;</span> get<span style="color: #008000;">;</span> set<span style="color: #008000;">;</span> <span style="color: #008000;">&#125;</span>
&nbsp;
    <span style="color: #008080; font-style: italic;">/// &lt;summary&gt;The object to use if this conversion applies.&lt;/summary&gt;</span>
    <span style="color: #0600FF; font-weight: bold;">public</span> <span style="color: #6666cc; font-weight: bold;">object</span> To <span style="color: #008000;">&#123;</span> get<span style="color: #008000;">;</span> set<span style="color: #008000;">;</span> <span style="color: #008000;">&#125;</span>
&nbsp;
    <span style="color: #0600FF; font-weight: bold;">public</span> <span style="color: #6666cc; font-weight: bold;">bool</span> Matches<span style="color: #008000;">&#40;</span><span style="color: #6666cc; font-weight: bold;">object</span> value<span style="color: #008000;">&#41;</span>
    <span style="color: #008000;">&#123;</span>
        <span style="color: #0600FF; font-weight: bold;">if</span> <span style="color: #008000;">&#40;</span><span style="color: #0600FF; font-weight: bold;">From</span> <span style="color: #008000;">==</span> DependencyProperty<span style="color: #008000;">.</span><span style="color: #0000FF;">UnsetValue</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span> <span style="color: #0600FF; font-weight: bold;">return</span> <span style="color: #0600FF; font-weight: bold;">true</span><span style="color: #008000;">;</span> <span style="color: #008000;">&#125;</span>
        <span style="color: #0600FF; font-weight: bold;">return</span> ConversionUtilities<span style="color: #008000;">.</span><span style="color: #0000FF;">EqualsWithConversion</span><span style="color: #008000;">&#40;</span><span style="color: #0600FF; font-weight: bold;">From</span>, value<span style="color: #008000;">&#41;</span><span style="color: #008000;">;</span>
    <span style="color: #008000;">&#125;</span>
&nbsp;
    <span style="color: #0600FF; font-weight: bold;">public</span> <span style="color: #6666cc; font-weight: bold;">bool</span> MatchesBack<span style="color: #008000;">&#40;</span><span style="color: #6666cc; font-weight: bold;">object</span> value<span style="color: #008000;">&#41;</span>
    <span style="color: #008000;">&#123;</span>
        <span style="color: #0600FF; font-weight: bold;">if</span> <span style="color: #008000;">&#40;</span>To <span style="color: #008000;">==</span> DependencyProperty<span style="color: #008000;">.</span><span style="color: #0000FF;">UnsetValue</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span> <span style="color: #0600FF; font-weight: bold;">return</span> <span style="color: #0600FF; font-weight: bold;">false</span><span style="color: #008000;">;</span> <span style="color: #008000;">&#125;</span>
        <span style="color: #0600FF; font-weight: bold;">return</span> ConversionUtilities<span style="color: #008000;">.</span><span style="color: #0000FF;">EqualsWithConversion</span><span style="color: #008000;">&#40;</span>To, value<span style="color: #008000;">&#41;</span><span style="color: #008000;">;</span>
    <span style="color: #008000;">&#125;</span>
<span style="color: #008000;">&#125;</span>
&nbsp;
<span style="color: #008080; font-style: italic;">/// &lt;summary&gt;</span>
<span style="color: #008080; font-style: italic;">/// Looks up a value against a list of conversions (&lt;see cref=&quot;LookupConversion&quot; /&gt; objects) in order.</span>
<span style="color: #008080; font-style: italic;">/// The first conversion that is satisfied will determine the resulting output value.</span>
<span style="color: #008080; font-style: italic;">/// &lt;/summary&gt;</span>
<span style="color: #008000;">&#91;</span>ContentProperty<span style="color: #008000;">&#40;</span><span style="color: #666666;">&quot;Conversions&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#93;</span>
<span style="color: #0600FF; font-weight: bold;">public</span> <span style="color: #6666cc; font-weight: bold;">class</span> LookupConverter <span style="color: #008000;">:</span> IValueConverter
<span style="color: #008000;">&#123;</span>
    <span style="color: #0600FF; font-weight: bold;">private</span> <span style="color: #0600FF; font-weight: bold;">readonly</span> List<span style="color: #008000;">&lt;</span>LookupConversion<span style="color: #008000;">&gt;</span> _Conversions <span style="color: #008000;">=</span> <span style="color: #008000;">new</span> List<span style="color: #008000;">&lt;</span>LookupConversion<span style="color: #008000;">&gt;</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">;</span>
    <span style="color: #0600FF; font-weight: bold;">public</span> List<span style="color: #008000;">&lt;</span>LookupConversion<span style="color: #008000;">&gt;</span> Conversions
    <span style="color: #008000;">&#123;</span>
        get <span style="color: #008000;">&#123;</span> <span style="color: #0600FF; font-weight: bold;">return</span> _Conversions<span style="color: #008000;">;</span> <span style="color: #008000;">&#125;</span>
    <span style="color: #008000;">&#125;</span>
&nbsp;
    <span style="color: #0600FF; font-weight: bold;">public</span> <span style="color: #6666cc; font-weight: bold;">object</span> Convert<span style="color: #008000;">&#40;</span><span style="color: #6666cc; font-weight: bold;">object</span> value, Type targetType, <span style="color: #6666cc; font-weight: bold;">object</span> parameter, CultureInfo culture<span style="color: #008000;">&#41;</span>
    <span style="color: #008000;">&#123;</span>
        <span style="color: #0600FF; font-weight: bold;">foreach</span> <span style="color: #008000;">&#40;</span>var conversion <span style="color: #0600FF; font-weight: bold;">in</span> Conversions<span style="color: #008000;">&#41;</span>
        <span style="color: #008000;">&#123;</span>
            <span style="color: #0600FF; font-weight: bold;">if</span> <span style="color: #008000;">&#40;</span>conversion<span style="color: #008000;">.</span><span style="color: #0000FF;">Matches</span><span style="color: #008000;">&#40;</span>value<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span>
            <span style="color: #008000;">&#123;</span>
                <span style="color: #0600FF; font-weight: bold;">return</span> ConversionUtilities<span style="color: #008000;">.</span><span style="color: #0000FF;">Convert</span><span style="color: #008000;">&#40;</span>conversion<span style="color: #008000;">.</span><span style="color: #0000FF;">To</span>, targetType<span style="color: #008000;">&#41;</span><span style="color: #008000;">;</span>
            <span style="color: #008000;">&#125;</span>
        <span style="color: #008000;">&#125;</span>
        <span style="color: #0600FF; font-weight: bold;">return</span> DependencyProperty<span style="color: #008000;">.</span><span style="color: #0000FF;">UnsetValue</span><span style="color: #008000;">;</span>
    <span style="color: #008000;">&#125;</span>
&nbsp;
    <span style="color: #0600FF; font-weight: bold;">public</span> <span style="color: #6666cc; font-weight: bold;">object</span> ConvertBack<span style="color: #008000;">&#40;</span><span style="color: #6666cc; font-weight: bold;">object</span> value, Type targetType, <span style="color: #6666cc; font-weight: bold;">object</span> parameter, CultureInfo culture<span style="color: #008000;">&#41;</span>
    <span style="color: #008000;">&#123;</span>
        <span style="color: #0600FF; font-weight: bold;">foreach</span> <span style="color: #008000;">&#40;</span>var conversion <span style="color: #0600FF; font-weight: bold;">in</span> Conversions<span style="color: #008000;">&#41;</span>
        <span style="color: #008000;">&#123;</span>
            <span style="color: #0600FF; font-weight: bold;">if</span> <span style="color: #008000;">&#40;</span>conversion<span style="color: #008000;">.</span><span style="color: #0000FF;">MatchesBack</span><span style="color: #008000;">&#40;</span>value<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span>
            <span style="color: #008000;">&#123;</span>
                <span style="color: #0600FF; font-weight: bold;">return</span> ConversionUtilities<span style="color: #008000;">.</span><span style="color: #0000FF;">Convert</span><span style="color: #008000;">&#40;</span>conversion<span style="color: #008000;">.</span><span style="color: #0600FF; font-weight: bold;">From</span>, targetType<span style="color: #008000;">&#41;</span><span style="color: #008000;">;</span>
            <span style="color: #008000;">&#125;</span>
        <span style="color: #008000;">&#125;</span>
        <span style="color: #0600FF; font-weight: bold;">return</span> DependencyProperty<span style="color: #008000;">.</span><span style="color: #0000FF;">UnsetValue</span><span style="color: #008000;">;</span>
    <span style="color: #008000;">&#125;</span>
<span style="color: #008000;">&#125;</span></pre></div></div>

<p>(Yep, that&#8217;s right, this is a bidirectional converter, so it can be used on <code>TwoWay</code> properties &#8212; but having said that, I&#8217;ve yet to find a case when that&#8217;s useful.)</p>
]]></content:encoded>
			<wfw:commentRss>http://lambert.geek.nz/2011/06/10/a-tableau-of-conversion/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Fable the Third</title>
		<link>http://lambert.geek.nz/2011/06/07/fable-the-third/</link>
		<comments>http://lambert.geek.nz/2011/06/07/fable-the-third/#comments</comments>
		<pubDate>Mon, 06 Jun 2011 17:07:58 +0000</pubDate>
		<dc:creator>Miral</dc:creator>
				<category><![CDATA[Games]]></category>
		<category><![CDATA[Fable]]></category>

		<guid isPermaLink="false">http://lambert.geek.nz/?p=155</guid>
		<description><![CDATA[<p>Fable 3 (Amazon, Mighty Ape, Steam) was released a month or so ago (for PC, anyway), and I finished my first playthrough not that long ago.</p> <p>I&#8217;d seen fairly mixed reviews of the Xbox version beforehand, but I was going in with fairly light expectations &#8212; I&#8217;d played Fable: TLC (on PC too, of course) [...]]]></description>
			<content:encoded><![CDATA[<p><strong>Fable 3</strong> (<a href="http://www.amazon.com/gp/product/B002I0KO8I?ie=UTF8&amp;tag=thougfrommira-20&amp;linkCode=as2&amp;camp=1789&amp;creative=9325&amp;creativeASIN=B002I0KO8I" target="_blank">Amazon</a><img src="http://www.assoc-amazon.com/e/ir?t=thougfrommira-20&amp;l=as2&amp;o=1&amp;a=B002I0KO8I" class="amazon-assoc" border="0" height="1" width="1" />, <a href="http://www.mightyape.co.nz/product/PC-Games/Fable-III/6700305/?r=1529217" target="_blank">Mighty Ape</a>, <a href="http://store.steampowered.com/app/105400/" target="_blank">Steam</a>) was released a month or so ago (for PC, anyway), and I finished my first playthrough not that long ago.</p>
<p>I&#8217;d seen fairly mixed reviews of the Xbox version beforehand, but I was going in with fairly light expectations &#8212; I&#8217;d played Fable: TLC (on PC too, of course) previously and found it to be a fairly light-hearted and silly RPG, but still pretty fun. I haven&#8217;t played Fable 2 (since it never made it to PC), but I was expecting something similar from Fable 3.<br />
<span id="more-155"></span><br />
And I think it met those expectations. It&#8217;s still quite light-hearted and silly (what other series would have a chicken as the main character of the introductory cinematic, and featured on all the loading screens?), not taking itself particularly seriously and aiming for fun rather than realism or number-crunching. And it delivers on these quite nicely.</p>
<p>In terms of performance, I never really had any serious issues with the game, although I did encounter a few minor bugs. Specifically:</p>
<ul>
<li>Sometimes the voice-over announcements in the chicken race failed to play, which sometimes made it quite hard to work out who had won.</li>
<li>One of my in-game children became merely &#8220;Fine&#8221; (instead of Happy or better) and demanded a toy to return to Happy status &#8212; but on being given a toy, their status reset to the centre of the &#8220;Fine&#8221; bar, rather than going up a grade.</li>
<li>The pathfinding of the dog wasn&#8217;t particularly good &#8212; on rare occasions he&#8217;d get stuck behind something and I&#8217;d have to go back and find him, but a more common problem would be when he&#8217;d bark to alert me to the presence of a dig spot right next to where I was standing but then spending ages walking in circles behind some obstacle before finding his way past it and over to me so that I could dig there.</li>
<li>Another mysterious problem with the dog is that he lacked a sense of height &#8212; on a few occasions he&#8217;d bark and lead me to a location directly above or below where the treasure actually was (usually when the way to get there was a long way away).</li>
</ul>
<p>Character interaction is still basically the same as in earlier games &#8212; while you have a voice in cutscenes, when interacting with the villagers during normal gameplay you&#8217;re restricted to a fairly limited palette of gestures/emotes (or &#8220;expressions&#8221;); they&#8217;re kinda fun to play with at first, but they can get a bit old if you spend much time trying to impress (or terrify) the villagers &#8212; and there&#8217;s something a bit surreal about your hero walking up to random strangers and dancing or playing pat-a-cake with them (or ruder things), especially later in the game when your character is fairly well known. Although again, that&#8217;s part of the game not really taking itself seriously. Something else that might bother the role-players a bit is that some of the expressions (particularly the more evil ones) are locked until later in the game.</p>
<p>The plot itself seems reasonably decent; you&#8217;re starting out fairly small and working your way up to the big things, and there&#8217;s a bit of an upset towards the end when you learn about the Big Bad and some of the reasons behind the situation earlier on in the game. And you&#8217;re afforded a reasonable amount of opportunities to be good or evil, although as with most games &#8220;evil&#8221; is more &#8220;Chaotic Stupid&#8221; than anything else. One thing that&#8217;s nice about the endgame is that it tries to make you agonise about the decisions by offering you &#8220;good but expensive&#8221; vs. &#8220;evil but profitable&#8221;, and since you have to get a certain amount of gold or face destruction, sometimes that really does make the evil option tempting.</p>
<p>But in order to do that, it seems to make certain assumptions about your situation which don&#8217;t always really apply. For example, in my playthrough I already had about 10 million whenI assumed the throne, and since I was playing a nominally good character that meant that I immediately transferred all of it to the treasury, which is more than is required to achieve the best ending. Despite this,the book-keeper and Reaver still frequently whined about how it would be a good idea to do the evil things to build up the gold and frequently suggested that I would fail if I didn&#8217;t top it up some more from personal funds, despite that being obviously not true. (It was particularly silly when I ended the game with 2 million spare in the treasury and a further 8 million in personal funds.) Still, I can see what they were trying to do, and how it definitely could have caught some people out if they weren&#8217;t sufficiently prepared beforehand, so I applaud them for that.</p>
<p>Combat was decent; the auto-targeting was occasionally quite annoying when you&#8217;d be preparing some high-strength flourish or spell attack, only to have the stronger enemy you were trying to hit summon some weaker additional enemies in front and your attack would hit them instead. Still, it was fast and furious (and fun), although threat tended to be based on facing hordes of weaker monsters much more often than encounters with stronger monsters. It played well with mouse &amp; keyboard, but I can&#8217;t help but suspect that multi-weapon combos might have been easier with a controller &#8212; having different buttons for &#8220;sword attack&#8221; vs. &#8220;magic attack&#8221; vs. &#8220;gun attack&#8221; (as on controller) would let you switch between them much faster than (as on keyboard/mouse) having a single &#8220;attack&#8221; button with &#8220;select sword/magic/gun&#8221; keys (and mousewheel).</p>
<p>The side-quests were fun, for the most part; there are a few particular favourites (&#8220;The Game&#8221; and &#8220;The Final Insult&#8221; spring to mind, as does the final book from &#8220;The Pen is Mightier&#8230;&#8221;), and like I said before, the game doesn&#8217;t really take itself too seriously, which I quite like. The villager socialisation quests get old fairly quickly, though; invariably you do one or two expressions, at which point they ask you to take something to one of the neighbouring areas and return, then you can do some more expressions (if you want). This can mean quite a lot of travel back and forth between regions if you&#8217;re trying to befriend many villagers, although you can queue up several at once and do them all together to save some time. Fortunately, though, you don&#8217;t <em>really</em> need to befriend all that many villagers anyway, unless you&#8217;re trying to upgrade one of the weapons that has that as one of its conditions.</p>
<p>The coop multiplayer aspect is emphasised fairly strongly in this game; you can turn on floating orbs which appear (and speak) wherever other players are in the game, and you can invite other players into your world or trade items with them. This last one I actually find fairly annoying &#8212; I&#8217;m generally a bit of a completionist, I like to experience as much of a game as possible; as such I usually try to complete all side quests and collect all item types, although I do make some exceptions (eg. if I&#8217;m trying to play a good character then I won&#8217;t do the obviously-evil-goal quests). But because of the trading mechanic, the game was designed such that of the 50 unique weapons and 7 unique gem types possible, only about 25 and 4 of these (respectively) can be found in any individual game. For the rest, you have to trade with other players, which irritates my completionist side no end, especially since I don&#8217;t really like online play. (There&#8217;s also a Demon Door in the game which can only be opened with the help of a co-op partner. These doors are optional, of course, but they do each hide some kind of treasure.)</p>
<p>One of the other things that I found annoying was the 5-star dog potion DLC. Presumably this was introduced somewhat late in the life of the Xbox version, intended for those players on their second or subsequent playthroughs who didn&#8217;t want to worry about levelling up their dog&#8217;s skills in each game. I was planning to avoid it for my first playthough, since it felt like cheating. Unfortunately, one of the &#8220;helpful&#8221; features of the game is to remind you about the free DLC which is available, which resulted in it frequently reminding me that it was sitting there waiting for me to download it. Eventually I caved, thinking it&#8217;d be like the dog breed potions, which require you to visit your dog&#8217;s basket and manually apply them &#8212; that way I could have the DLC installed but not use it during my first playthrough. But sadly that&#8217;s not the case &#8212; that potion seems to automatically apply itself to your dog as soon as you open the unmarked &#8220;gift&#8221; package it appears in after the DLC is installed. So my dog received a &#8220;cheat&#8221; upgrade about half-way through the game, which made me sad.</p>
<p>But overall I think the biggest problem in the game was the lack of a clear inventory system. The Sanctuary was introduced at least in part because &#8220;players didn&#8217;t like scrolling through menus&#8221;, and it was kind of an interesting idea and a fun place to visit, and for the most part it worked well (especially since it had hotkeys to quickly jump between &#8220;rooms&#8221;) &#8212; and because John Cleese was there. It does stretch credulity a bit though that even in the middle of a heated battle the Hero can instantly freeze time and teleport to the Sanctuary to switch weapons or clothes, but can&#8217;t heal or anything during that time. (Makes sense from a gameplay perspective, quite strange from an in-world perspective.) But there was one key thing missing from the Sanctuary: some way to browse through the actual items (potions, food, trade items, gifts) you already possessed. What made this even worse is that when you were at a shop there&#8217;d be no corresponding indicator for how many of the items you already had either &#8212; for example, you might have found yourself a potion shop just prior to a big fight, but there&#8217;s absolutely no way to tell how many potions you already had, whether you were running low or had far more than you needed.</p>
<p>You weren&#8217;t left <em>completely</em> in the dark &#8212; for potions and food you could see how many were available during combat, but (in the case of healing potions and food) only if you&#8217;d been injured. And in the big towns there were pawn shops that would let you view your whole inventory (for the purposes of selling some of it). But neither of these are particularly convenient, especially if you&#8217;re in the middle of a quest or if you&#8217;re trying for a &#8220;realism&#8221; run and avoiding fast-travel. Another problem with this is that due to the lack of selectable inventory items they decided to make it so that you could only have one type of food on you at any given moment &#8212; which means that if you&#8217;ve already built up a stack of 10 apples, for example, buying one bit of pie or tofu will make you throw away all your apples and leave you with just that one food item. The game does give you a warning when it&#8217;ll happen, and it&#8217;s not a big loss, since food you find in chests or other loot containers around the world are always of whatever type you have on you, and they&#8217;re cheap enough for you to build up a stockpile again if you want to, but it is a bit weird.</p>
<p>So, overall, I did enjoy the game, which is the main thing, I guess. But it&#8217;s not without its flaws, and you shouldn&#8217;t go in expecting something deep, meaningful, or serious. That&#8217;s just not what the Fable series is about.</p>
<p>(One final thought concerning the DRM on this game; they did go a bit overboard, loading it down with GFWL and SecuROM as well as (if purchased on Steam) Steam itself. GFWL makes a certain amount of sense; it is a Microsoft game after all, and since the co-op component is woven so tightly into the game it would be difficult to replace GFWL&#8217;s networking and achievement system with eg. Steam&#8217;s, especially since that would probably result in segregating the players between bought-on-Steam vs. not-bought-on-Steam bases. The inclusion of SecuROM seemed bizarre and unnecessary, though, since both GFWL and Steam include activation components. But in the end, the combination kept itself reasonably in the background, and didn&#8217;t really interfere with gameplay at all, except in one way. Normally, I log into my PC with one user account but use &#8220;runas&#8221; to execute games under a different user profile (but still on the same desktop), in order to segregate the settings and avoid polluting my Documents folder with all the crazy folders various games seem to like creating there. Unfortunately, doing this seems to really annoy GFWL &#8212; for whatever reason the system it uses to download content completely fails under this scenario. So for this game I was forced to use &#8220;Switch User&#8221; to log in separately for gameplay. Which is survivable, it&#8217;s only a minor annoyance, but I do regard it as a bug.)</p>
]]></content:encoded>
			<wfw:commentRss>http://lambert.geek.nz/2011/06/07/fable-the-third/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Combos of Enums</title>
		<link>http://lambert.geek.nz/2011/06/03/combos-of-enums/</link>
		<comments>http://lambert.geek.nz/2011/06/03/combos-of-enums/#comments</comments>
		<pubDate>Thu, 02 Jun 2011 17:03:36 +0000</pubDate>
		<dc:creator>Miral</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[.NET]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[conversion]]></category>
		<category><![CDATA[WPF]]></category>
		<category><![CDATA[XAML]]></category>

		<guid isPermaLink="false">http://lambert.geek.nz/?p=136</guid>
		<description><![CDATA[<p>It&#8217;s probably about time that I continued on from my previous post. This one is just going to be a short one, but it&#8217;s a nice setup for the following post in the series.</p> <p>When you have a property which can only have one of a limited number of values, there are a few different [...]]]></description>
			<content:encoded><![CDATA[<p>It&#8217;s probably about time that I continued on from my <a href="http://lambert.geek.nz/2011/03/01/clever-conversion/">previous post</a>.  This one is just going to be a short one, but it&#8217;s a nice setup for the following post in the series.</p>
<p>When you have a property which can only have one of a limited number of values, there are a few different ways to represent it &#8212; both in the UI and in the code.  In the UI, the choice is usually between a combo box and a list box, with which one you choose partly driven by personal taste and partly based on whether you think it might be possible to support multiple selections in the future &#8212; in general, a combo box is ideal for cases which only support a single selection, and a list box for cases with multiple selections.  (These aren&#8217;t hard limitations, of course &#8212; you can have a single-select list box or a combo-box which does multi-select with a lingering drop-down or just via checkboxes in its drop-down, and sometimes you&#8217;ll want to do this for aesthetic or sizing reasons &#8212; but those are the conventions that people have come to expect.)</p>
<p>In the code, you can create a collection and fill it with all possible values as discrete objects; this certainly makes it nice and easy to bind to the UI, and is really the only option if all the possible values aren&#8217;t known at compile time (eg. you have to load them from a database, or you&#8217;re letting the user select between items they&#8217;ve already created in some other part of your software).  If you know all the possible values at compile time, though, and there isn&#8217;t any &#8220;extra&#8221; info you need to store about a single item, then an enumeration is a good fit to represent the value in your data model.</p>
<p>Once you have an enumeration in the data model, though, how do you get its values into the combo box?  One way of course is to &#8220;translate&#8221; it in your view-model layer, by converting it from the enum value to one of a collection of UI placeholder objects (as described above), and then back again.  That seems like quite a bit of overhead, though.</p>
<p>Another way to do it is to get the .NET framework itself to help you out.  There&#8217;s a static method you can call which returns a collection of all the possible values of an enum type (this is <code>Enum.GetValues</code>).  You could expose this as a property in your view-model and bind to it, but you can instead get the XAML to do all the work for you:</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;Window.Resources<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;ObjectDataProvider</span> <span style="color: #000066;">x:Key</span>=<span style="color: #ff0000;">&quot;ReportTypes&quot;</span> <span style="color: #000066;">ObjectType</span>=<span style="color: #ff0000;">&quot;{x:Type System:Enum}&quot;</span> <span style="color: #000066;">MethodName</span>=<span style="color: #ff0000;">&quot;GetValues&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;ObjectDataProvider.MethodParameters<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
            <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;x:Type</span> <span style="color: #000066;">TypeName</span>=<span style="color: #ff0000;">&quot;app:ReportType&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/ObjectDataProvider.MethodParameters<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/ObjectDataProvider<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/Window.Resources<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    ...
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;ComboBox</span> <span style="color: #000066;">ItemsSource</span>=<span style="color: #ff0000;">&quot;{Binding Source={StaticResource ReportTypes}}&quot;</span> <span style="color: #000066;">SelectedItem</span>=<span style="color: #ff0000;">&quot;{Binding ReportType, Mode=TwoWay}&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span></pre></div></div>

<p>(This will obtain the values in the same order in which they&#8217;re defined in the code, which is usually what you want &#8212; but you can interpose something which sorts the list as well if you like.)</p>
<p>If you try this for yourself, though, you&#8217;ll find that it has a bit of a hole &#8212; the enum values are presented to the user using the same name as it appears in code.  Now, if your enum values are simple enough (a single word, for example, so you don&#8217;t run into BumpyCasingIssues), or if this is for a prototype or otherwise cheap and hacky program, then this might be ok, but for most real-world usage it leaves a bit to be desired.</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;Window.Resources<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;app:ReportTypesConverter</span> <span style="color: #000066;">x:Key</span>=<span style="color: #ff0000;">&quot;ReportTypesConverter&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;DataTemplate</span> <span style="color: #000066;">DataType</span>=<span style="color: #ff0000;">&quot;{x:Type app:ReportTypes}&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;TextBlock</span> <span style="color: #000066;">Text</span>=<span style="color: #ff0000;">&quot;{Binding Converter={StaticResource ReportTypesConverter}}&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/DataTemplate<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/Window.Resources<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></div></div>

<p>The standard way of changing the appearance of an item in WPF is to template it, and this is no exception.  By adding the code above, the enum values will automatically be displayed in the UI using the text returned by the <code>ReportTypesConverter</code>, which is an <code>IValueConverter</code> you&#8217;ll have to write yourself that converts from an enum value to the text you want to display for it in the UI.  (Note that you don&#8217;t have to write a conversion back the other way.)  You can use similar techniques if you wanted to do something else with your enums &#8212; for example, displaying an image in addition to or instead of the text.</p>

<div class="wp_syntax"><div class="code"><pre class="csharp" style="font-family:monospace;"><span style="color: #008000;">&#91;</span>Conversion<span style="color: #008000;">&#40;</span><span style="color: #008000;">typeof</span><span style="color: #008000;">&#40;</span>ReportTypes<span style="color: #008000;">&#41;</span>, <span style="color: #008000;">typeof</span><span style="color: #008000;">&#40;</span><span style="color: #6666cc; font-weight: bold;">string</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#93;</span>
<span style="color: #0600FF; font-weight: bold;">public</span> <span style="color: #6666cc; font-weight: bold;">class</span> ReportTypesConverter <span style="color: #008000;">:</span> IValueConverter
<span style="color: #008000;">&#123;</span>
    <span style="color: #0600FF; font-weight: bold;">public</span> <span style="color: #6666cc; font-weight: bold;">object</span> Convert<span style="color: #008000;">&#40;</span><span style="color: #6666cc; font-weight: bold;">object</span> value, Type targetType, <span style="color: #6666cc; font-weight: bold;">object</span> parameter, CultureInfo culture<span style="color: #008000;">&#41;</span>
    <span style="color: #008000;">&#123;</span>
        <span style="color: #0600FF; font-weight: bold;">switch</span> <span style="color: #008000;">&#40;</span><span style="color: #008000;">&#40;</span>ReportTypes<span style="color: #008000;">&#41;</span>value<span style="color: #008000;">&#41;</span>
        <span style="color: #008000;">&#123;</span>
            <span style="color: #0600FF; font-weight: bold;">case</span> ReportTypes<span style="color: #008000;">.</span><span style="color: #0000FF;">Basic</span><span style="color: #008000;">:</span> <span style="color: #0600FF; font-weight: bold;">return</span> <span style="color: #666666;">&quot;Basic Report&quot;</span><span style="color: #008000;">;</span>
            <span style="color: #0600FF; font-weight: bold;">case</span> ReportTypes<span style="color: #008000;">.</span><span style="color: #0000FF;">Extended</span><span style="color: #008000;">:</span> <span style="color: #0600FF; font-weight: bold;">return</span> <span style="color: #666666;">&quot;Enhanced Report (includes section B)&quot;</span><span style="color: #008000;">;</span>
            <span style="color: #008000;">...</span>
        <span style="color: #008000;">&#125;</span>
        <span style="color: #0600FF; font-weight: bold;">return</span> <span style="color: #666666;">&quot;Unknown (&quot;</span> <span style="color: #008000;">+</span> value <span style="color: #008000;">+</span> <span style="color: #666666;">&quot;)&quot;</span><span style="color: #008000;">;</span>
    <span style="color: #008000;">&#125;</span>
&nbsp;
    <span style="color: #0600FF; font-weight: bold;">public</span> <span style="color: #6666cc; font-weight: bold;">object</span> ConvertBack<span style="color: #008000;">&#40;</span><span style="color: #6666cc; font-weight: bold;">object</span> value, Type targetType, <span style="color: #6666cc; font-weight: bold;">object</span> parameter, CultureInfo culture<span style="color: #008000;">&#41;</span>
    <span style="color: #008000;">&#123;</span>
        <span style="color: #0600FF; font-weight: bold;">throw</span> <span style="color: #008000;">new</span> NotSupportedException<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">;</span>
    <span style="color: #008000;">&#125;</span>
<span style="color: #008000;">&#125;</span></pre></div></div>

<p>You can get quite fancy in this converter (eg. handling translation) &#8212; and there&#8217;s even a technique you can use to let you use a <code>Description</code> attribute on the enum values themselves to define the text you want to show in the UI (and a further technique to extend that to be translatable); which at least means you&#8217;d only need to write one converter which would work for all enum types.  But I&#8217;m not going to go into that at the moment.  (I can post it if there&#8217;s sufficient interest, but I don&#8217;t really like that solution as it mixes too much UI-view stuff into the data-model.)</p>
<p>There&#8217;s yet another way to do it, though, which I think is a bit more elegant &#8212; but that will have to wait until the next post in the series.</p>
]]></content:encoded>
			<wfw:commentRss>http://lambert.geek.nz/2011/06/03/combos-of-enums/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Clever Conversion</title>
		<link>http://lambert.geek.nz/2011/03/01/clever-conversion/</link>
		<comments>http://lambert.geek.nz/2011/03/01/clever-conversion/#comments</comments>
		<pubDate>Mon, 28 Feb 2011 14:01:33 +0000</pubDate>
		<dc:creator>Miral</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[.NET]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[conversion]]></category>
		<category><![CDATA[WPF]]></category>

		<guid isPermaLink="false">http://lambert.geek.nz/?p=109</guid>
		<description><![CDATA[<p>I&#8217;ve been planning to post this (and a few other things) for a while now, but never quite seemed to get around to it. Well, brace yourselves, because here it finally is! (And it might even turn into an actual series!)</p> <p>This first part is pretty straightforward; it&#8217;s a helper class designed to make a [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been planning to post this (and a few other things) for a while now, but never quite seemed to get around to it.  Well, brace yourselves, because here it finally is!  (And it might even turn into an actual series!)</p>
<p>This first part is pretty straightforward; it&#8217;s a helper class designed to make a best-effort attempt to convert any object into a specific type, by making use of any defined converters.  It&#8217;s the sort of thing you&#8217;d <strong>think</strong> <code>Convert.ChangeType</code> would do (but doesn&#8217;t, because that only works for the native value types), and what the WPF XAML parser actually does do (although unfortunately it doesn&#8217;t seem to expose its underlying mechanism for external use; at least not that I could find).</p>
<p>But let&#8217;s get straight into the code:</p>

<div class="wp_syntax"><div class="code"><pre class="csharp" style="font-family:monospace;">    <span style="color: #0600FF; font-weight: bold;">public</span> <span style="color: #0600FF; font-weight: bold;">static</span> <span style="color: #6666cc; font-weight: bold;">class</span> ConversionUtilities
    <span style="color: #008000;">&#123;</span>
        <span style="color: #008080; font-style: italic;">/// &lt;summary&gt;Convert the given value to the specified type (if possible).  Requires a direct &lt;see cref=&quot;TypeConverter&quot;/&gt; conversion to work.&lt;/summary&gt;</span>
        <span style="color: #008080; font-style: italic;">/// &lt;param name=&quot;currentValue&quot;&gt;The value to be converted.&lt;/param&gt;</span>
        <span style="color: #008080; font-style: italic;">/// &lt;param name=&quot;expectedType&quot;&gt;The type to convert the value to.&lt;/param&gt;</span>
        <span style="color: #008080; font-style: italic;">/// &lt;returns&gt;The converted value; or the original value if the conversion is not necessary or not possible.&lt;/returns&gt;</span>
        <span style="color: #008080; font-style: italic;">/// &lt;exception cref=&quot;Exception&quot;&gt;Any exceptions thrown by the conversion operation will be propagated outwards.&lt;/exception&gt;</span>
        <span style="color: #0600FF; font-weight: bold;">public</span> <span style="color: #0600FF; font-weight: bold;">static</span> <span style="color: #6666cc; font-weight: bold;">object</span> Convert<span style="color: #008000;">&#40;</span><span style="color: #6666cc; font-weight: bold;">object</span> currentValue, Type expectedType<span style="color: #008000;">&#41;</span>
        <span style="color: #008000;">&#123;</span>
            var convertedValue <span style="color: #008000;">=</span> currentValue<span style="color: #008000;">;</span>
            <span style="color: #0600FF; font-weight: bold;">if</span> <span style="color: #008000;">&#40;</span>convertedValue <span style="color: #008000;">==</span> <span style="color: #0600FF; font-weight: bold;">null</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span> <span style="color: #0600FF; font-weight: bold;">return</span> convertedValue<span style="color: #008000;">;</span> <span style="color: #008000;">&#125;</span>
            <span style="color: #0600FF; font-weight: bold;">if</span> <span style="color: #008000;">&#40;</span>expectedType<span style="color: #008000;">.</span><span style="color: #0000FF;">IsAssignableFrom</span><span style="color: #008000;">&#40;</span>convertedValue<span style="color: #008000;">.</span><span style="color: #0000FF;">GetType</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span> <span style="color: #0600FF; font-weight: bold;">return</span> convertedValue<span style="color: #008000;">;</span> <span style="color: #008000;">&#125;</span>
&nbsp;
            var converter <span style="color: #008000;">=</span> TypeDescriptor<span style="color: #008000;">.</span><span style="color: #0000FF;">GetConverter</span><span style="color: #008000;">&#40;</span>expectedType<span style="color: #008000;">&#41;</span><span style="color: #008000;">;</span>
            <span style="color: #0600FF; font-weight: bold;">if</span> <span style="color: #008000;">&#40;</span>converter <span style="color: #008000;">!=</span> <span style="color: #0600FF; font-weight: bold;">null</span> <span style="color: #008000;">&amp;&amp;</span> converter<span style="color: #008000;">.</span><span style="color: #0000FF;">CanConvertFrom</span><span style="color: #008000;">&#40;</span>convertedValue<span style="color: #008000;">.</span><span style="color: #0000FF;">GetType</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span>
            <span style="color: #008000;">&#123;</span>
                convertedValue <span style="color: #008000;">=</span> converter<span style="color: #008000;">.</span><span style="color: #0000FF;">ConvertFrom</span><span style="color: #008000;">&#40;</span>convertedValue<span style="color: #008000;">&#41;</span><span style="color: #008000;">;</span>
            <span style="color: #008000;">&#125;</span>
            <span style="color: #0600FF; font-weight: bold;">else</span>
            <span style="color: #008000;">&#123;</span>
                converter <span style="color: #008000;">=</span> TypeDescriptor<span style="color: #008000;">.</span><span style="color: #0000FF;">GetConverter</span><span style="color: #008000;">&#40;</span>convertedValue<span style="color: #008000;">.</span><span style="color: #0000FF;">GetType</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">;</span>
                <span style="color: #0600FF; font-weight: bold;">if</span> <span style="color: #008000;">&#40;</span>converter <span style="color: #008000;">!=</span> <span style="color: #0600FF; font-weight: bold;">null</span> <span style="color: #008000;">&amp;&amp;</span> converter<span style="color: #008000;">.</span><span style="color: #0000FF;">CanConvertTo</span><span style="color: #008000;">&#40;</span>expectedType<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span>
                <span style="color: #008000;">&#123;</span>
                    convertedValue <span style="color: #008000;">=</span> converter<span style="color: #008000;">.</span><span style="color: #0000FF;">ConvertTo</span><span style="color: #008000;">&#40;</span>convertedValue, expectedType<span style="color: #008000;">&#41;</span><span style="color: #008000;">;</span>
                <span style="color: #008000;">&#125;</span>
            <span style="color: #008000;">&#125;</span>
            <span style="color: #0600FF; font-weight: bold;">return</span> convertedValue<span style="color: #008000;">;</span>
        <span style="color: #008000;">&#125;</span>
&nbsp;
        <span style="color: #008080; font-style: italic;">/// &lt;summary&gt;Convert the given value to the specified type (if possible).  Requires a direct &lt;see cref=&quot;TypeConverter&quot;/&gt; conversion to work.&lt;/summary&gt;</span>
        <span style="color: #008080; font-style: italic;">/// &lt;param name=&quot;currentValue&quot;&gt;The value to be converted.&lt;/param&gt;</span>
        <span style="color: #008080; font-style: italic;">/// &lt;typeparam name=&quot;T&quot;&gt;The type to convert the value to.&lt;/typeparam&gt;</span>
        <span style="color: #008080; font-style: italic;">/// &lt;returns&gt;The converted value.&lt;/returns&gt;</span>
        <span style="color: #008080; font-style: italic;">/// &lt;exception cref=&quot;InvalidCastException&quot;&gt;Thrown if the specified conversion is not defined.&lt;/exception&gt;</span>
        <span style="color: #008080; font-style: italic;">/// &lt;exception cref=&quot;Exception&quot;&gt;Any exceptions thrown by the conversion operation will be propagated outwards.&lt;/exception&gt;</span>
        <span style="color: #0600FF; font-weight: bold;">public</span> <span style="color: #0600FF; font-weight: bold;">static</span> T Convert<span style="color: #008000;">&lt;</span>T<span style="color: #008000;">&gt;</span><span style="color: #008000;">&#40;</span><span style="color: #6666cc; font-weight: bold;">object</span> currentValue<span style="color: #008000;">&#41;</span>
        <span style="color: #008000;">&#123;</span>
            <span style="color: #0600FF; font-weight: bold;">if</span> <span style="color: #008000;">&#40;</span>currentValue <span style="color: #008000;">==</span> <span style="color: #0600FF; font-weight: bold;">null</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span> <span style="color: #0600FF; font-weight: bold;">return</span> <span style="color: #0600FF; font-weight: bold;">default</span><span style="color: #008000;">&#40;</span>T<span style="color: #008000;">&#41;</span><span style="color: #008000;">;</span> <span style="color: #008000;">&#125;</span>
            <span style="color: #0600FF; font-weight: bold;">return</span> <span style="color: #008000;">&#40;</span>T<span style="color: #008000;">&#41;</span>Convert<span style="color: #008000;">&#40;</span>currentValue, <span style="color: #008000;">typeof</span><span style="color: #008000;">&#40;</span>T<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">;</span>
        <span style="color: #008000;">&#125;</span>
&nbsp;
        <span style="color: #008080; font-style: italic;">/// &lt;summary&gt;Compares two objects for equality, applying conversions (if possible) if their types differ.&lt;/summary&gt;</span>
        <span style="color: #008080; font-style: italic;">/// &lt;param name=&quot;a&quot;&gt;The first object to compare.&lt;/param&gt;</span>
        <span style="color: #008080; font-style: italic;">/// &lt;param name=&quot;b&quot;&gt;The second object to compare.&lt;/param&gt;</span>
        <span style="color: #008080; font-style: italic;">/// &lt;returns&gt;True if the objects are convertible to an equal value.&lt;/returns&gt;</span>
        <span style="color: #0600FF; font-weight: bold;">public</span> <span style="color: #0600FF; font-weight: bold;">static</span> <span style="color: #6666cc; font-weight: bold;">bool</span> EqualsWithConversion<span style="color: #008000;">&#40;</span><span style="color: #6666cc; font-weight: bold;">object</span> a, <span style="color: #6666cc; font-weight: bold;">object</span> b<span style="color: #008000;">&#41;</span>
        <span style="color: #008000;">&#123;</span>
            <span style="color: #0600FF; font-weight: bold;">if</span> <span style="color: #008000;">&#40;</span>a <span style="color: #008000;">==</span> <span style="color: #0600FF; font-weight: bold;">null</span> <span style="color: #008000;">&amp;&amp;</span> b <span style="color: #008000;">==</span> <span style="color: #0600FF; font-weight: bold;">null</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span> <span style="color: #0600FF; font-weight: bold;">return</span> <span style="color: #0600FF; font-weight: bold;">true</span><span style="color: #008000;">;</span> <span style="color: #008000;">&#125;</span>
            <span style="color: #0600FF; font-weight: bold;">if</span> <span style="color: #008000;">&#40;</span>a <span style="color: #008000;">==</span> <span style="color: #0600FF; font-weight: bold;">null</span> <span style="color: #008000;">||</span> b <span style="color: #008000;">==</span> <span style="color: #0600FF; font-weight: bold;">null</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span> <span style="color: #0600FF; font-weight: bold;">return</span> <span style="color: #0600FF; font-weight: bold;">false</span><span style="color: #008000;">;</span> <span style="color: #008000;">&#125;</span>
&nbsp;
            <span style="color: #0600FF; font-weight: bold;">if</span> <span style="color: #008000;">&#40;</span>Equals<span style="color: #008000;">&#40;</span>a, b<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span> <span style="color: #0600FF; font-weight: bold;">return</span> <span style="color: #0600FF; font-weight: bold;">true</span><span style="color: #008000;">;</span> <span style="color: #008000;">&#125;</span>
            <span style="color: #0600FF; font-weight: bold;">if</span> <span style="color: #008000;">&#40;</span>Equals<span style="color: #008000;">&#40;</span>Convert<span style="color: #008000;">&#40;</span>a, b<span style="color: #008000;">.</span><span style="color: #0000FF;">GetType</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span>, b<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span> <span style="color: #0600FF; font-weight: bold;">return</span> <span style="color: #0600FF; font-weight: bold;">true</span><span style="color: #008000;">;</span> <span style="color: #008000;">&#125;</span>
            <span style="color: #0600FF; font-weight: bold;">if</span> <span style="color: #008000;">&#40;</span>Equals<span style="color: #008000;">&#40;</span>a, Convert<span style="color: #008000;">&#40;</span>b, a<span style="color: #008000;">.</span><span style="color: #0000FF;">GetType</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span> <span style="color: #0600FF; font-weight: bold;">return</span> <span style="color: #0600FF; font-weight: bold;">true</span><span style="color: #008000;">;</span> <span style="color: #008000;">&#125;</span>
            <span style="color: #0600FF; font-weight: bold;">return</span> <span style="color: #0600FF; font-weight: bold;">false</span><span style="color: #008000;">;</span>
        <span style="color: #008000;">&#125;</span>
    <span style="color: #008000;">&#125;</span></pre></div></div>

<p>Note that if the conversion is not possible, then the first method will return the original object, which will result in the second method throwing an <code>InvalidCastException</code>.</p>
<p>These methods only support a single conversion step &#8212; if <code>Foo</code> and <code>Bar</code> are both convertible to <code>String</code> (as all objects are, ultimately), then it will let you convert either a <code>Foo</code> object or a <code>Bar</code> object to a string (or vice versa, if the reverse conversion has been defined), but it will <strong>not</strong> let you convert a <code>Foo</code> object into a <code>Bar</code> object directly &#8212; although you can request the intermediate conversion yourself if that&#8217;s what you really want:</p>

<div class="wp_syntax"><div class="code"><pre class="csharp" style="font-family:monospace;">ConversionUtilities<span style="color: #008000;">.</span><span style="color: #0000FF;">Convert</span><span style="color: #008000;">&lt;</span>Bar<span style="color: #008000;">&gt;</span><span style="color: #008000;">&#40;</span>ConversionUtilities<span style="color: #008000;">.</span><span style="color: #0000FF;">Convert</span><span style="color: #008000;">&lt;</span><span style="color: #6666cc; font-weight: bold;">string</span><span style="color: #008000;">&gt;</span><span style="color: #008000;">&#40;</span>foo<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span></pre></div></div>

<p>I chose this limitation both to help avoid potential loops if complex conversion paths are available, and because letting it chain through more than one conversion step at a time could easily lead to a loss of information or other surprising behaviour &#8212; especially since every object is convertible to a string (though not necessarily back from a string), but those conversions aren&#8217;t necessarily all that helpful.</p>
<p>We&#8217;ll cover a particularly interesting use for this class in a later post.</p>
]]></content:encoded>
			<wfw:commentRss>http://lambert.geek.nz/2011/03/01/clever-conversion/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Scott Pilgrim</title>
		<link>http://lambert.geek.nz/2010/09/07/scott-pilgrim/</link>
		<comments>http://lambert.geek.nz/2010/09/07/scott-pilgrim/#comments</comments>
		<pubDate>Mon, 06 Sep 2010 21:07:26 +0000</pubDate>
		<dc:creator>Miral</dc:creator>
				<category><![CDATA[Random]]></category>
		<category><![CDATA[film]]></category>
		<category><![CDATA[Scott Pilgrim]]></category>
		<category><![CDATA[video]]></category>

		<guid isPermaLink="false">http://lambert.geek.nz/?p=83</guid>
		<description><![CDATA[<p>I&#8217;ve been meaning to post this for a couple of weeks, but you know me. I figured I had better do it before it&#8217;s completely gone from the theatres, at least.</p> <p>If you&#8217;re into computer games at all (with particular emphasis on the old 8-bit Nintendo games, but any gaming interest is probably good enough), [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been meaning to post this for a couple of weeks, but you know me.  I figured I had better do it before it&#8217;s completely gone from the theatres, at least.</p>
<p>If you&#8217;re into computer games at all (with particular emphasis on the old 8-bit Nintendo games, but any gaming interest is probably good enough), then <em>Scott Pilgrim vs. the World</em> is definitely a good movie to go and see.</p>
<p>On the surface (and for the first 20 minutes or so), it&#8217;s basically just your boring average run of the mill cheesy teen romance stuff, although occasional glimmers of interest peek through sometimes (and it&#8217;s really hard to like the main character at this point; not sure if that&#8217;s intentional or not).  Once you get past that part, though (basically shortly after Ramona first appears), the action heats up and things just get insanely awesome.</p>
<p>I guess it has a bit of a niche audience (which is probably why according to most reports it&#8217;s been fairly mediocre at the box office), but for those people squarely in its niche (like me), it&#8217;s one to be remembered.</p>
<p>Here&#8217;s the official trailer:<br />
[There is a video that cannot be displayed in this feed. <a href="http://lambert.geek.nz/2010/09/07/scott-pilgrim/">Visit the blog entry to see the video.]</a></p>
<p>And, just for added awesome points, here&#8217;s a fan trailer combining video from the <em>Matrix</em> series with audio from the <em>Scott Pilgrim</em> trailer (which works out surprisingly well):<br />
[There is a video that cannot be displayed in this feed. <a href="http://lambert.geek.nz/2010/09/07/scott-pilgrim/">Visit the blog entry to see the video.]</a></p>
]]></content:encoded>
			<wfw:commentRss>http://lambert.geek.nz/2010/09/07/scott-pilgrim/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>

