Hello Guest it is December 07, 2019, 12:00:17 AM

Author Topic: Plugin development in VS2005, VS2008  (Read 14431 times)

0 Members and 1 Guest are viewing this topic.

Offline j1sys

*
  •  16 16
    • View Profile
Plugin development in VS2005, VS2008
« on: April 09, 2008, 12:57:45 PM »
Hello All -

I am 99.99% confident I have found the "Why" on why development can't be done on VS2005/VS2008.

I am 97% confident I can "fix" the problem and will soon be releasing ".h" files and instructions for others to use.

The problem IS that Mach is passing you four VERY important pointers. (Thank you Art/Brian). The problem is that several of these are pointers to CLASSes not STRUCTs.

To track down the problem I turned on "Assembly Code Listing" in both 2003 and 2008 and compared the generated code line by line. (Yes I'm that crazy). I immediately found that most of the offsets on MainPlanner (TrajectoryControl *) are WAY off. The reason is that TrajectoryControl inherits CWnd and CWnd changed in the MFC libraries between versions. There may be other inheritance differences that add to the problem.

To test my theory I cast the pointer to a hand crafted struct pointer to allow acces to the TCPModBusData struct down near the end of the data area. Using the struct I was then able to access and display the cgf array in a simple MessageBox in myConfig. I use this same technique in VS2003 to have a look at the raw data inside Mach for debugging a stand-alone MODBUS TCP Simulation Server I am working on for release to the Mach community. I now have two versions of the data dumping plugin. One compiled in VS2003 and one, with minor changes, compiled in VS2008.

I am in the process of analyzing TrajectoryControl.h line by line with the intent of creating a STRUCT that can be used in place of the CLASS. This should allow greater portability across different version of the compiler. I am INITIALLY only targeting the Data areas. After completion I will then target the public functions. I don't know if anyone is, or IMHO even should, or can be calling functions in the class currently in VS2003.

This is not just a tease. I am making rapid progress daily and wanted to "leak" to the community that we may have a clean solution soon.

My ultimate goal will be to then wrap ALL interfaces with Mach in a both a managed C++ class and a C# class to allow using .NET. Using .NET may be optimistic but I believe I can do it. If I can't do it directly then I will wrap it all in COM and interact that way.

-Ed

Edward D. Bryson
Joshua 1 Systems Inc.
Knoxville TN USA

Offline ART

*
  • *
  •  1,698 1,698
  • Tough as soggy paper.
    • View Profile
Re: Plugin development in VS2005, VS2008
« Reply #1 on: April 09, 2008, 02:53:44 PM »
Ed:

  Interesting. I did know that it was an issue with the trajectory class's pointers getting corrupted, but I didnt know that CWnd changed size between versions. I wonder if theres a constant to tell windows a version of class. Good Job though, those changes would make things much easier for aspiring plugin authors. Let me know how you make out and Ill update the release resources to reflect it. Ill try to get some tie this week to see if there is soem arcane compiler switch that will take care of it. OR if perhaps an easier solution exists. Seems to be it should be safe to take a class pointer using a CWnd class, seems an awful big hole to leave between versions..

Thanks
Art
Re: Plugin development in VS2005, VS2008
« Reply #2 on: April 09, 2008, 05:07:02 PM »
Good work ED!!!! I need to get 2008 at some point :)

Thanks
Brian
Fixing problems one post at a time ;)

www.newfangledsolutions.com
www.machsupport.com

Offline poppabear

*
  • *
  •  2,233 2,233
  • Briceville, TN, USA
    • View Profile
    • S S Systems, LLC
Re: Plugin development in VS2005, VS2008
« Reply #3 on: April 09, 2008, 05:52:05 PM »
For what it is worth..........

   I can vouch for Ed, he is the guy I have been taking weekly C++ classes from for doing plugins. I met him as my student in the Mach3 Convention, he noted he was a programmer of some 30 years experience. So, I asked for classes from him. It took him about 1-2 weeks to get up to speed on plugins, and then he started pointing out the issues to me, using LARGE and EXPENSIVE words that I never learned on Seaseme Street...........

   At any Rate, I bugged him to bug YOU:    Art and Brian about his discoveries, since I figured you fellers would understand the big words since you already paid for them, and I am just learning them, hehehe.

   Thanks again Ed, for your potintial fixes to the Plugin community, this will help us all greatly.

