3

What are the best practices for building a GUI desktop app that will support both Windows and OS X? Let's say it's budgeting software, so there is a bit of math and some big data structures. User data is saved in XML files; there is no separate database or networking.

At one extreme, you could just build the Windows version in C# and the Mac version in Objective C. Is there a better approach, so you can more easily keep the two versions in sync and write less duplicate code? Would you write the math and data structures and "business logic" in C++, with pre-processor directives for simple system calls like IO, and then a separate GUI layer written once for Windows and once for OS X? Is C/C++ the only choice for the cross-platform back end, assuming you want native code? Is there any way to write even the GUI part a single time? (I expect not.)

Please note that I'm not asking how to use a cross-compiler. I'm interested in how you'd structure your overall project for the least hassle.

Paul A Jungwirth
  • 23,504
  • 14
  • 74
  • 93

3 Answers3

3

You are essentially correct. You would write the data model in C/C++ and the UI in C#/.NET and Objective-C/Cocoa.

I'm not familiar with how C# talks to non-C# code, but Objective-C (being built on C) will easily talk to C and C++ (the latter with Objective-C++). You can also use Python and/or Ruby with Objective-C code and the Cocoa frameworks, if you'd prefer to use them for the cross-platform segments.

I applaud you for looking beyond the easy solution of Java or other cross-platform UIs. You'll have a better-looking, easier-to-use product if you go the native route.

Cajunluke
  • 3,103
  • 28
  • 28
  • It's not too nasty calling from a C# app to a C/C++ dll. It's cleaner if I make the dll "managed," but I suspect that would sufficiently pollute the C++ code so it'd be hard to compile it for a Mac. (I'm not positive; I don't have experience with managed C++.) – Paul A Jungwirth Feb 05 '11 at 16:13
2

It's very likely that I have a different view from most on this issue, given my strong feelings about platform native user interfaces and controls/widgets, but I very much tend to prefer your second approach. Even I'm not masochistic enough to go through the hassle of building the entire application separately.

So I would definitely write the library or data layer code entirely separate from the GUI layer. Doing it in C++ is an obvious choice, especially if you're already comfortable with that language, but more on that later. The point is that this code should be limited only to your "business logic", and thus completely platform independent. If you follow solid object-oriented principles, it should work out that the bulk of the programming work is done on this level.

Separately from that, you would write a thin, "wrapper" library over the core OS and UI functions for both Windows and OS X. The wrapper library would be the sole entity responsible for directly interacting with the platform, and your data layer code should call functions from this wrapper library, rather than directly from the platform's API.

Of course, several of you reading this are probably screaming "But that's what QT already does for you!" Yeah, I know. But it doesn't use native widgets, and it doesn't conform to standard platform conventions in so many places. That means it sucks. I've seen other wrapper libraries for Windows that do get this right, but I've yet to see one on OS X that looked halfway decent. Yes, I'm picky, but so is your typical Mac user. They just won't put up with the type of garbage on their screen that Windows users will, and even the Mac Office team knows this. (We all collectively applaud you for trying to get this right.)

