everything-else

more like a current position, not a direction

i have not had many hours to work the last few days, but i think i have come up with a plan..

i am not going to bother with any wpf or xaml or anything not in a default .net 2.0 installation. this will allow me to ship an intermediate product to robotengineer. right now it is called servotalk. basically it is a tool that lets you make a model out of servos. you'll then be able to use it to control your real servos like a puppet.

this just so happens to be exactly what i am making for my robot. who the hell would buy such a thing? well, there is a good chance that the whole 3 people out there that would probably read servo magazine. niche, niche. anyway. i need it and it is always good to have a reason to shine up a project for real. it'll also give me a chance to release early (often!).

i decided that i am going to use c++/cli + forms. i just feel like programming in c++ (ish) and not c# right now.

one of the "features" of servotalk will be that it is extensible so that it can support a wide variety of servo controllers. i am going to accomplish that by compiling code on the fly with the CodeDomProvider.

anyway, here's how you can abuse the clr to do your extensibility bidding.. i am subclassing a compiled c++ class from a c# source file and instantiating the it at runtime.. CRAZY!

it is a mess as i just barely got it working (mostly), so tough.

Code:

#include "servotalk.hpp"

#include <cassert>

using namespace servotalk;

namespace Lame
{
public ref class LameWindow : public Form
{

public:
   
   virtual void cheese()
   {
      MessageBox::Show("cheese");
   }

};
}

Object^ deserialize_object_from_codedomprovider_stream(CodeDomProvider^ provider,Stream^ stream,StringWriter^ errorStream)
{
   assert(provider!=nullptr);
   assert(stream!=nullptr);

   CompilerParameters^ params=gcnew CompilerParameters();
   params->ReferencedAssemblies->Add("System.dll");
   params->ReferencedAssemblies->Add("System.Windows.Forms.dll");
   params->ReferencedAssemblies->Add("servotalk_debug.exe");
   params->GenerateInMemory=false;
   
   StreamReader sr(stream);
   String^ source=sr.ReadToEnd(); 
   //MessageBox::Show(source);
   
   CompilerResults^ compilation=provider->CompileAssemblyFromSource(params,source);
   if(compilation->Errors->HasErrors)   
   {
      String^ errorStr=gcnew String("");
   
      errorStr+=compilation->Errors->Count.ToString() + " Errors:";
      for (int x=0;x<compilation->Errors->Count;x++)
      {
         errorStr+= "\r\nLine: " + compilation->Errors[x]->Line.ToString() + " - " + compilation->Errors[x]->ErrorText;
      }
      
      MessageBox::Show(errorStr);
         
      if(errorStream!=nullptr)
      {
         errorStream->Write(errorStr);
      }
      
      return nullptr;
   }

   return compilation->CompiledAssembly->CreateInstance("MyNamespace.MyClass");
}


[STAThreadAttribute]
int main(array<System::String ^> ^args)
{
   String^ sourceStr = " \
      using System; \
      using System.IO; \
      using System.Windows.Forms; \
      namespace MyNamespace \
      { \
         public class MyClass : Lame.LameWindow \
         { \
            public override void cheese()  \
            { \
               MessageBox.Show(\"Cheese Donkey\"); \
            } \
         } \
      } \
      ";

   MemoryStream sourceMS;
   StreamWriter sourceSW(%sourceMS);
   sourceSW.Write(sourceStr);
   sourceSW.Flush();
   sourceMS.Flush();
   sourceMS.Position=0;
   Object^ obj=deserialize_object_from_codedomprovider_stream(gcnew CSharpCodeProvider(),%sourceMS,nullptr);
   Lame::LameWindow^ window=dynamic_cast<Lame::LameWindow^>(obj);
   window->cheese();
   window->Show();
   
   while(window->Created)
   {
      Application::DoEvents();
   }

   return 0;
}


this is just a rehash/remix of random csharp code you might find on the inet, but the proof of concept seems to work.