tags:

views:

195

answers:

5

I'm writing a NON-GUI app which I want to be cross platform between OS X and Windows. I'm looking at the following architecture, but I don't know if it will work on the windows side:

(Platform specific entry point) -> ANSI C main loop => ANSI C model code doing data processing / logic => (Platform specific helpers)

So the core stuff I'm planning to write in regular ANSI C, because A) it should be platform independent, B) I'm extremely comfortable with C, C) It can do the job and do it well

(Platform specific entry point) can be written in whatever necessary to get the job done, this is a small amount of code, doesn't matter to me.

(Platform specific helpers) is the sticky thing. This is stuff like parsing XML, accessing databases, graphics toolkit stuff, whatever. Things that aren't easy in C. Things that modern languages/frameworks will give for free. On OS X this code will be written in Objective-C interfacing with Cocoa. On Windows I'm thinking my best bet is to use C#

So on Windows my architecture (simplified) looks like

(C# or C?) -> ANSI C -> C#

Is this possible? Some thoughts/suggestions so far..

1) Compile my C core as a .dll -- this is fine, but seems there's no way to call my C# helpers unless I can somehow get function pointers and pass them to my core, but that seems unlikely

2) Compile a C .exe and a C# .exe and have them talk via shared memory or some kind of IPC. I'm not entirely opposed to this but it obviously introduces a lot of complexity so it doesn't seem ideal

3) Instead of C# use C++, it gets me some nice data management stuff and nice helper code. And I can mix it pretty easily. And the work I do could probably easily port to Linux. But I really don't like C++, and I don't want this to turn in to a 3rd-party-library-fest. Not that it's a huge deal, but it's 2010.. anything for basic data management should be built in. And targetting Linux is really not a priority.

Note that no "total" alternatives are OK as suggested in other similar questions on SO I've seen; java, RealBasic, mono.. this is an extremely performance intensive application doing soft realtime for game/simulation purposes, I need C & friends here to do it right (maybe you don't, but I do)

+6  A: 

Short answer: Yes. You can access non-managed code quite easily from .NET, but you'll have to marshal your data.

Long answer: Don't do it. You know about the mono project? It's a x-platform implementation of .NET. They're a bit behind Microsoft, but they still offer a solution that works for many. I'd highly suggest keeping in managed code if at all possible, you're defeating the purpose of .NET if you're in-and-outing to C code. This will also help reduce your project complexity tenfold.

If you require C ANSI for low-level access, I suggest you expose a small & well-tested C ANSI api to your .NET core to do any low-level stuff.

C# Core <==> Small C ANSI Helper Library

Aren
I think the OP wants the non-managed code to call into C#, not the other way round. This could be done via COM:ANSI C Core <==> C/C++ COM wrapper <==> C#
ShellShock
Yes I want the non-managed code to call in to C#, not the other way around. My C ANSI API is really the high level stuff actually, the 'low level' being in C#As I said in OP I don't want to use mono. Would love to see elaboration on the COM wrapper technique please. How can it bridge?
Nektarios
I would just point out that "marshal your data" sounds a bit scary in this context, but that's technically incorrect. A P/Invoke call to a C library isn't a call to a separate app domain, for example. It's probably no more overhead than calling the same C API from a C++ application. So I'm not sure why the person asking the question mentioned IPC, since it's not necessary. The mapping layer between the C library and the C# front end wouldn't even need to be isolated since it would be Windows-specific.
kprobst
I mentioned IPC because I was talking about 2 completely separate executables communicating with each other
Nektarios
There doesn't seem to be anything that a COM wrapper would bring to the picture. You can just as well pass function pointers (packed into structs for convenience) directly to C code. COM would be a very roundabout way of doing the same thing, with vtables of CCWs being those structs, except that calling it from C would be less convenient.
Pavel Minaev
+1  A: 

Why would you not do this all in c++? You can hit all your platforms and get all the stuff that you say C does not have. C# is only for dot net stuff, c/c++ still works on windows, just get the api call you need for whatever you are trying to do.

I'm thinking I am going to have to go with C++ really. But I want to do easy (built in) database accessing, easy (built in) XML parsing, etc.. I don't get that from C++I'm not concerned about calling WPF or MFC or DX or whatever, that's not an issue
Nektarios
Have you looked at Qt?
Pavel Minaev
+1  A: 