As far as your choice of languages, you say that you are looking for native code on both platforms. That's a pretty difficult blob of jelly to pin to the wall. For example, do you consider JIT-complied code to be native? If not, that rules out C#. Excluding any type of interpreted code rules out a host of other potential languages. You aren't left with many options other than C++ and Objective-C. But C++/Win32 programming isn't that much more difficult than Cocoa programming, just different.

Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
  • I agree with your aesthetic judgments re GUI platforms, and your assessment of Mac users. To me, C# on Windows and Obj-C on Mac are sufficiently "native" (I'm targeting a pretty old version of .Net.) I just don't want the shared code to bring along a big framework install. – Paul A Jungwirth Feb 05 '11 at 16:19
  • I assumed by "native" he meant "primary supported language/framework" not strictly "compiles to native assembly" *because* he mentioned C#. – Cajunluke Feb 05 '11 at 16:23
  • 1
    @Paul: Then it's worth noting that the C# interop with C++ code is really not that difficult. But I think writing a wrapper lib that calls into native APIs (which you would do in C++ even on Windows rather than C# because the .NET Framework provides its own GUI library) is still an easier solution than reinventing the GUI entirely separately on both platforms. Of course, if you do decide to design separate GUIs on both platforms, you have even more flexibility. You might want your app to look like iTunes on the Mac and Microsoft Word on Windows, for example. – Cody Gray - on strike Feb 05 '11 at 16:24
  • 1
    @Cajun: Sure, that's one possible interpretation. But it's also wrong to suppose that C#/.NET is the "primary supported language/framework" on Windows. I suppose it's a testament to Microsoft's marketing prowess that so many people think that, but Windows *does* provide a native API that programmers have been using for years to write C/C++ applications. It's called Win32, and WinForms is just a heavy wrapper over it. WPF adds some extra stuff of its, but ultimately relies on the Win32 API as well. .NET still doesn't meet *either* definition of "native". – Cody Gray - on strike Feb 05 '11 at 16:26
  • @Cody: I love the idea of a UI wrapper library with platform-specific C++/Obj-C implementations, but if it were that easy, wouldn't that exist already? – Paul A Jungwirth Feb 05 '11 at 16:55
  • @Cody: ... or are you telling me that Qt isn't so bad after all? :-) – Paul A Jungwirth Feb 05 '11 at 17:02
  • 1
    @Paul: No, no. I wouldn't use Qt, but that doesn't stop you from doing something similar to what it does yourself. It's not strictly a wrapper because it reimplements the standard controls. If you wrote your own wrapper, you'd simply call down to the platform and let it handle drawing the controls/windows/etc. If you're familiar with WinForms, this is basically what it does with the Win32 API. MFC does this with Win32 API in C++. Of course, you wouldn't need to expose *all* possible functionality, just what your app used. But the point is a `Button` control would look and act the same way – Cody Gray - on strike Feb 05 '11 at 17:05
  • 1
    (continued) as far as your application's code is concerned because all it ever deals with is your wrapper libraries, which present a common interface. The wrapper libraries would be independently responsible for doing all the heavy lifting with the OS. Translating that abstract `Button` class into whatever the platform APIs require to get that button drawn on screen and otherwise interact with it. Does that make sense? I'm not sure exactly how much programming experience you have, and with what languages/platforms. This isn't going to be a trivial project, of course. – Cody Gray - on strike Feb 05 '11 at 17:07
  • @Cody: Thanks for the long response. Most of my experience is in webapps, both with heavy Java+Frameworks, or light Perl/Python. On the desktop, I've done some Swing (ick) and Obj-C, but mostly C# WinForms. I'm pretty confident in C, much less in C++ (especially the windows API). I'm still a bit incredulous about building my own cross-platform UI library, but it's tempting! Thanks again for all your detailed suggestions. – Paul A Jungwirth Feb 05 '11 at 17:44
  • @Cody: You are saying that Qt doesn't use native widget in OS X (and also in Windows) and that Qt doesn't conform to standard platform conventions. My experiences with Qt in Windows are that the Qt apps look much more native than Microsoft's own applications. Can you point to any references about Qt's standard convention deviations? I am not saying that Qt is perfect, I just would like to find out more detailed information about the deviations. –  Feb 05 '11 at 18:18
  • @Roku: I think you missed the point. How can something look "much more native than Microsoft's own applications"? Yeah, Microsoft Office now misses the point, too. I refuse to use it. But I'm talking about Windows itself. There's a *huge* difference between letting the operating system draw your buttons vs. drawing them yourself to *simulate* what the OS does. Qt chooses the latter option. Regrettably, it's not alone in that decision. Fire up Spy++ and look around at different controls. I'm really not sure how else to explain it to you if you can't appreciate the fundamental difference. – Cody Gray - on strike Feb 06 '11 at 04:19
  • @Cody: Its quite easy for Microsoft to violate its own standards. Just look Office, IE, Visual Studio. All have subtly different menus. But I don't understand why you say that Qt's way of drawing controls is bad. It uses the native API (both in OS X and Windows) to draw the controls, so what's the problem? You are correct, the Qt widgets are still not native widgets. But what's the problem there? For example .NET uses native widgets and my experiences (C#, .NET 2) are that they are awfully slow and flickering. I prefer fast, flicker free and native looking Qt widgets. –  Feb 06 '11 at 10:05
  • @Roku: Yeah, MS violates their own standards; not my argument. No, Qt doesn't use the native API to draw the controls. They're not standard Windows controls. Bust out your copy of Spy++ or equivalent to verify. Not all of the .NET widgets are "native", and the reason .NET flickers more than Qt is Qt has implemented double-buffering across the board. You could easily do this with the API (or even in .NET), if you didn't mind the performance hit. I've never written a Win32 application or seen Cocoa app that flickered. Ever. – Cody Gray - on strike Feb 06 '11 at 10:33
  • @Cody: Well, yes, Qt uses native APIs to draw the widgets: http://en.wikipedia.org/wiki/Qt_%28framework%29#Use_of_native_UI-rendering_APIs As I said, the widgets are not *native widgets* but they are drawn using *native widget drawing APIs*. As a developer, I don't mind the difference. Originally I was wondering what are the differences that the end user can see. I don't think that many end users inspect their apps with Spy++. And btw, I haven't been able to get rid of all the .NET flickering even with double buffering. –  Feb 06 '11 at 11:08
  • @Roku: Good to see that they're finally trying. They're still not there yet. I'm not really sure what's so hard about actually using the native controls. But whatever. I said at the top of my answer that there would probably be a lot of people who disagree with me. Users do care, they just don't know *why* they care. They can't put their finger on it. That's not unique to software development. – Cody Gray - on strike Feb 06 '11 at 11:11
1

Have you looked at Mono? It allows you to develop in .Net but deploy across platforms.

JoeyRobichaud
  • 2,689
  • 1
  • 15
  • 11
  • 1
    Thank you for the suggestion, but I don't want to encumber the install with a big framework. Otherwise I'd use Java. – Paul A Jungwirth Feb 05 '11 at 16:06
  • 1
    @Paul: Note that C#/.NET *still* requires a framework when you install it on a Windows machine. Yes, lots of computers can be expected to have this installed already, but certainly not all. And the degree to which you can depend on an installed base depends on which version of the .NET Framework you target. You can't assume that everyone will have the latest version installed; it hasn't even been included with a version of Windows yet. If your goal is to avoid frameworks altogether (and like I mentioned in my answer, stick to strictly native code), you'll have to eschew C# on the PC side, too. – Cody Gray - on strike Feb 05 '11 at 16:12
  • @Cody, see my comment to your answer: I'm planning to require a pretty old .Net, so it should be there. – Paul A Jungwirth Feb 05 '11 at 16:21