Hello Guest it is March 28, 2024, 09:10:24 PM

Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.


Messages - CWare

Pages: 1 2 »
2
Hi everyone,


this took me a few days to figure out...

I must thank rhtuttle for pointing me in the right direction
and ART for giving me a list of commands and a few more tips.
If you found this helpful make sure to thank those guys.

The following code will
Connect to Mach 3
reset mach
, home the axes
, close any open file
, load a specified file
,rewind it
, set feedrate to 300%
and CycleStart

          

If anyone has a full list with the button numbers that would be a great help, Mach needs to ref all home before cyclestart idk what the buttonr is though...

If you spot any errors or have suggestions or found something cool to add  please post them below.
What should be added is some way to check if mach is ready to cyclestart that usleep is ugly and also reset should check if the reset already occurred...




Compiled In Code::Blocks with the MinGW compiler->linker settings
-lole32
-loleaut32
-luuid



Code: [Select]
#include <iostream>
#include <ole2.h>
#include <Windows.h>
#include <Objbase.h>
#include <OleAuto.h>
#include <cstring>
#include <string.h>
#include <unistd.h>



CLSID   clsid,clsid2;
bool connected;

using namespace std;


TCHAR *GetLastErrorMessage(DWORD last_error)
{
    static TCHAR errmsg[512];
    if (!FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,0,last_error,0,errmsg,511,NULL)) {
        return (GetLastErrorMessage(GetLastError()));
    }

    return errmsg;
}



HRESULT OLEMethod(int nType, VARIANT *pvResult,
                  IDispatch *pDisp,LPOLESTR ptName, int cArgs...)
{
    if(!pDisp) return E_FAIL;

    va_list marker;
    va_start(marker, cArgs);

    DISPPARAMS dp = { NULL, NULL, 0, 0 };
    DISPID dispidNamed = DISPID_PROPERTYPUT;
    DISPID dispID;
    char szName[200];

    // Convert down to ANSI
    WideCharToMultiByte(CP_ACP, 0, ptName, -1, szName, 256, NULL, NULL);

    // Get DISPID for name passed...
    HRESULT hr= pDisp->GetIDsOfNames(IID_NULL, &ptName, 1,
                                     LOCALE_USER_DEFAULT, &dispID);
    if(FAILED(hr)) {
        return hr;
    }
    // Allocate memory for arguments...
    VARIANT *pArgs = new VARIANT[cArgs+1];
    // Extract arguments...
    for(int i=0; i<cArgs; i++) {
        pArgs[i] = va_arg(marker, VARIANT);
    }

    // Build DISPPARAMS
    dp.cArgs = cArgs;
    dp.rgvarg = pArgs;

    // Handle special-case for property-puts!
    if(nType & DISPATCH_PROPERTYPUT) {
        dp.cNamedArgs = 1;
        dp.rgdispidNamedArgs = &dispidNamed;
    }

    // Make the call!
    hr = pDisp->Invoke(dispID, IID_NULL, LOCALE_SYSTEM_DEFAULT,
                       nType, &dp, pvResult, NULL, NULL);
    if(FAILED(hr)) {
        return hr;
    }

    // End variable-argument section...
    va_end(marker);
    delete [] pArgs;
    return hr;
}



void CloseMach(LPDISPATCH &InterfPtr)
{
    HRESULT ivres;

    DISPPARAMS dp = { NULL, NULL, 0, 0 };
    ivres=InterfPtr->Invoke(0x4, IID_NULL, LOCALE_SYSTEM_DEFAULT,
                            DISPATCH_METHOD, &dp, NULL, NULL, NULL);


    cout<<GetLastErrorMessage(ivres)<<endl;



}


void LoadFile(LPDISPATCH &InterfPtr, OLECHAR*Filename)
{
    HRESULT ivres;

    VARIANT vtFileName;
    vtFileName.vt = VT_BSTR;
    vtFileName.bstrVal = SysAllocString(Filename);


    ivres=OLEMethod(DISPATCH_METHOD, NULL, InterfPtr, L"LoadGCodeFile", 1, vtFileName );             // reversed order is using more options


    cout<<GetLastErrorMessage(ivres)<<endl;



}


void CloseFile(LPDISPATCH &InterfPtr)
{
    HRESULT ivres;

    DISPPARAMS dp = { NULL, NULL, 0, 0 };
    ivres=InterfPtr->Invoke(0x2, IID_NULL, LOCALE_SYSTEM_DEFAULT,
                            DISPATCH_METHOD, &dp, NULL, NULL, NULL);


    cout<<GetLastErrorMessage(ivres)<<endl;

}


void CycleStart(LPDISPATCH &InterfPtr)
{
    HRESULT ivres;

    DISPPARAMS dp = { NULL, NULL, 0, 0 };


    ivres=OLEMethod(DISPATCH_METHOD, NULL, InterfPtr, L"CycleStart", NULL, dp );
    cout<<"CycleStart"<<GetLastErrorMessage(ivres)<<endl;

}