I like Aren's answer (look at Mono), but if you really want to use C + C#, you can use SWIG to produce wrappers of C code somewhat automatically. It's got a learning curve, but if the number of C functions you want to call from C# is large enough, it's worth the effort. SWIG doesn't support Objective C out-of-box, but there is a branch with not-quite-finished support for it.

Update: oh, you want to primarily call C# from C? Sorry, SWIG isn't really designed for that. C# does allow it, however. You can use either a C# or C/C++ entry point (a C# entry point is probably easier), and you can pass pointers to C# functions (delegates) into C code.

Let's say you want to pass a void(string) function from C# to C. First off, I don't know how C code can directly get pointers to C# functions (it may be possible, I just don't know how.) Instead, I would start the program in C# code and have the C# code pass itself to the C code.

Something like this:

// Visual C code:
// (.NET functions use the __stdcall calling convention by default.)
typedef void (__stdcall *Callback)(PCWSTR);
void __declspec(dllexport) Foo(Callback c)
{
    c(L"Hello world");
}

// C# code:
// (A delegate declaration can include marshaling commands that
// control how argument types are converted.)
public delegate void Callback([MarshalAs(UnmanagedType.LPWStr)] string message);
void PrintOut(string message) { Console.WriteLine(message); }

Here we have a C function "Foo" that can receive a pointer to the C# function "PrintOut" (or a C function for that matter), plus a Callback typedef. We use __declspec(dllexport) so that C# code can call it.

On the C# side we have a delegate declaration, which is roughly analogous to the typedef in C, and a function "PrintOut" that we want to pass to C.

Assuming you compile your C code into a DLL called Foo.dll, you'll need a C# P/Invoke declaration, and code that actually calls Foo:

[DllImport("Foo")]
public static extern void Foo(Callback c);

public void CallFoo()
{
    Foo(PrintOut);
}

The above will probably work at first, but there is one "gotcha": the above code wraps PrintOut in a delegate, and the garbage collector will free the delegate eventually unless you keep a reference to it. So if you want the C code to have a permanent reference to the C# method, we must change the above C# code to keep a reference to the delegate:

[DllImport("Foo")]
public static extern void Foo(Callback c);

static Callback PrintOutRef; // to prevent garbage collection of the delegate

public void CallFoo()
{
    Foo(PrintOutRef = PrintOut);
}

Hope that helps!

Qwertie
Absolutely do update with more details - ".. pass pointers to C# functions (delegates) into C code"What I'd look for is something like(C# initialization code) -> pass pointers to C# helper functions foo and bar to C code.Later, C code calls function foo, with argument "char *mydata", C# code writes chars into that array for return.This would be my absolutely preferred way of communicating so please like I said, elaborate
Nektarios
A: 

There's no reason at all to use ANSI C over C++. In addition, if you have C++ code, writing a C++/CLI wrapper for use in C# is very trivial (as far as I know) and C++ won't add two floats any slower than C will (many other operations are actually faster, like sorting). In addition to that, C++ is pretty flexible as to what you can do with it.

C++ <--> C++/CLI <--> C# is probably the easiest way to go, as C++/CLI interop can easily work both ways.

DeadMG
No, I wouldn't say writing a C++/CLI wrapper is trivial. I quit using C++/CLI partly because of how hard it was to allow C# to call plan-old C++ code - too much wrapping work was involved, making SWIG seem more attractive.
Qwertie
It's "trivial" in a sense that it is relatively simple. It's not trivial in a sense that it's still tedious. SWIG is definitely faster.
Pavel Minaev
+1  A: 

First of all, to answer one specific worry: you can marshal delegates as function pointers to your native C code - in fact, it "just works", and P/Invoke will take care of all the wrapping:

// C#
class ManagedEntryPoint {

    [DllImport("core", CallingConvention=CallingConvention.Cdecl)]
    static extern void NativeEntryPoint(Func<int, int, float> helper);

    static float Helper(int, int) { ... }

    static void Main() {
        NativeEntryPoint(Helper);
    }
}

// C
void NativeEntryPoint(float (*helper)(int, int)) {
    float x = helper(1, 2);
    ...
}

However, I don't see much point in this - it's easier to use C++/CLI compiler. Note that this doesn't mean that you actually have to use C++ - you can stick to the subset of C which is C++-compatible, which is 95% of it (I'd expect about the only thing you'll need to do differently in practice is explicitly casting the return of malloc). You compile your native C functions as a native .lib, and then link that to an executable compiled with /clr. C++/CLI will take care of all the marshaling itself, and you won't need to write P/Invoke declarations and such.

Pavel Minaev
Great, thank you
Nektarios