Hello Guest it is October 24, 2026, 04:33:58 PM

Recent Posts

Pages: « 1 2 3 4 5 6 7 8 9 10 »
81
MachPro General Discussion / Re: Screen Edit not saving.
« Last post by joeaverage on September 18, 2026, 03:20:46 PM »
Hi Paul,
excellent reply.....thanks.

Still digesting it all, but I like the trick of placing a self scripted button on top of or alongside a hard coded block.

When writing code in Mach4 all the calls were prepended 'mc........' or 'wx.........' To my mind these are Lua table structures with mc meaning Mach Core and wx meaning Widgets.
In Mach4 there is a similar table 'scr.....' but I never used it, and the advice given at the time was that it is and was not generally considered a table for use by a user.

In your reply I note that you specifically use and recommend the use of several tables for which I am unfamiliar.......starting with 'scr.' But also 'h.' and 'w.' Is there any documentation
that I can access to find out more about these tables and the functionality they confer?

Craig
82
MachPro General Discussion / Re: Screen Edit not saving.
« Last post by paul.stephens on September 18, 2026, 10:17:13 AM »
Hi,

Great questions. I'll address them the best I can..

Yes, you can run your own copy of the screen
The screen is not compiled into MachPro. It is a data file (a .set file) that is loaded at startup. The built-in workflow is exactly what you described:

  • Load the shipped screen.
  • Enter screen-edit mode.
  • Use Screen → Save As and give it your own name (for example, MyMill.set).
  • MachPro remembers that filename in your profile and loads your copy from then on. The shipped file is never touched.
  • So the "fork" approach you are already used to works here too: maintain your own .set, take responsibility for merging changes if you ever do update, and keep the original as your fallback.
  • Nothing in the user-code separation philosophy prevents this. That philosophy is about protecting you from updates, not about locking you out of the screen.
Your offsets, and those zero buttons

Your fixture offsets live on the Fixtures tab. That page exists for exactly the purpose you described: viewing and managing all the offsets that apply at a given moment.

And on the muscle-memory point: when you switch into Edit Offsets mode, Zero DRO buttons appear right next to each DRO. So the "zero button beside the DRO" workflow you're used to is already built into the screen. It only appears in that mode, deliberately, so an accidental tap during normal running can't zero an axis mid-job.

The Fixtures tab also has spare room and editable fields. If you want to rearrange it or add your own touches (extra readouts, your registration-hole button, and so on), it's a normal editable area in your forked copy, no workarounds needed.

Why some areas can't be edited
The reason you can add things outside the dashboard but can't change certain existing elements is that those areas (like the DRO block) are single, self-contained controls rather than groups of individually editable pieces. The editor can show them and let you attach code, but it can't let you rearrange what is inside them. There is nothing to grab onto.

The practical workaround where it matters: place your own buttons as separate controls overlapping or immediately adjacent to a sealed block, with your own code behind them. To the operator, the result looks and behaves the same as if the button were part of the block.

Screen editing tips
Use the UserGUIModule for behavior instead of (or alongside) the screen
If you haven't explored it yet, the UserGUIModule is your best friend for screen work. It lets you change what is displayed, switch pages, set labels, and adjust properties programmatically, which means you can often get what you want without editing the screen file at all. For example, forcing a specific page on a button press:

Code: [Select]
function UserGUIModule.MyCustomPage()

    scr.ShowPage("CustomPageName")

end
--If you want the button in your dashboard.
function UserGUIModule.CreateUserCommands()
w.CreateCommandActionOption("ShowMyCustomPage", function(from_opr_panel) UserGUIModule.MyCustomPage() end)
w.CreateSimpleCommand("ShowMyCustomPage")
end
Alternatively, if you wanted to call anything from the UserGUIModule inside the screen with, lets say a custom button:
Code: [Select]
--Button Script
h.ScreenButtonCall(User.MyCustomPage(), ...)



Anything you can do with scr.SetProperty or scr.ShowPage in a module survives updates cleanly, because modules are user code and are never overwritten. A good strategy is: use Save As for layout changes you can't achieve any other way (button placement for muscle memory), and use the UserGUIModule for everything else (showing pages, relabeling, hiding and showing elements). That minimizes the diff in your forked screen and makes any future merge almost painless.

Why the self-contained controls are actually on your side
I understand the frustration, but the "hard-coded" composite controls exist for a reason. Actually several, and they all benefit you directly:

They can't be broken by screen edits. The DRO block contains logic that must always work: position display, units handling, work/machine coordinate switching. If its internals were exposed to the editor, one accidental drag in edit mode could silently break a safety-critical readout. You'd never know until you scrapped a part.
  • They can't be broken by screen edits. The DRO block contains logic that must always work: position display, units handling, work/machine coordinate switching. If its internals were exposed to the editor, one accidental drag in edit mode could silently break a safety-critical readout. You'd never know until you scrapped a part.
  • They come pre-automated. This is the big one, and it's easy to overlook if you're coming from Mach4. Much of what a Mach4 user had to hand-build, such as wiring buttons to function codes, scripting enable/disable behavior, linking LEDs to signals, and making DROs respond to units and coordinate modes, is already built into these controls. Drop a Cycle Start button on the screen and it works: no script, no signal plumbing, no PLC ladder. Anyone who set up a Mach4 screen from scratch knows how many evenings that used to take. MachPro's controls remove that startup burden. The screen is functional out of the box, and your time goes into the custom things your machine needs, not into re-implementing the basics.
  • They survive updates. Because the control owns its own layout and behavior, a MachPro update can improve or fix the DRO block and your forked screen picks up the improvement automatically. The .set file just references the control; it doesn't freeze its internals.
  • Your code still attaches to them. You can read their properties, react to their state, and build your own controls around them. They're sealed, not isolated.

In other words: the areas you can't edit are precisely the areas that either (a) would cost you parts if accidentally broken, or (b) would cost you evenings to rebuild if they weren't automated. The areas you can edit (pages, groups, dashboards, and your own buttons with your own code) are where all the productivity wins live anyway, and there the field is wide open.

Why custom buttons should use h.ScreenButtonCall()
When you add your own button to the screen, its script property (for example, the Left Up Script) should call h.ScreenButtonCall(...) rather than calling your function directly. It is the standard entry point the shipped buttons use, and it gives your custom button the same protection and polish for free:
  • Password protection is enforced automatically. If you set a password level on the button in the screen editor, ScreenButtonCall checks it before your code runs. No extra code in your handler, and no chance of an unauthorized operator triggering your function.
  • Errors can't crash the screen. Your handler runs inside a protected wrapper. If your Lua code throws an error, you get a warning message instead of a dead UI.
  • Every press is logged. The button's label and press are written to the log, which makes diagnosing "what did the operator do just before this happened" much easier.
  • Standard argument handling. It passes your custom arguments first and the standard screen-event parameters (control name, event source, control type) last, so your handler signature stays consistent with every other button in the system.

The pattern looks like this in the button's script:
Code: [Select]
h.ScreenButtonCall(m.screen.MyCustomFunction, ...)
Yes, multiple pages and tabs are supported
Tabs are a first-class feature of the screen system. A dedicated Machine Diagnostics tab holding your live offsets block (and as many or as few I/O LEDs as you feel are worth the effort) is a completely normal thing to build. It costs zero space on the main page until you click over to it, which is exactly the behavior you described wanting. And with a scr.ShowPage("Diagnostics(1)") style call in the UserGUIModule, you can even jump to it from a button or a key rather than hunting for the tab.

One note before you build it: check the Fixtures tab first. Between its offsets display and Edit Offsets mode, it may already cover much of what your diagnostics page was doing, which would save you the rebuild.
83
General Mach Discussion / Re: Help !!
« Last post by Larrythelathe on September 18, 2026, 09:02:02 AM »
i hope these pictures help. I can upload more if anyone can help
84
General Mach Discussion / Re: Help !!
« Last post by Larrythelathe on September 18, 2026, 09:01:03 AM »
3.1
85
General Mach Discussion / Re: Help !!
« Last post by Larrythelathe on September 18, 2026, 08:41:08 AM »
pic
86
General Mach Discussion / Help !!
« Last post by Larrythelathe on September 18, 2026, 08:32:32 AM »
Hi all
Bit of back ground. I am a mechanical eng who has found himself sick and home bound. My son who has just finished school is really found it hard to get any work. So i have decided to teach him basic skills in CAD and CAM to make him more employable. I have purchase 360 and have the intro license on Mach 3.
I am fine with 360 and maybe mach 3.