void RewindGcode(LPDISPATCH &InterfPtr)
{
    HRESULT ivres;

    DISPPARAMS dp = { NULL, NULL, 0, 0 };


    ivres=OLEMethod(DISPATCH_METHOD, NULL, InterfPtr, L"RewindGcode", NULL, dp );
    cout<<GetLastErrorMessage(ivres)<<endl;

}


void SetFRO(LPDISPATCH &InterfPtr,double FeedOverride)
{
    HRESULT ivres;

    VARIANT FRO;
    FRO.vt = VT_R8;
    FRO.dblVal = FeedOverride;


    ivres=OLEMethod(DISPATCH_METHOD, NULL, InterfPtr, L"SetFRO", 1, FRO );             // reversed order is using more options


    cout<<GetLastErrorMessage(ivres)<<endl;


}


void Reset(LPDISPATCH &InterfPtr)
{
    HRESULT ivres;


    VARIANT BNnr;
    BNnr.vt = VT_I2;
    BNnr.iVal = 21;

    ivres=OLEMethod(DISPATCH_METHOD, NULL, InterfPtr, L"DoButton",1,BNnr );             // reversed order is using more options

    cout<<GetLastErrorMessage(ivres)<<endl;


}



IDispatch* GetScriptDispatch(LPDISPATCH &InterfPtr)
{
    HRESULT ivres;


    VARIANT result;
    VariantInit(&result);
    ivres=    OLEMethod(DISPATCH_PROPERTYGET, &result, InterfPtr, L"GetScriptDispatch", NULL, NULL );             // reversed order is using more options
    return(result.pdispVal);

    cout<<GetLastErrorMessage(ivres)<<endl;


}


void HomeAll(LPDISPATCH &InterfPtr)
{

    HRESULT ivres;


    VARIANT BNnr;
    BNnr.vt = VT_I2;
    BNnr.iVal = 24;

    ivres=OLEMethod(DISPATCH_METHOD, NULL, InterfPtr, L"DoButton",1,BNnr );             // reversed order is using more options

    cout<<GetLastErrorMessage(ivres)<<endl;


    BNnr.vt = VT_I2;
    BNnr.iVal = 23;

    ivres=OLEMethod(DISPATCH_METHOD, NULL, InterfPtr, L"DoButton",1,BNnr );             // reversed order is using more options

    cout<<GetLastErrorMessage(ivres)<<endl;


    BNnr.vt = VT_I2;
    BNnr.iVal = 22;

    ivres=OLEMethod(DISPATCH_METHOD, NULL, InterfPtr, L"DoButton",1,BNnr );             // reversed order is using more options

    cout<<GetLastErrorMessage(ivres)<<endl;

    BNnr.vt = VT_I2;
    BNnr.iVal = 25;

    ivres=OLEMethod(DISPATCH_METHOD, NULL, InterfPtr, L"DoButton",1,BNnr );             // reversed order is using more options

    cout<<GetLastErrorMessage(ivres)<<endl;

}





void OnBnClickedConnect()
{
    LPUNKNOWN lpUnk;
    LPDISPATCH lpDispatch=NULL;
    LPDISPATCH Scripter=NULL;

    //COleException e;
    HRESULT res;

// Initialize COM for this thread...
    CoInitialize(NULL);


    // Get CLSID for our server...

    if (CLSIDFromProgID(L"Mach4.Document", &clsid) != NOERROR)

    {
        cout << "error CLSIDFromProgID" << endl;
        return;
    }

    if (res = GetActiveObject( clsid, NULL, &lpUnk) == NOERROR) {
        HRESULT hr = lpUnk->QueryInterface(IID_IDispatch,
                                           (LPVOID*)&lpDispatch);  //get a pointer to the object's IDispatch interface.

        lpUnk->Release();

        if (hr == NOERROR) {


            connected = true;
            cout << "connected" << endl;


            Scripter=GetScriptDispatch(lpDispatch);


            if(Scripter!=NULL) {

                cout << "gotScripter" << endl;
                Reset(Scripter);
                HomeAll(Scripter);
                CloseFile(lpDispatch);
                LoadFile(lpDispatch, L"C:\\R1.ngc");
                RewindGcode(lpDispatch);
                SetFRO(lpDispatch,300.0);
                usleep(300000);
                CycleStart(lpDispatch);


            }








        }

        //m_Status = "Connected to Mach3.";
        // UpdateData(false);
        // SetTimer( NULL,1, 200, NULL );





        return ;
    } else {

        cout << "error GetActiveObject" << endl;

    }
    //m_Status = "No Connection to Mach3.";
    //UpdateData(false);
    // Uninitialize COM for this thread...
    CoUninitialize();
   if(lpDispatch!=NULL){
    free(lpDispatch);
    
   }
   if(Scripter!=NULL){
    free(Scripter);
    }

}







int main()
{
    connected = false;

    OnBnClickedConnect();

    return 0;
}