The plug in he is helping me do, is to take inputs from a modbus, parpport, or TCP to use as a direct External jogging button. So he got me started and pointed in the right way. So far I have all 6 axis jogging + and - with LEDs that light for that function, through serial modbus using Arturos boards. I will be adding Analog Jog override, jog on-off, Jog-select type, jog-select axis vs. a jog all axis. (i.e. if you pushed the negative direction on each of the six axis then all would move simultanously), and a few other odds, and ends.

He Explained more to me, and I learned more from him in just a few hours, than my own study of days........

As a side note he is building some Hardware that will greatly enhance the Mach community as well, be on the look out for it........

Scott
« Last Edit: April 09, 2008, 05:54:38 PM by poppabear »
Commercial Mach3 & Mach 4, Design/Build/Retrofit CNC and Industrial machines.
http://www.ss-systems-llc.com/

Offline j1sys

*
  •  16 16
    • View Profile
Re: Plugin development in VS2005, VS2008
« Reply #4 on: April 09, 2008, 06:27:52 PM »
Art, Brian, Poppabear -

I am doing all this with VS Pro 2008, and VS Pro 2003. But I'm targeting, when done, to provide all the pieces that will allow ANYBODY to use the free VS2008 student editiion.

Art/Brian (poppabear wouldn't understand ;^)) - In all of your initial programming I'm sure you didn't ever plan on opening up and allowing plugins. Again thanks for doing it. I will try to provide more help, info, tutorials, templates, functions to the community to support its work and leave you guys to work on the big picture. IMHO classes, especially inherited ones, are not the best choice of how to communicate between master and plugin. Think about COM, Interop and all the Marshaling Options built into the new languages to allow communication with OLD DLLs. They are all based on STRUCTs not CLASSes. In this case we are trying to do the reverse. I understand it will be a VERY big undertaking for you to upgrade your code. I support many legacy customers going back to Manx Aztec C and VC6 for DOS. Just like you like to/need to add a new data field to support a new feature, CWnd needed to be improved. As soon as it added one bool it changed the offset to YOUR classes part of the buffer. That is one of the beauties of inheritence. You can always use a pointer to access the lower classes in the hierarchy. It may be possible to use ALL the headers and libraries from VS2003 plugged into VS2008 but I don't think it is worth the risk or effort. If I remember the code paradigm for C++ it really just passes a pointer to the class data structure as a first hidden parameter but otherwise follows the _CDECL calling format. I should be able to wrap any needed functions in custom static classes and expose an easy to use interface for plugin writers. My worst problems might be exposing the CString text. They may have changed its layout also and it will require some poking around to find the public or hidden pointer that will get me to the raw data.

My plan is to make a struct that has byte arrays of fill space to skip over the areas I can't/won't do on each pass. The following example code snippet is the cheater struct I used to test my theories with TCPModBusData:

struct TrajectoryControlTCPModCon
{
   char   fill1[2762596l];

   TCPModCon   TCPModBusData;
};

TrajectoryControl                 *M3MainPlanner;                  // original CLASS pointer
TrajectoryControlTCPModCon *M3MainPlannerTCPModCon; // duplicate STRUCT pointer

#define   REGTYPE_INPUT_REGISTERS   0x00
#define   REGTYPE_INPUT_HOLDING   0x01
#define   REGTYPE_INPUT_COILS   0x02
#define   REGTYPE_INPUT_DISCRETE   0x03
#define   REGTYPE_OUTPUT_HOLDING   0x04
#define   REGTYPE_OUTPUT_COILS   0x05

.....

extern "C" __declspec(dllexport) bool   InitControl(void *m3Engine, void *m3Setup, void *m3MainPlanner, void *m3View)
{
   AFX_MANAGE_STATE(AfxGetStaticModuleState());

   M3MainPlanner = (TrajectoryControl *) m3MainPlanner;
   M3MainPlannerTCPModCon = (TrajectoryControlTCPModCon *) m3MainPlanner;

   return true;
}

//---------------------------------------------------------------------
//
//   Config() - Legacy Config Interface
//
//---------------------------------------------------------------------

extern "C" __declspec(dllexport) void   Config()
{
   AFX_MANAGE_STATE(AfxGetStaticModuleState());

    CString   txt;

    txt = "";

    TCPModCon   *tcpModCon1 = &M3MainPlanner->TCPModBusData;                      //just to compare ASM listings
    TCPModCon   *tcpModCon2 = &M3MainPlannerTCPModCon->TCPModBusData;     //---------------------------------------

     for (int i = 0; i < 65; i++)
    {
       TCPModCfg *tmc = &M3MainPlannerTCPModCon->TCPModBusData.cgf;

       if (tmc->Enabled)
       {
          CString   valTxt;
          int regType = tmc->Input;

          txt += "Cgf[";
          valTxt.Format("%02d", i);
          txt += valTxt;
          txt += "]: ";

          switch (regType)
          {
          case REGTYPE_INPUT_REGISTERS:
             valTxt = "Input - InputRegisters";
             break;
          case REGTYPE_INPUT_HOLDING:
             valTxt = "Input - HoldingRegisters";
             break;
          case REGTYPE_INPUT_COILS:
             valTxt = "Input - Coils";
             break;
          case REGTYPE_INPUT_DISCRETE:
             valTxt = "Input - DiscreteInputs";
             break;
          case REGTYPE_OUTPUT_HOLDING:
             valTxt = "Output - HoldingRegisters";
             break;
          case REGTYPE_OUTPUT_COILS:
             valTxt = "Output - Coils";
          }

          txt += valTxt;
          txt += "\n";

          switch (regType)
          {
          case REGTYPE_INPUT_COILS:
          case REGTYPE_INPUT_DISCRETE:
          case REGTYPE_OUTPUT_COILS:
             {
                int byteCnt = 8;
                int bitCnt = 8;

                for (int j = 0; j < tmc->nReg; j++)
                         {
                             if (tmc->Data[j]) txt += "1";
                             else txt += "0";

                             if (--bitCnt == 0)
                      {
                         if (--byteCnt == 0) { txt += "\n"; byteCnt = 8; }
                         else txt += " ";
                        
                         bitCnt = 8;
                      }
                   }

                     if (byteCnt < 8 ) txt += "\n";
             }
             break;
            

          case REGTYPE_INPUT_REGISTERS:
          case REGTYPE_INPUT_HOLDING:
          case REGTYPE_OUTPUT_HOLDING:
             {
                int wordCnt = 8;

                for (int j = 0; j < tmc->nReg; j++)
                         {
                             valTxt.Format("%04x", tmc->Data[j]);
                      txt += "0x";
                             txt += valTxt;

                             if (--wordCnt == 0) { txt += "\n"; wordCnt = 8; }
                             else txt += " ";
                   }

                     if (wordCnt < 8 ) txt += "\n";
             }
             break;
          }
       }
    }

   MessageBox(NULL, txt, "PluginCPP", 0);
}

On a side note. I've empiracally tried many different combinations to get the minimal acceptable functions and declarations to make a plugin. Is there any chance of publishing some of the "Load Plugin" code so I can try to get it down to bare bones?

-Ed

Offline ART

*
  • *
  •  1,698 1,698
  • Tough as soggy paper.
    • View Profile
Re: Plugin development in VS2005, VS2008
« Reply #5 on: April 09, 2008, 09:38:15 PM »
Hi Ed:

  Good Idea. I did similarly with some other code I used. The plugin loader
is pretty simple. It sends a pointer to the functions back to MAch3 so it
calls the DoButton() and the GetLED() etc... as pointers to the plugins
functions. All other calles are simply the pointers your playing with. Since
I didnt know what var's woudl be used, using Com' etc was really hard to
arrange without making every function exported.. Your right, I hadnt planned
on making it open, it just hit me one day so I di dit, unfortunately, this
makes it a bad usage of pointers. Hard to switch over though. Brian will
send you any code you think will help, but I suspect the loader isnt much
good to you, it only exports pointers from the plugin, which should be all
OK in any language, its just the classes that are an issue, and various
plugins use variosu variables , so its really hard to set them all to com.
Id suggest just finding the difference in size and using a subtraction from
the var names maybe.. gotta think about that one.. The original problem was
dll's wernt designed to callback to the originating code base, only to have
routines to BE called..
  Thanks for the investigations..


Thanks,
Art
Re: Plugin development in VS2005, VS2008
« Reply #6 on: April 10, 2008, 05:18:47 PM »
Ed, GREAT news.  And I'm glad Scott could find somebody so capable to help that is local.  Please keep me in the loop on all this and I will write another tutorial on getting started with plugins using VS 2005 and probably 2008.  I assume you are talking about the 'Express' free compilers when you mention the student editions?  How will you support MFC with those?

-James Leonard

Offline j1sys

*
  •  16 16
    • View Profile
Re: Plugin development in VS2005, VS2008
« Reply #7 on: April 10, 2008, 06:45:05 PM »
James -

My PERSONAL goal is to move away from MFC and use .NET in my plugins. Time critical code (40hz / 10 hz Update) MAY be left in C++ unmanaged but that code should not be doing MFC IMHO. The techniques to get it working at all can still be used by anybody for any purpose. I believe that the $199 VS2008 C++ Standard would include MFC support for those that needed it. We still are going to be constantly fighting the older version MFC vs either the newer version MFC or vs .NET. I'd rather fight the battle all the way and go for .NET.

I am also looking into the redistribution rights and restrictions to see what I could give someone with an Express version to use for MFC. Again for .NET they would already have it. So for simple plugins, if I can make it work and document it, .NET may be the answer.

It will be a moving target with several different solutions based on the needs of the individual. So the fun has just begun.

-Ed
Re: Plugin development in VS2005, VS2008
« Reply #8 on: April 10, 2008, 07:12:21 PM »
Hi Ed,

Ok, sounds very good.  I personally have zero interest in .NET so it seems together we can cover both sides of the fence.  My primary use of MFC in a plugin would be to simplify support for ActiveX controls on dialogs.  For most other uses I am a SDK programmer and working with ordinary modeless dialogs is going well for my CorelDRAW hosted CAD / CAM system.

I researched the MFC / Express compiler issues a LOT initially and AFAIK MFC just isn't available (legally) for usages like this.

-James Leonard

Offline j1sys

*
  •  16 16
    • View Profile
Re: Plugin development in VS2005, VS2008
« Reply #9 on: August 05, 2008, 10:34:12 AM »
Status Update -

I've spent over 80 hours in the last two weeks working on the .h files that will be needed to accomplish this.

I'm down to testing and working on a minimalist approach to a plugin. I am targeting using VS2008 C++ Express Edition with mixed mode CLR code.

I've got a plugin working in VS2008 C++ Professional. And have one ALMOST working in C++ Express. It loads, can be config'd (with managed dialogs), but blows up Mach with an infinite error message "ART9991" when I enable it.

A question for Brian/Art that would help me in finishing this:

About the 4 routines concerning COM automation (DLLGetClassObject, etc) - Does Mach USE COM to talk to the plugin or was this just if the plugin needed COM to talk to other software?

To me it looks like Mach does ALL simple DLL calls to the plugin. I have setup 'simple' functions like: extern "C" __declspec(dllexport) void Config()

These all appear to generate the proper DLL exports under examination with PEBrowserPRO.

My C++ Pro code is very similar to the example plugins. My C++ Express code can not access AfxDllGetClassObject, etc. since it does not include MFC headers. I'm trying to get around it by returning S_OK. Any ideas on what I can try? Would some other return tell Mach that I don't need automation and have it skip the other calls? Ultimately, with my mixed mode I should be able to use Managed COM for people that need COM.

Thanx,

-Ed

p.s. i will be asking for contributions to my new glasses fund after poring over 17,000 lines of assembly code to check out the structs that I replaced ALL classes with  ;^)