My problem is spindle wiring and i have a tool height setter. I am needing spindle control then i can see about mach 3. I have attached some pictures of what i have. The spindle control bored has three wires that need connecting but i cannot figure out where. Same goes for the tool height setter it has four wires two paired normally open two paired normally closed. i have connect to input 4 and one to ground. but i don't see a change in the diagnostic page. I need to be able to do before i try and teach him as it stresses both out !

87
PoKeys / connect 24VDC Quad (4 Channel) Relay Module to Pokeys57CNC
« Last post by Toner on September 17, 2026, 06:19:18 PM »
Hello,
Anyone connect 24VDC Quad (4 Channel) Relay Module to Pokeys57CNC?
Is this where I connect In1 In2 In3 In4 on Pokeys57CNC? Using OC1+,  OC2+, OC3+, OC4+?
Relatively new at this and Pokeys terminology not actually the same as other cheap controllers that I have used.
88
MachPro General Discussion / Re: Screen Edit not saving.
« Last post by joeaverage on September 17, 2026, 04:58:40 PM »
Hi Paul,
I want to drill down  a bit into why it is not possible to edit the screen outside of the dashboard areas.

In particular you say for instance that areas outside of the dashboard areas are hard coded. It is clear that I can try to edit those areas, and the features I wish to add
or modify show up and look even to have the appropriate code behind them to operate but I cannot overwrite the 'as shipped' screen.

Is it possible to make a copy (editable) of the 'as shipped' screen and have MachPro execute that copy rather than its current default?.

I am not hugely in favour of one screen over another, I care very little for cosmetics, but I care VERY much about functionality and productivity.

For example you posted that I could put <ZeroAxis> buttons in the dashboard area, as a solution to not being able to put the same feature alongside the DRO. Understand that
I have literally thousands of hours operating my machine, and it is now a matter of muscle memory that I zero an axis using the button alongside its DRO. Likewise I consider it normal
and logical to put a button (for drilling registration holes) with its underlying function coding in the file group alongside <CycleStart>,<Reset>,<Enable> etc.

I note from my other thread that MachPro is very strong on separating User Logic, User Mcodes etc from underlying 'as shipped' logic and functionality. Ostensibly meaning that future
updates will not overwrite user code. I understand that philosophy, but does that philosophy preclude me from doing it my way?

I do not update Mach4 all the time, in fact I am using build 4612, which is at least three years old. Simply put I do not feel the need to update software all the time. If what I've got works
then why bother?. If there were something genuinely new and advantageous in an update, well that's fine.....but more often than not updates contain little or nothing that improve
the parts coming out of the machine. This is a critical difference between me and many other hobbyists, I could care less about cosmetic changes but am hugely interested in
productivity enhancements.

Suffice it to say that I am accustomed to maintaining a 'fork' in Mach4 to handle those specific features that I have determined aid productivity, and accept responsibility of the complications
were I to do the same thing with the MachPro screenset.

Another question in a similar vein is whether it is possible to have multiple pages or tabs  in the screen set?. In particular I like to maintain a Machine Diagnostics tab. It has a data block that
maintains all the relevant offsets that apply at a given moment. I only use it occasionally and therefore do not want to waste real-estate on the main page (tab) for it.....but it is very convenient when
you're diagnosing a problem. The same tab (pictured) used to have a lot more LED's reflecting various IO's, but at the last update after which I had to re-do the screen I just could not be bothered with the
extra work, and in general they provided very little in the way of extra information pursuant to problem solving.

Craig
89
MachPro General Discussion / Re: MachPro upgrade questions
« Last post by joeaverage on September 17, 2026, 03:01:24 PM »
Hi Paul,
another excellent description.

I have several Mcodes on which my work depends.

In particular m40 and m41, which were back in Mach3 days, built-in functions to open a data file, and then close it. This file would be used for storing probing or point cloud data.

I use Autoleveller, a freeware utility to probe PCB blanks and relies on storing probing data. Mach4 had some facsimilies of m40, m41 but I had to extensively modify them to use Autoleveller.
The procedures you've outlined will allow me to import those macros into MachPro.

The same advice with respects to built-in Mach4 Mcodes also applied, you risked overwriting Mach's functionality with unpredictable results. You could however do so if you chose.
For instance I have a custom m8 macro to introduce a delay when turning on the coolant pump. When Mach4 encountered an Mcode it would search, in the first instance,
in the Profile/Macros folder, ie the user file,  and enact it if it did find it. If there was no such macro in that folder then Mach would 'search up the file tree' until it found it,
usually Mach4's built-in function.