Mach3 should be running. If this fails to connect make sure you got all registry keys...


Code: [Select]
Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOT\CLSID\{CA7992B2-2653-4342-8061-D7D385C07809}]
@="Mach4.Document"

[HKEY_CLASSES_ROOT\CLSID\{CA7992B2-2653-4342-8061-D7D385C07809}\InprocHandler32]
@="ole32.dll"

[HKEY_CLASSES_ROOT\CLSID\{CA7992B2-2653-4342-8061-D7D385C07809}\LocalServer32]
@="C:\\Mach3\\Mach3.exe"

[HKEY_CLASSES_ROOT\CLSID\{CA7992B2-2653-4342-8061-D7D385C07809}\ProgID]
@="Mach4.Document"

[HKEY_CLASSES_ROOT\Mach4.Document]
@="Mach4.Document"

[HKEY_CLASSES_ROOT\Mach4.Document\CLSID]
@="{CA7992B2-2653-4342-8061-D7D385C07809}"

Thanks to machpendant for that regfix.



Use at your own risk...

3
Thanks a bunch for clearing that up.
I should be able to manage with that much info.
I'll take it from here and try to write a console application in code::blocks if I manage i'll post it here.

cheers

4
Figured out something more

plugin = a dll that loads at runtime. The code in the dll is executed in the update loop of mach I guess.

That MachRemote application uses OLE https://en.wikipedia.org/wiki/Object_Linking_and_Embedding  to communicate.
I guess that means mach must be active in the background.

Could you show me how to make a wrapper for mach?
You showed mach's dro's updated when you changed values from from machme. What is going on there? Was machme altering some files which mach also reads or was it the mach gui and machme gui loaded together.
Later when you closed mach machme was still operational?


5
Ok seems this is a bit above my experience level.
I'm not familiar with the way vs creates dialogs. I use qt for gui's if needed.
Writing to registry is also something unfamiliar.
Well eh you get the picture.
I was hoping to be able to use the methods in the headers to establish communication.

I found your thread
https://www.machsupport.com/forum/index.php?topic=11240.0
Installed it.
unfortunately it's expired?

Saw on your yt channel what it does...

You've done exactly what I look for .
I'm still a bit confused though to how you did it and how this works.


Installed vs2010  yesterday which isn't the right one but at least I see the project tree of the sdk plugin.
Watched the video of I believe Jerry on creating a plugin.


You didn't seem to need a plugin.
Your program asks for the mach.exe and the xml?


Found this online
COM clients are applications that make use of a COM object implemented by another application Automation Servers (Automation controllers) and applications that host an ActiveX control (ActiveX containers).

To make information about the COM server available to your client application, you must import the information about the server that is stored in the server's type library. Your application can then use the resulting generated classes to control the server object.

You wrote
"If your development environment has the ability to import a type library that will create the wrapper for you."
searched wrapper
so you took the mach. exe and wrapped it in a class?

I haven't done anything like that
Also what is that machremote example doing.
This seems to connect

Code: [Select]
void CMachRemoteDlg::OnBnClickedConnect()
{
LPUNKNOWN lpUnk;
LPDISPATCH lpDispatch;
COleException e;
HRESULT res;

if (CLSIDFromProgID(OLESTR("Mach4.Document"), &clsid) != NOERROR)
{
   return;
}
    if (res = GetActiveObject( clsid, NULL, &lpUnk) == NOERROR)
{
HRESULT hr = lpUnk->QueryInterface(IID_IDispatch,
(LPVOID*)&lpDispatch);
lpUnk->Release();
if (hr == NOERROR)
{
mach4.AttachDispatch(lpDispatch, TRUE);
lpDispatch = mach4.GetScriptDispatch();
scripter.AttachDispatch(lpDispatch, TRUE);
}
    connected = true;
m_Status = "Connected to Mach3.";
UpdateData(false);
SetTimer( 1, 200, NULL );
return ;
}

m_Status = "No Connection to Mach3.";
UpdateData(false);

}

Am I correct that there are 3ways to do something similar.

1 plugin.
2 some remote access.
3 wrapper com

trying to figure out which one the easiest is to implement without using vs.



6
Thanks a lot for replying,
I guess its the
procedure LoadRun(const FileName: WideString);

I havent done anything in pascal though its not familiar.

 where can i find documentation for it or a sample program would be awesome?

7
Shall do thanks.

8
General Mach Discussion / Re: Cable length
« on: March 14, 2016, 12:36:46 PM »
Long cables bad idea.
20ft step dir :s


What else have you done?

Have you tried reinstalling windows and checked the cooling and power of the ting?
A lightbulb emits noise so if you put it in your case I guess you should turn it off before starting the pc.


9
So it isn't possible?
Any of the devs I could pm?

10
General Mach Discussion / Re: MUST KILL WINDOZE!!
« on: March 14, 2016, 12:07:25 PM »
Um do you have admin rights?

Pages: 1 2 »