Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
815 views
in Technique[技术] by (71.8m points)

windows - AnyCPU/x86/x64 for C# application and it's C++/CLI dependency

I'm Windows developer, I'm using Microsoft visual studio 2008 SP1. My developer machine is 64 bit.

The software I'm currently working on is managed .exe written in C#. Unfortunately, I was unable to solve the whole problem solely in C#. That's why I also developed a small managed DLL in C++/CLI. Both projects are in the same solution.

My C# .exe build target is "Any CPU". When my C++ DLL build target is "x86", the DLL is not loaded. As far as I understood when I googled, the reason is C++/CLI language, unlike other .NET languages, compiles to the native code, not managed code.

I switched the C++ DLL build target to x64, and everything works now. However, AFAIK everything will stop working as soon as my client will install my product on a 32-bit OS. I have to support Windows Vista and 7, both 32 and 64 bit versions of each of them.

I don't want to fall back to 32 bits. That 250 lines of C++ code in my DLL is only 2% of my codebase. And that DLL is only used in several places, so in the typical usage scenario it's not even loaded.

My DLL implements two COM objects with ATL, so I can't use "/clr:safe" project setting.

Is there way to configure the solution and the projects so that C# project builds "Any CPU" version, the C++ project builds both 32 bit and 64 bit versions, then in the runtime when the managed .EXE is starting up, it uses either 32-bit DLL or 64-bit DLL depending on the OS?

Or maybe there's some better solution I'm not aware of?

Thanks in advance!

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

There is a way: to have an "AnyCPU" C# wrapper and a C++ project per architecture, and let the C# wrapper load the right C++ project at run time.

For the C++ project, create one version per different architecture (x86, x64), and build them all. Then in the wrapper do:

public class CppWrapper
{
    // C++ calls that will be dynamically loaded from proper architecture:
    public static readonly Func<long> MyCplusplusMethodUsableFromCsharpSpace;

    // Initialization:
    static CppWrapper()
    {
        if(Environment.Is64BitProcess)
        {
            MyCplusplusMethodUsableFromCsharpSpace = CppReferences64.MyCplusplusClass.Method;
            // Add your 64-bits entry points here...
        }
        else
        {
            MyCplusplusMethodUsableFromCsharpSpace = CppReferences32.MyCplusplusClass.Method;
            /* Initialize new 32-bits references here... */
        }
    }

    // Following classes trigger dynamic loading of the referenced C++ code
    private static class CppReferences64
    {
        public static readonly Func<long> MyCplusplusMethod = Cpp64.MyCplusplusMethod;
        /* Add any64-bits references here... */
    }
    private static class CppReferences32
    {
        public static readonly Func<long> MyCplusplusMethod = Cpp32.MyCplusplusMethod;
        /* Add any 32-bits references here... */
    }
}

And in the C++ code, I use the same sources as I said, but will compile to different namespace depending on the build architecture:

#ifdef _M_X64
namespace Cpp64 {
#else
namespace Cpp32 {
#endif
    public ref class MyCPlusPlusClass
    {
        public: static __int64 Method(void) { return 123; }
    };
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...