C# in VS2005: Can a device project target both ful

2019-03-30 12:33发布

问题:

We're developing with Compact Framework for a device under Visual Studio 2005. However we want to make an emulated version of the software as well, running at the PC (preferably selectable via a Build Configuration).

It seems however that the .vsproj file is specific for devices; there is no way to use the full .NET framework for example by just changing the target.

Is there any way around this? I suppose we can run the compact framework on the PC, but still the project can't target for example an ARM processor or else I assume the JIT compiler will generate unusable code for the PC?

回答1:

You can run a Compact Framework application in regular Windows (maybe). There are two major potential problems with this, however.

First, because certain form and control properties present in the full framework are missing in the compact framework, your application will behave a bit oddly in Windows. For example, in the full framework forms have a StartPosition property which determines where the forms appear on the screen when they're first created. This property does not exist in the compact framework (for obvious reasons), so when you run your CF application in regular Windows, the forms pick up the default StartPosition value of WindowsDefaultLocation, which means that setting the form's Left and Top properties has no effect on where they appear, so the forms pop up wherever.

Second, any Windows API PInvoke calls in CF must reference "coredll", whereas the same calls in the full framework reference "user32", "winmm" etc. One way around this problem is to do something like this:

[DllImport("winmm.dll", EntryPoint="waveOutReset")]
private static extern int waveOutResetFULL(IntPtr hWaveIn);
[DllImport("coredll.dll", EntryPoint="waveOutReset")]
private static extern int waveOutResetCF(IntPtr hWaveIn);
public static int waveOutReset(IntPtr hWaveIn)
{
    if (Environment.OSVersion.Platform == PlatformID.WinCE)
    {
        return waveOutResetCF(hWaveIn);
    }
    else
    {
        return waveOutResetFULL(hWaveIn);
    }
}

There are other ways to do this, also.

Regarding the first set of problems, one solution is to set the properties that are missing in the compact framework via Reflection when the application is running in regular Windows. I think a better alternative is to encapsulate all the elements of your UI as UserControls, each one hosted on a single "master" UserControl that creates and disposes the other UserControl elements as needed. You can then host your single "master" UserControl on a single instance of a form.

By the way, I wrote an application that does exactly this (run in Windows and on Windows Mobile devices) for a major shipbuilder, and it is still in use. In fact, the ability of this application to run in both environments literally saved its life when the use of mobile devices in the shipyard was temporarily suspended for security reasons.



回答2:

Jared is correct, you cannot get Studio to do this (well not without a whole lot of pulling your hair out and very brittle end results). In addition, though, there are som other things to note.

First, MSIL is processor independent so it's not going to "generate unusable code" from that perspective. ARM IL is identical to x86 IL (or MIPS or SH3 for that matter). In fact CF assemblies can be directly used in the full framework becasue they are retargetable (the reverse is not true since the CF doesn't implement all of the opcodes the desktop does).

That said, it's pretty uncommon to have a CF application that doesn't call a device specific API, whether it's a P/Invoke to coredll.dll or a device-specific assembly like Microsoft.WindowsMobile.dll. In those cases the assembly either will except at runtime (cannot find a native DLL) or at load (cannot find a referenced assembly).

You can (sometimes only with great effort) work around these issues. It's up to you to determine if it's even worth doing. My experience is that, generally speaking, it is not. It's way less effort to just use the emulator or a Virtual PC running CE.



回答3:

I think the only way to do this is to have 2 project files for the same project. One which is the normal CF one and one that works just like a normal .Net application. Having the project file target both the CF and full framework is not a supported operation.



回答4:

I have a related issue in some open-source code that I maintain; I have separate project files, but to reduce maintenance, I use a hand-crafted project file that automatically includes all *.cs files in the project tree:

<ItemGroup>
  <Compile Include="..\protobuf-net\**\*.cs" />
</ItemGroup>

This way, I don't have to keep remembering to add files to the other build scripts - although I do need to be religious about deleting obsolete files (not just removing them from the project).



回答5:

We do this where I work and it's (mostly) fine. If you're only using it for emulation you can also handle the few rough edges that the GDI+ spits out. You just have to identify the incompatible points and push them out into some sort of platform interface for those issues that seriously break things.

As MusiGenesis astutely states one of the main areas will be your P/Invokes. I also have a very incomplete list of Compact Framework / Full Framework bugs being gathered here:



回答6:

A workaround is NOT to use VS. One great example is the software Basic4PPC (see here).

It's a programming-language in the style of VB.Net (all applications written with it requires the Compact Framework installed on the device). However, the point is that you use only one IDE, same source-code but you can compile your applications to run either on the desktop or the device. There are many user-libraries available and for certain tasks, you might be required to use a specific library for the desktop or the device.

The program has been written in C#. It's well worth a look.



回答7:

I've tackled a similar problem from a different direction: I have a utility library that works in both full and compact, so I used multiple projects, but only a single set of source files.

The full csproj has the source files, and the compact csproj has links to those files. Whenever a class calls a method that isn't in the compact, I make that a partial class and the methods in question are implmented in *.pc.cs and *.ppc.cs files.

Combine this with the concept with Marc Gravell posted (to automatically include files from the full project), and it should be pretty easy to maintain.