MachPro's handling of the same process is very much more structured. Sure it adds some architectural complexity but much increases the reliability of the outcome.

Also it demystifies the use of 'hooks', a term I had not previously been familiar with in connection with Mach software.

I think it fair to say that in your last two posts you have very convincingly demonstrated that MachPro is in fact a more architecturally sophisticated evolution of Mach4. All the functionality
that I regarded as essential in Mach4 is available, in fact is a subset of what is available in MachPro. All to the good. There remains now another 'bone of contention' regarding the
editability or otherwise of the screen set. This I will address it in that thread, as you have comprehensively answered my upgrade concerns in this thread.

Craig
90
MachPro General Discussion / Re: MachPro upgrade questions
« Last post by paul.stephens on September 17, 2026, 11:42:34 AM »
Hi,

Quote
Can I also assume that any functionality that I would normally include in the Mach4 ScreenLoad script I can include in UserGUIModule.mcs?

That is correct! We Ideally want to keep any custom User logic abstracted from the main framework. It is the same way for MCodes as well. We have a UserMCodeModule that is used for MCodes. The process is slightly different for them, but the results are the same.

I'll run through the basics of the MCode as well..

How to make a new MCode:

What is an MCode?
An MCode is a command in a part program (G-code file) that makes the machine do something other than move; turn a spindle on, open a clamp, run a probe routine, and so on. MCodes look like M3 (spindle clockwise) or M30 (end of program).

Mach comes with many MCodes already built in. You can also create your own, for example, M500 could turn on a vacuum pump, open a door, or run any sequence your machine needs. This guide walks through creating M500 from scratch. The same steps work for any new MCode, just pick a number that isn't already used (numbers 500 and above are the safest choices for custom codes).

The Big Picture (two files, two jobs)
A custom MCode needs two files. Keeping them straight is the whole trick:

FileFolder PathJob / Description
m500.mcsMach\Profiles\<your profile>\Macros\The doorbell. When the machine sees M500 in a program, it looks for and runs this file. Without this file, nothing happens, ever.
UserMCodeModule.mcs     Mach\Profiles\<your profile>\Macros\Scripts\     The brain. This is where you write what M500 actually does.

Think of it this way: the machine can't call you unless you have a doorbell (m500.mcs). The doorbell's only job is to ring you. What you do when you answer is written in the brain (UserMCodeModule.mcs).

Adding a Custom MCode:
Step 1: Create the doorbell: m500.mcs
Open the folder Mach\Profiles\<your profile>\Macros\.
Create a new plain-text file named exactly m500.mcs (all lowercase; not M500.txt, not m500.mcs.txt - Windows sometimes hides the extension, so double-check).
Paste this in, exactly as shown, and save:
Code: [Select]
function m500(hVars, GcodeComment)
    return m.InvokeMacro('m500', hVars, GcodeComment)
end

if (mc.mcInEditor() == 1) then
    m500()
end
You never need to edit this file again. It simply says: "When M500 runs, go find my instructions in UserMCodeModule."

If someday you add M501, M502, etc., each gets its own copy of this file with only the number changed (m501.mcs containing function m501(...) / m.InvokeMacro('m501', ...)).

Step 2: Create the brain; UserMCodeModule.mcs
Open the folder Mach\Profiles\<your profile>\Macros\Scripts\.

Check whether UserMCodeModule.mcs already exists:

If it exists: open it in a text editor (or the Mach script editor) and skip to step 4 - you'll just add to it.
If it does not exist: create it and paste in the starter template below.
Starter template for a brand-new UserMCodeModule.mcs:
Code: [Select]
local UserMCodeModule = {}

-- Custom MCode functions go here (Step 4).

return UserMCodeModule
Now write what M500 should do. Add this function inside the file (between the two lines of the starter template):
Code: [Select]
function UserMCodeModule.m500(hVars)
    ------------------ Your instructions go below this line ------------------

    -- Example: turn OUTPUT #4 on.
    local hReg, rc = mc.mcRegGetHandle(inst, "mc.OSIG_OUTPUT4")
    if rc == mc.MERROR_NOERROR then
        mc.mcRegSetValue(hReg, 1)
    end

    ------------------ Don't edit below this line ------------------
    return true, true, w.FunctionCompleted()
end

What the parts mean:

