|
|
Quite a while back, I posted an article about getting native callbacks to work across AppDomains. Since then, I’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’d be a good idea to post a clarification.
Fundamentally, there are just a few things that you need to remember:
- You cannot access managed objects (including
GCHandles and gcroots) outside of the AppDomain in which they were created.
- Each thread which has executed managed code has a “history” 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.
- Delegates contain information about which AppDomain they should be executed in, so they can “cross the line” when an otherwise pure native thread has no idea which AppDomain it should be using.
- Managed delegates can be turned into native function pointers via the
Marshal::GetFunctionPointerForDelegate method.
- 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.
- Native functions can only have native types as parameters (but they don’t have to just be primitive types). (Actually, there are some limited exceptions to this, which I cover below.)
So, here’s a few example scenarios, to get your head around the ideas. Note that none of these care whether you’re crossing AppDomain boundaries or not (they’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.
Continue reading AppDomains and unmanaged callbacks, redux
Finally, the last post in my series about conversion and the LookupConverter.
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’ve actually never used this in a real-world scenario myself (I’ve always found alternatives), since the goal of the LookupConverter in the first place was to avoid 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.
Continue reading Conversion Filter
Some people might be wondering why I said that the last two Programming posts were part of a series — 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’s this post which should help to tie everything together.
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’s ok, if you’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.
As a reminder, the (somewhat contrived) example from the previous post went something like this:
<window .Resources>
<objectdataprovider x:Key="ReportTypes" ObjectType="{x:Type System:Enum}" MethodName="GetValues">
</objectdataprovider><objectdataprovider .MethodParameters>
<x:type TypeName="app:ReportType" />
</objectdataprovider>
<app:reporttypesconverter x:Key="ReportTypesConverter" />
<datatemplate DataType="{x:Type app:ReportTypes}">
<textblock Text="{Binding Converter={StaticResource ReportTypesConverter}}" />
</datatemplate>
</window>
...
<combobox ItemsSource="{Binding Source={StaticResource ReportTypes}}" SelectedItem="{Binding ReportType, Mode=TwoWay}" />
But the ReportTypesConverter isn’t very satisfactory there — 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’ll need more than one converter for a single enum type, if it’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.
So I went looking for a better way. Continue reading A Tableau of Conversion
It’s probably about time that I continued on from my previous post. This one is just going to be a short one, but it’s a nice setup for the following post in the series.
When you have a property which can only have one of a limited number of values, there are a few [...]
I’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!)
This first part is pretty straightforward; it’s a helper class designed to make [...]
(Well, look at that. I did manage to write another Programming post after all.)
One of the really great things about WPF is its composable UI structure and dynamic layouts — the ability to replace one set of controls with another on the fly as things happen (eg. when something is selected by the user) and have everything adjust accordingly. The data binding engine is one of the most important elements in this, but closely linked to it is the templating engine.
In this post I’ll cover a little bit of background behind DataTemplates, but the primary focus is going to be on the DataTemplateSelector — what it is, why you might want to use it, a way to make it easier to use, and finally a better alternative to using them at all.
Continue reading Templates Galore
Today’s topic is fairly basic, but hey, it gives me a chance to moan about something weird in the framework, so it’s not all bad
Windows Presentation Foundation. WPF. Essentially it’s a long-overdue reboot of the child window model coupled with a powerful data binding engine (though not without its own quirks). And I love it.
The data binding model, though, does tend to result in the proliferation of little helper classes. In this case, I’m referring to value converters, those classes built solely to take a property value, convert it for display purposes (usually to a string), and optionally back the other way again.
Continue reading StringFormatConverter
WARNING: As discussed in the comments, this collection class uses weak events, and (due to a bug in the .NET framework itself) weak events are not reliable unless you’re using .NET 3.5 SP1 or higher. If you’re stuck with an earlier version of the framework (or don’t want to verify that end users have installed the service pack), you could try using Kevin Kerr’s class, which works around the problem by treating the collection lifetimes differently than mine. (My one keeps the domain collection entirely separate and assumes it can out-live the UI; his ties them together and assumes that the collection is created by the UI in the first place; thus his one doesn’t need the weak events.)
It’s about time now for another programming post. (I noticed a little while ago that I appear to be maintaining a “two posts other, one post programming” pattern. This was unintentional at first, but once I noticed I figured I might as well keep it up. We’ll see how long it lasts before I get bored.) And this one’s going to be a long one.
I’ve been experimenting a bit in recent months with WPF, and in particular trying to do things the “WPF way” by using data binding to tie domain objects to the UI rather than writing code. This all works fairly well once you get the basic concepts down, but there’s one gaping hole in the framework: while it can cope with property changes occurring across threads, it can’t cope with collection changes across threads. This means that if you’re binding to a collection (to display a list of items somewhere), then that collection can only be modified on the UI thread, not any other thread. If you break this rule, then things may seem to work for a while, but you’ll eventually either get a simple exception (a NotSupportedException saying “This type of CollectionView does not support changes to its SourceCollection from a thread different from the Dispatcher thread.”) or a weirder exception (such as an IndexOutOfRangeException from deep within the internals of the framework).
But sometimes (eg. for performance reasons), you really do need to update that collection from a different thread. You might think you can get away with just making the collection synchronised (wrapping every operation in a lock), but there are two problems with that. First, you would have to synchronise enumeration operations too, which you can’t do from within the collection class — and since the WPF code is written assuming a single thread, it’s unlikely it will be doing the synchronisation itself. Second, from some of the weird messages it produces, it’s clear that after getting a “collection changed” notification the framework will go and access the collection to retrieve additional info — and by the time it does that the collection may have changed again, meaning it will be accessing the wrong items and getting itself horribly confused.
Continue reading Multithreaded Collections and WPF
For those who don’t already know, my main desktop machine at the moment is running 64-bit Windows. There probably isn’t a particularly good reason for doing that — after all, I’ve only got 2GB of RAM in there at the moment, so I’m not even hitting the 3GB limit of 32-bit Windows yet. But when I bought my shiny new 64-bit processor I figured, why the heck not? And it has the added bonus of being able to make sure my own software works on a 64-bit platform, too. Of course, I could just be masochistic.
Having said that, for the most part I haven’t had any problems with native applications (there have been a few issues, but I don’t want to go into that now. Maybe I’ll save it for a later Rant post). Even games (and their evil DRM disc-detection software) run just fine.
Where I have hit some issues though is with .NET applications. “Wait!” I hear you say, “Aren’t .NET apps supposed to be platform-independent?” Well, they are (in a way), and it’s partly that which is their downfall 
Continue reading .NET 2.0 and 64-bit Windows
Continuing on the theme of mixing managed and native code from my last programming post, here’s another issue I ran into at about the same time…
Normally, you’re writing managed code as an interop layer to hide the native code away from the managed world, so it’s only used with private visibility. Sometimes, however, [...]
|
|
Recent Comments