POV-Ray : Newsgroups : povray.off-topic : Adventures with WCF Server Time
31 Oct 2024 14:08:53 EDT (-0400)
  Adventures with WCF (Message 1 to 10 of 30)  
Goto Latest 10 Messages Next 10 Messages >>>
From: Orchid Win7 v1
Subject: Adventures with WCF
Date: 6 Nov 2013 15:43:23
Message: <527aa9eb$1@news.povray.org>
OK, so I've got a small but fairly complicated client/server program, 
using a trivial custom communications protocol that I wrote myself. 
Basically I want the client program to remotely execute methods in the 
server program. And, as you might suspect, it turns out there are 3rd 
part libraries for doing that kind of thing automatically.

One such library is Microsoft's "WCF". (No, I have no idea what that 
stands for.) The idea, according to what little documentation I can 
find, is that you write a C# interface, write some code that implements 
that interface, and then you can hook up a client so it can call the 
interface methods just as if they were local.

Trouble is, WCF is a huge, sprawling framework with a bazillion bells 
and whistles. It's almost impossible to make any sense out of the API 
documentation. (For one thing, it's mostly extremely terse.) What's 
really lacking is something to explain the high-level abstractions and 
give you somewhere to *start*...

Oh, there *is* documentation, mind you. Both from Microsoft themselves 
and on various blogs and so on. But they all say something along the 
lines of "open Visual Studio, select the WCF Class Library template, 
watch it generate eleventy-billion lines of XML configuration file which 
isn't explained or documented anywhere on the face of the Internet".

Most horrifyingly of all, it seems that absolutely everything to do with 
WCF defaults to turning method calls into XML data [which seems 
reasonable enough] and then transmitting it via HTTP [which is the most 
absurd thing I've ever heard of]. Almost nowhere does it tell you how to 
turn off the completely unnecessary HTTP layer and just run on plain TCP 
sockets.

(Seriously. HTTP provides *nothing* which is useful for transferring 
transient data. It's just pointless overhead. What the hell is *wrong* 
with the world? *Why* must *everything* be kludged to work over HTTP 
these days? Sheesh...)

If you walk through the examples, it does eventually work. But the way 
it works is bizarre: You've written a C# interface, which lists exactly 
what methods your server exposes. And yet, what they want you to do is 
enable "metadata exchange (mex)", and then run a command-line tool which 
connects to the server, downloads the interface description, and 
generates C# code for talking to the server.

Even though the necessary information is ALREADY sitting RIGHT THERE in 
that interface you just wrote! WTF?

(I suppose if the server was written by somebody on the other side of 
the planet and you don't have the source code, being able to dynamically 
look up its API is nice. But for any other use-case... why this much 
complexity??)

Sadly, it seems that mex cannot ever be made to operate over TCP, only 
HTTP. (Christ knows why...) Also disturbing is that if you use the magic 
WCF template, Visual Studio somehow "knows" if your service is running 
or not, and automatically starts and stops it when you try to run 
clients that use it. This makes me very, very nervous!



Well, you know what? All that stuff I just said? You can completely 
ignore that bunch of nonsense. Because it turns out that all you 
*actually* need to do is this:

1. Write a C# interface, with the right attributes on it.

2. Write a class in your server that implements this interface.

3. Execute THREE LINES OF CODE in your server's Main() function, telling 
it what class implements the interface, and where to listen for clients.

4. Write THREE LINES OF CODE in the client, using the interface type as 
a generic parameter. You get passed back a proxy object which implements 
the interface - but whenever you call a method, it actually executes on 
the server. Transparently. With no effort from you other than writing 
THREE LINES OF CODE.

So, yeah. The client and the server both reference the same C# interface 
type, and WCF automagically transports arguments and results between 
client and server. Other than figuring out how to connect to each other, 
there's almost no code involved. In particular, you DO NOT need a 
200-line XML file with undocumented contents to make this work!

Now, if something somewhere on the Internet would have just *said* all 
that, I could have saved myself many, many hours of head-banging...



Of course, this all means much less code needs to be written. But on the 
other hand, I just surrendered control to an external library, so now 
it's much harder to work out why things aren't working. ;-)

It seems that, by default, opening a connection creates your proxy 
object, but doesn't actually *connect* to the server until you try to 
call a method. Which means that if anything goes wrong, instead of 
throwing an exception in the connection method, it throws an exception 
in some other random place in your application, depending on where you 
just happen to try to use the server for the first time. :-S

It's easy enough to fix that one. It's not documented, but there's an 
Open() method which forces the connection to be opened *right now*. You 
know, so I can decide whether to proceed or not based on whether the 
server is *actually* listening to me or not.

Unfortunately, it seems by default, if the server is *not* listening, 
the Open() method simply waits forever. This is not very helpful. 
Fortunately, you can trivially specify a timeout as a parameter to the 
method. So that's OK.

Now the *real* fun begins! You see, I actually want to use this stuff on 
a mixture of .NET and Mono. I wrote a small test project to check that I 
could get this stuff to work, but I only tried it on .NET, and only on 
the local machine. When I tried to modify the *real* application to use 
WCF, suddenly I ran into several problems.

The first problem is that Mono *refuses* to listen on all network 
interfaces. Won't do it. You can easily to it with .NET, but Mono won't.

https://bugzilla.xamarin.com/show_bug.cgi?id=275

To sumarise: If you ask .NET to listen on "localhost", it will accept 
any and all incoming network connections. If you ask Mono to listen to 
"localhost", it will *only* accept connections from the local machine. 
Under .NET, you can listen on "0.0.0.0" to allow connections from all 
configured IP addresses (including loopback). But on Mono, this THROWS 
AN EXCEPTION. (!!) Finally, you can listen on one of your machine's 
configured IP addresses (assuming you can FIND one...), in which case 
only connections to that address are accepted.

To sumarise the summary: Mono can listen to internal connections OR 
external connections, but not both at the same time [which is the 
*default* action under .NET] Oh, well, unless you explicitly configure 
TWO listening addresses...

So it seems an easy hack for that is to listen on whatever 
Dns.GetHostName() returns. Now remote connections are allowed. (But not 
local ones under Mono. But hey, the real application happens to not need 
local connections...)

Next, a rather more strange issue. It seems that if you run my client 
and server under .NET, everything is fine. If you run them both under 
Mono, everything is fine. But if you run one under .NET and one under 
Mono... the connection just hangs forever. (Or times out if you 
specified a timeout value.) What the...?

OK, so that this point I'm guessing defaulting shenanigans. And it turns 
out I'm right:

https://bugzilla.xamarin.com/show_bug.cgi?id=276

By default, .NET runs TCP with SSL turned on, while Mono defaults to 
having SSL turned off. So presumably the client (.NET) is sitting there 
waiting for some SSL handshake data, while the server (Mono) has no 
intention of sending any such data - and has no idea the client is 
waiting for it.

What, no feature negotiation step? :-P

The solution is pretty simple; just explicitly specify whether SSL 
should be on or off. (And specify it the same way for both client and 
server.) But man, do you have *any idea* how many protocol configuration 
options there are?? It's a damned good thing this is the only one who's 
default value differs between .NET and Mono, because otherwise I'd have 
to explicitly configure every single one of them...!

Hey, wait a sec. Bug #275 is a WCF bug in Mono, and bug #276 is 
*another* WCF bug in Mono. Do you suppose #277 is...

https://bugzilla.xamarin.com/show_bug.cgi?id=277

...yes, of course it is. It's *another* WCF bug in Mono. Oh goodie!

Essentially, .NET allows multiple services to listen on the same TCP 
port, provided they each have a different URL. (Presumably one component 
listens, then when it sees the URL it routes the connection to the 
appropriate handler or something...) If you attempt to do this under 
Mono, it simply throws an exception at you. Let me say that again: A 
perfectly acceptable, working program on .NET summarily throws an 
exception if you run it under Mono.

Oh dear. I was actually contemplating *using* that particular feature... 
oh well, I guess not! (Makes that part of the URL _completely_ pointless 
now though, doesn't it?)

So I deploy my new WCF code, and I hit upon *another* problem: It seems 
that after a while, the server disconnects for no apparent reason. 
Searching the Internet gives me nothing, until *eventually* I stumble 
upon a vague reference to ReceiveTimeout.

Reading the scant documentation, it appears that if the server doesn't 
hear anything for this number of seconds, it disconnects the client. The 
intention seems to be that a client can't hog server resources by just 
connecting and then saying nothing.

OK, a couple of things.

1. I can see how this might be bad if you were offering this service to 
the entire world (or maybe just a large internal network). However, I'm 
using this for 1 server with 1 client. This is an internal test 
framework. It will never be exposed to the outside world. I don't *care* 
about resource usage!

2. Doesn't TCP *already* send periodic heartbeat messages and close the 
connection if it doesn't get a reply for a while? Why is WCF trying to 
duplicate this functionality when it's already present??

Well anyway, all you have to do is go set ReceiveTimeout to some higher 
value. (The documentation is inconsistent, but I believe this defaults 
to 10 minutes - which is too soon, considering some of my tests take 
half an hour.)

Oh, wait a sec... That works on .NET, but under Mono is has ABSOLUTELY 
NO EFFECT. Wuh?! O_O

OK, so under Mono it appears to be _impossible_ to stop the server 
disconnecting. So there's that. Also, while in the process of doing 
this, I found that on .NET you can say AddDefaultEndpoints(), and it 
does what the documentation says. However, when you run this under Mono, 
it THROWS AN EXCEPTION saying the required method DOES NOT EXIST! :-O

Fortunately, it turns out I don't really need this method. It's trivial 
enough to generate the default endpoint by hand. But sheesh... the 
entire experience of WCF on Mono just seems to be a steaming pile of 
broken. And I really don't know how to fix this disconnect issue; it's 
looking like I'll have to write a pile of code to manually send 
heartbeat messages to the server just to hold the connection open. (You 
know - the EXACT SAME THING that the TCP layer is ALREADY DOING!!)

When you have to write MORE CODE to disable a supposed "feature" of the 
framework you're using... yeah, what can you say?



On the plus side, if I ever get this stuff to work, it'll be beautiful. 
I especially like the way I can make it so if the server throws an 
exception, the client gets the exception (rather than just hang forever 
or spit out a socket exception). I suspect this is going to make things 
far more reliable...


Post a reply to this message

From: Orchid Win7 v1
Subject: Re: Adventures with WCF
Date: 6 Nov 2013 15:46:21
Message: <527aaa9d@news.povray.org>
On 06/11/2013 08:43 PM, Orchid Win7 v1 wrote:
> Hey, wait a sec. Bug #275 is a WCF bug in Mono, and bug #276 is
> *another* WCF bug in Mono. Do you suppose #277 is...
>
> https://bugzilla.xamarin.com/show_bug.cgi?id=277
>
> ...yes, of course it is. It's *another* WCF bug in Mono. Oh goodie!

OK, so admit it: Now you want to know if #278 is WCF as well! :-D

Well no, it isn't. But I just this second realised that #274 is WCF. (It 
seems a global constant is set to null under Mono.)

#273 isn't WCF though.

What I find amusing is that these bugs were reported in 2011, and most 
of them are still open...

(And by "amusing" I of course mean some suitable antonym of "amusing"...)


Post a reply to this message

From: Doctor John
Subject: Re: Adventures with WCF
Date: 6 Nov 2013 15:47:41
Message: <527aaaed@news.povray.org>
On 06/11/13 20:43, Orchid Win7 v1 wrote:
> OK, so I've got a small but fairly complicated client/server program,
> using a trivial custom communications protocol that I wrote myself.

<snip>

> On the plus side, if I ever get this stuff to work, it'll be beautiful.
> I especially like the way I can make it so if the server throws an
> exception, the client gets the exception (rather than just hang forever
> or spit out a socket exception). I suspect this is going to make things
> far more reliable...

Thankyou Andrew for assuring me that the world still goes on (see
preceding post)

John
-- 
Protect the Earth
It was not given to you by your parents
You hold it in trust for your children


Post a reply to this message

From: Orchid Win7 v1
Subject: Re: Adventures with WCF
Date: 6 Nov 2013 16:24:04
Message: <527ab374$1@news.povray.org>
On 06/11/2013 08:47 PM, Doctor John wrote:
> Thankyou Andrew for assuring me that the world still goes on

There's no charge for this service. :-)


Post a reply to this message

From: scott
Subject: Re: Adventures with WCF
Date: 7 Nov 2013 03:21:19
Message: <527b4d7f@news.povray.org>
> 3. Execute THREE LINES OF CODE in your server's Main() function, telling
> it what class implements the interface, and where to listen for clients.
>
> 4. Write THREE LINES OF CODE in the client, using the interface type as
> a generic parameter.

Aren't you going to share those three lines of code?

> Now the *real* fun begins! You see, I actually want to use this stuff on
> a mixture of .NET and Mono.

It wasn't too long ago you were complaining how you didn't even have a 
.net runtime installed and it was a huge bloated monster and didn't 
understand why anyone would want to use it - and you would have told us 
all that it was obviously impossible to get any .net code working on 
anything other than Windows. What a change (for the better)! :-D


Post a reply to this message

From: Orchid Win7 v1
Subject: Re: Adventures with WCF
Date: 7 Nov 2013 13:15:58
Message: <527bd8de$1@news.povray.org>
On 07/11/2013 08:21 AM, scott wrote:
>> 3. Execute THREE LINES OF CODE in your server's Main() function, telling
>> it what class implements the interface, and where to listen for clients.
>>
>> 4. Write THREE LINES OF CODE in the client, using the interface type as
>> a generic parameter.
>
> Aren't you going to share those three lines of code?

OK, so here's what you have to do.

First, write your interface:

   [ServiceContract]
   public interface IDoStuff
   {
     [OperatioContract]
     double DoTheStuff(double x, double y);
   }

Next, write the server code that actually does it.

   public class RealDoStuff : IDoStuff
   {
     ...
   }

Now, to serve the interface to the outside world, do this:

   var host = new ServiceHost(typeof(RealDoStuff));
   host.AddEndpoint(typeof(IDoStuff), "net.tcp://localhost:1664/DoStuff/");
   host.Open();

Clients can now connect and run any method mentioned in IDoStuff. 
Speaking of which... On the client end, do this:

   var binding = new NetTcpBinding();
   var factory = new ChannelFactory<IDoStuff>(binding, 
"net.tcp://localhost:1664/DoStuff/");
   var proxy = factory.CreateChannel();

The "proxy" object implements IDoStuff. You can call it like any other 
local object. But actually, when you call it, it calls your server.

Actually, the client doesn't attempt to make a network connection until 
the first time you call a method on the proxy - which is a bit annoying! 
You can force it to open immediately, however:

   ((ICommunicationObject)proxy).Open();

A similar technique can be used to explicitly close the connection if 
you want to.

Compare this to, for example,

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
     <startup>
       <!-- specifies the version of WCF to use-->
         <supportedRuntime version="v4.0" 
sku=".NETFramework,Version=v4.5,Profile=Client" />
     </startup>
     <system.serviceModel>
         <bindings>
             <!-- Uses wsHttpBinding-->
             <wsHttpBinding>
                 <binding name="WSHttpBinding_ICalculator" />
             </wsHttpBinding>
         </bindings>
         <client>
             <!-- specifies the endpoint to use when calling the service -->
             <endpoint 
address="http://localhost:8000/ServiceModelSamples/Service/CalculatorService"
                 binding="wsHttpBinding" 
bindingConfiguration="WSHttpBinding_ICalculator"
                 contract="ServiceReference1.ICalculator" 
name="WSHttpBinding_ICalculator">
                 <identity>
                     <userPrincipalName 
value="mig### [at] redmondcorpmicrosoftcom" />
                 </identity>
             </endpoint>
         </client>
     </system.serviceModel>
</configuration><?xml version="1.0" encoding="utf-8" ?>
<configuration>
     <startup>
         <supportedRuntime version="v4.0" 
sku=".NETFramework,Version=v4.5,Profile=Client" />
     </startup>
     <system.serviceModel>
         <bindings>
             <wsHttpBinding>
                 <binding name="WSHttpBinding_ICalculator" />
             </wsHttpBinding>
         </bindings>
         <client>
             <endpoint 
address="http://localhost:8000/ServiceModelSamples/Service/CalculatorService"
                 binding="wsHttpBinding" 
bindingConfiguration="WSHttpBinding_ICalculator"
                 contract="ServiceReference1.ICalculator" 
name="WSHttpBinding_ICalculator">
                 <identity>
                     <userPrincipalName 
value="mig### [at] redmondcorpmicrosoftcom" />
                 </identity>
             </endpoint>
         </client>
     </system.serviceModel>
</configuration>

*This* is the way Microsoft insists you have to do it.

To be fair, this has the advantage that you can change the network 
configuration without recompiling your client or server code. But in my 
case, since this is an internal application which only I will ever use, 
this "advantage" is moot.

>> Now the *real* fun begins! You see, I actually want to use this stuff on
>> a mixture of .NET and Mono.
>
> It wasn't too long ago you were complaining how you didn't even have a
> .net runtime installed and it was a huge bloated monster and didn't
> understand why anyone would want to use it - and you would have told us
> all that it was obviously impossible to get any .net code working on
> anything other than Windows. What a change (for the better)! :-D

Well, when somebody pays you to write .NET code, you spend an hour or 
two installing .NET (Actually, VS takes multiple hours to install...) It 
wasn't my decision to use C#. ;-)

Having said that, C# is basically like Java, but less broken. It even 
has real generics (rather than the fake generics they kludged into 
Java). Hell, you can write *monads* in C#! ;-)

I'm still pretty sure that .NET was invented for the sole purpose of 
vendor lock-in though. And back when I was whining about it, Mono didn't 
exist. :-P

Man, the amount of bugs in the Mono WCF stuff... >_<


Post a reply to this message

From: scott
Subject: Re: Adventures with WCF
Date: 8 Nov 2013 02:48:55
Message: <527c9767$1@news.povray.org>
> OK, so here's what you have to do.
...
That seems pretty simple, I'll file that in "useful stuff to remember" :-)

Someone at work introduced me to Arduino a few months ago (they used one 
to control a test rig here), I was so impressed how simple it was to set 
up and code for that I ordered one myself to tinker with at home - so 
that's taking up my "spare" time at the moment. Along with decorating 
the house, and playing iRacing, and keeping fit, and ... Fiddling with 
C# is pretty low down the list nowadays.

> I'm still pretty sure that .NET was invented for the sole purpose of
> vendor lock-in though. And back when I was whining about it, Mono didn't
> exist. :-P

I'm sad that MS have discontinued proper 3D graphics support with C#. 
You used to have the option between XNA or managed DirectX, both of 
which were pretty easy to use at perfectly good enough performance 
levels. Now you have to use C++ and Windows 8, which is a shame as 
that's not really justification enough for me to upgrade from Windows 7 
(not to mention relearning all the differences between C++ and C#).


Post a reply to this message

From: Francois Labreque
Subject: Re: Adventures with WCF
Date: 8 Nov 2013 09:28:42
Message: <527cf51a$1@news.povray.org>

>
> Most horrifyingly of all, it seems that absolutely everything to do with
> WCF defaults to turning method calls into XML data [which seems
> reasonable enough] and then transmitting it via HTTP [which is the most
> absurd thing I've ever heard of]. Almost nowhere does it tell you how to
> turn off the completely unnecessary HTTP layer and just run on plain TCP
> sockets.
>
> (Seriously. HTTP provides *nothing* which is useful for transferring
> transient data. It's just pointless overhead. What the hell is *wrong*
> with the world? *Why* must *everything* be kludged to work over HTTP
> these days? Sheesh...)
>

There are two reasons for this:
- Everybody and their grandmother knows how to handle HTTP.  You don't 
need to rewrite a custom interface to handle AndrewTP over port 31337 
when you want to interface with the application.  (Just dealing with the 
XML parser is enough headaches already!)

- Firewalls

> So I deploy my new WCF code, and I hit upon *another* problem: It seems
> that after a while, the server disconnects for no apparent reason.
> Searching the Internet gives me nothing, until *eventually* I stumble
> upon a vague reference to ReceiveTimeout.
>
> Reading the scant documentation, it appears that if the server doesn't
> hear anything for this number of seconds, it disconnects the client. The
> intention seems to be that a client can't hog server resources by just
> connecting and then saying nothing.
>
> OK, a couple of things.
>
> 1. I can see how this might be bad if you were offering this service to
> the entire world (or maybe just a large internal network). However, I'm
> using this for 1 server with 1 client. This is an internal test
> framework. It will never be exposed to the outside world. I don't *care*
> about resource usage!

Then program a keepalive message at the application level.

>
> 2. Doesn't TCP *already* send periodic heartbeat messages and close the
> connection if it doesn't get a reply for a while? Why is WCF trying to
> duplicate this functionality when it's already present??
>

Not always.
TCP keepalive is an option and defaults to off.

Secondly, you may have many short-lived TCP connections part of the same 
long-lived application "session" (e.g.: online shopping, or http 1.0)

> Well anyway, all you have to do is go set ReceiveTimeout to some higher
> value. (The documentation is inconsistent, but I believe this defaults
> to 10 minutes - which is too soon, considering some of my tests take
> half an hour.)
>

How does your client know the difference between the server processing 
the request and the server having exploded in a firey ball of ones and 
zeroes?

When you get put on hold, do you prefer hearing a "your call is 
important to us, please remain on the line to retain your calling 
priority" reminder ever minute or so, or just hearing dead air, not 
knowing if the agent hung up on you, or it looking at your file?

Client/server apps are the same.  If you want the communication channel 
to remain open, you should program a keepalive, and ideally an 
erro-recovery mechanism where it will try to reconnect in case the 
keepalive gets eaten by goblins.

> Oh, wait a sec... That works on .NET, but under Mono is has ABSOLUTELY
> NO EFFECT. Wuh?! O_O
>
> OK, so under Mono it appears to be _impossible_ to stop the server
> disconnecting.

At the risk of repeating myself... program an application-level keepalive.


-- 
/*Francois Labreque*/#local a=x+y;#local b=x+a;#local c=a+b;#macro P(F//
/*    flabreque    */L)polygon{5,F,F+z,L+z,L,F pigment{rgb 9}}#end union
/*        @        */{P(0,a)P(a,b)P(b,c)P(2*a,2*b)P(2*b,b+c)P(b+c,<2,3>)
/*   gmail.com     */}camera{orthographic location<6,1.25,-6>look_at a }


Post a reply to this message

From: Orchid Win7 v1
Subject: Re: Adventures with WCF
Date: 8 Nov 2013 13:38:37
Message: <527d2fad$1@news.povray.org>
>> (Seriously. HTTP provides *nothing* which is useful for transferring
>> transient data. It's just pointless overhead. What the hell is *wrong*
>> with the world? *Why* must *everything* be kludged to work over HTTP
>> these days? Sheesh...)
>>
>
> There are two reasons for this:
> - Everybody and their grandmother knows how to handle HTTP. You don't
> need to rewrite a custom interface to handle AndrewTP over port 31337
> when you want to interface with the application. (Just dealing with the
> XML parser is enough headaches already!)

But this is *still* using XML - it's just that it's sending it on top of 
HTTP rather than over a raw TCP socket.

> - Firewalls

This is not a valid reason.

> Then program a keepalive message at the application level.

Right, so now I have to have a second thread sitting in the background 
with a timer, and I have to remember to reset that timer every time a 
command is sent, and then when the timer runs down, I send a null 
command and reset the timer... Surely all this boilerplate code should 
be in the framework?

Seriously, when I used plain TCP, I didn't need to do this. The helpful 
framework is forcing me to do *more* work!

(Well, technically it's not the framework's fault that Mono implements 
it wrong, but anyway...)

> How does your client know the difference between the server processing
> the request and the server having exploded in a firey ball of ones and
> zeroes?

No, this is the *server* not waiting for the *client*.

> Client/server apps are the same. If you want the communication channel
> to remain open, you should program a keepalive

This shouldn't be necessary. (And when it was plain TCP, it *wasn't* 
necessary, because TCP already implements this for you.)

> and ideally an
> erro-recovery mechanism where it will try to reconnect in case the
> keepalive gets eaten by goblins.

It appears to be impossible to tell under WCF when the connection has 
been broken.

>> OK, so under Mono it appears to be _impossible_ to stop the server
>> disconnecting.
>
> At the risk of repeating myself... program an application-level keepalive.

The solution I eventually came up with was to connect, send one command, 
and then immediately disconnect. So now the program makes a new 
connection for every individual command. It's inefficient, but what else 
can I do?


Post a reply to this message

From: Orchid Win7 v1
Subject: Re: Adventures with WCF
Date: 8 Nov 2013 13:40:47
Message: <527d302f$1@news.povray.org>
On 08/11/2013 07:48 AM, scott wrote:
> (not to mention relearning all the differences between C++ and C#).

Ooo, I can explain this one for you:

   The difference between C++ and C# is... they bare absolutely no 
resemblance to each other whatsoever!

Part of our code is C#, and a small part is C++. We try to avoid 
touching the C++ part. (I especially enjoy the way it compiles 
differently under different compilers... Oh, and manually editing 
Makefiles is fun too.)


Post a reply to this message

Goto Latest 10 Messages Next 10 Messages >>>

Copyright 2003-2023 Persistence of Vision Raytracer Pty. Ltd.