function UserMCodeModule.m500(hVars); the name must match the MCode: m500 for M500, m501 for M501, and so on. This is how the doorbell finds the right instructions.
The middle is where you put your actual machine logic: turn outputs on/off, wait for inputs, jog an axis, write to registers, show a message, anything the Mach scripting API can do.
return true, true, w.FunctionCompleted(); the standard "I finished successfully" sign-off. Leave it as the last line.

If something can go wrong, report it like this instead of the success line:
Code: [Select]
    return nil, false, "M500 failed: vacuum sensor never turned on"Returning false as the second value stops the program and shows your message to the operator as an alarm, which is exactly what you want when a safety check fails.
Save the file.

Step 3: Try it
Restart Mach (or reload the screen script) so it picks up the new files.
Go to the MDI line, type M500, and press Enter.
Your instructions run. In the example above, output #4 turns on.
If nothing happens
Check these in order:
  • m500.mcs exists in Profiles<your profile>\Macros\ -  spelled exactly, lowercase, with the .mcs extension, not .txt. This is the most common mistake. Without the doorbell file, the brain never gets called.
  • The function inside UserMCodeModule is named m500 exactly; lowercase m, matching the number.
  • UserMCodeModule.mcs starts with local UserMCodeModule = {} and ends with return UserMCodeModule.
  • You restarted Mach or compiled scripts after saving.
  • You edited the files in the profile you are actually running, not a different profile's folder.

Optional extras (when you're comfortable)
Code: [Select]
Passing a value to your MCode. You can write M500 P1 in a program and read the P value inside your function:
function UserMCodeModule.m500(hVars)
    local pValue, ok, errMsg = m.GetMCodeLocalVar(hVars, mc.SV_P)
    if ok ~= true then
        pValue = 0   -- P word wasn't given; use a default
    end
    -- ... use pValue to decide what to do ...
    return true, true, w.FunctionCompleted()
end

Safety lockout. If M500 must not run unless a guard is closed, check that input first and return nil, false, "message" to abort with an alarm before doing anything else.

Where the GUI module fits. You may also have a UserGUIModule.mcs file in the same Scripts folder. That file is for screen behavior (buttons, the PLC script, LEDs) - not MCodes. MCode logic always belongs in UserMCodeModule.mcs. If your M500 needs something visible on screen (like an indicator), the screen part goes in UserGUIModule and the machine action stays in UserMCodeModule.

How to modify an existing MCode

First: The Golden Rule
Never edit the stock macro files. Every built-in MCode (M3, M5, M6, M8, M30, …) already has a file in Mach\Profiles\<your profile>\Macros\ - like m3.mcs - plus built-in logic inside Mach's modules. Do not edit those files, and do not edit Mach's modules. Why:

Updates will overwrite your changes. When MachPro software is updated, stock files get replaced and your edits silently vanish.
You don't need to. Mach has a built-in extension system - called hooks - designed exactly for this. Your changes go in your file: UserMCodeModule.mcs in Mach\Profiles\<your profile>\Macros\Scripts\. That file is yours; updates never touch it.

The Big Picture: Hooks
Every built-in MCode runs its job in stages, and at specific points it pauses and asks: "Does the user have anything to say about this?" Those asking-points are hooks. For example, when M3 (spindle forward) runs, it asks at these moments, in this order:
Code: [Select]
M3 starts
  → hook "m3"        (before anything happens)
  → the built-in job (start the spindle)
  → hook "m3End"     (after the job finished)

If you wrote a function named UserMCodeModule.m3 in your UserMCodeModule.mcs file, it gets called at that first hook point. If you wrote UserMCodeModule.m3End, it gets called at the second. If you wrote neither, Mach shrugs and carries on; hooks are purely optional.

Most MCodes follow this pattern: a hook named after the code (m3, m8, m6…) that runs before the built-in job, and an …End hook (m3End, m8End, m6End…) that runs after it.

Your Two Choices:
When a hook is called, your function answers one question: should the built-in job still run? Your answer is the first value you return:

Your first return value   What happensUse this to…
return true, true, ...Built-in job runs normallyAdd behavior before/after the stock job (log it, turn on an extra output, check a condition)
return false, true, ...Built-in job is skippedReplace the stock behavior entirely with your own
return nil, false, "message"Everything stops, operator sees your message     as an alarmBlock the MCode when a safety condition fails

Recipe 1: Add something before the stock job (most common)
Example: you want M3 to also turn on a "spindle running" lamp (output #5).

Open Mach\Profiles\<your profile>\Macros\Scripts\UserMCodeModule.mcs.
If it doesn't exist, create it with this starter:

Code: [Select]
local UserMCodeModule = {}

return UserMCodeModule

Add a function named after the MCode; this runs before the spindle starts:

Code: [Select]
function UserMCodeModule.m3(hVars)
    -- Turn on the spindle lamp.
    local hReg, rc = mc.mcRegGetHandle(inst, "mc.OSIG_OUTPUT5")
    if rc == mc.MERROR_NOERROR then
        mc.mcRegSetValue(hReg, 1)
    end

    return true, true, w.FunctionCompleted()   -- "true" = now run the normal M3 job
end

Save and select "Compile Scripts". In rare cases, you will need to restart Mach. Now every M3 - from a program, MDI, or a screen button - lights the lamp first, then starts the spindle as usual.

Recipe 2: Add something after the stock job
Use the …End hook instead. Example: after M5 (spindle stop) finishes, turn the lamp off:
Code: [Select]
function UserMCodeModule.m5End(hVars)
    local hReg, rc = mc.mcRegGetHandle(inst, "mc.OSIG_OUTPUT5")
    if rc == mc.MERROR_NOERROR then
        mc.mcRegSetValue(hReg, 0)
    end

    return true, true, w.FunctionCompleted()
end

Recipe 3: Block the MCode when a condition isn't met

Example: don't allow M3 unless the guard door is closed (input #2).

Code: [Select]
function UserMCodeModule.m3(hVars)
    local hReg, rc = mc.mcRegGetHandle(inst, "mc.ISIG_INPUT2")
    if rc == mc.MERROR_NOERROR then
        local doorClosed = mc.mcRegGetValue(hReg)
        if doorClosed ~= 1 then
            return nil, false, "M3 refused: guard door is open"
        end
    end

    return true, true, w.FunctionCompleted()
end

Returning false as the second value aborts the whole MCode and shows your message to the operator. Nothing else runs; the spindle never starts.

Recipe 4: Replace the stock behavior entirely

Return false as the first value. Mach skips its built-in job and considers the MCode done.

Example: your machine has no physical spindle relay; M3 should only set a register for your VFD over Modbus, and never run the stock spindle logic:
Code: [Select]
function UserMCodeModule.m3(hVars)
    -- My own spindle-start logic here (VFD register writes, etc.)
    -- ...

    return false, true, w.FunctionCompleted()   -- "false" = skip Mach's built-in M3 job
end
Be careful with this one. The stock job often does bookkeeping you can't see (state tracking, status displays). Replacing M6 (tool change) or M30 (end of program) this way, for instance, can leave the control's idea of "what's happening" out of sync. Prefer Recipes 1–3 unless you're sure.

Which hook names exist?
m<code>  runs before the built-in job: m3, m4, m5, m6, m8, m9, m30, …
m<code>End  runs after the built-in job: m3End, m5End, …
Some complex operations have extra named hooks; tool change, for example, offers PreMainToolChangeCycle and PostMainToolChangeCycle.
If you're not sure which hooks a particular MCode supports, look at that MCode's Default file (read-only!) in Mach\Profiles\<your profile>\Macros\ and search Mach's modules for RunHooks("…  every name found there is a hook you can use. You can also search in:
https://support.machmotion.com/docs/current/dir_f2541a3b18981391fa76fac5599e978a.html

Testing and Troubleshooting
Select "Compile Scripts" or restart Mach - hooks are loaded at startup.
Trigger the MCode from the MDI line.
If your hook doesn't seem to run, check:
  • The file is UserMCodeModule.mcs, in Macros\Scripts\ of the profile you're actually running.
  • The file starts with local UserMCodeModule = {} and ends with return UserMCodeModule.
  • The function name matches the hook exactly: UserMCodeModule.m3 (lowercase "m", correct number) or UserMCodeModule.m3End.
  • You restarted Mach or compiled after saving.

Quick reference
You want to…Hook nameReturn
Add before stock job     UserMCodeModule.m3     true, true, w.FunctionCompleted()
Add after stock jobUserMCodeModule.m3End     true, true, w.FunctionCompleted()
Block with alarmUserMCodeModule.m3nil, false, "message"
Replace stock jobUserMCodeModule.m3false, true, w.FunctionCompleted()
Pages: « 1 2 3 4 5 6 7 8 9 10 »