UNPKG

solidworks-mcp-server

Version:

Clean Architecture SolidWorks MCP Server - Production-ready with SOLID principles

654 lines (612 loc) 26.4 kB
/** * Native Macro Recording for SolidWorks * Uses SolidWorks' built-in macro recording API for proper VBA initialization */ import { z } from 'zod'; /** * Native macro recording tools that use SolidWorks' internal VBA engine */ export const nativeMacroTools = [ // ============================================ // NATIVE MACRO RECORDING // ============================================ { name: 'start_native_macro_recording', description: 'Start recording a macro using SolidWorks native VBA recorder', inputSchema: z.object({ macroPath: z.string().describe('Full path where the macro will be saved (e.g., C:\\Macros\\MyMacro.swp)'), pauseRecording: z.boolean().default(false).describe('Start in paused state'), recordViewCommands: z.boolean().default(false).describe('Record view manipulation commands'), recordFeatureManager: z.boolean().default(true).describe('Record feature manager commands'), recordSelections: z.boolean().default(true).describe('Record selection commands') }), handler: (args, swApi) => { try { const swApp = swApi.getApp(); if (!swApp) throw new Error('SolidWorks application not connected'); // Ensure macro path has correct extension let macroPath = args.macroPath; if (!macroPath.toLowerCase().endsWith('.swp')) { macroPath = macroPath.replace(/\.[^.]*$/, '') + '.swp'; } // Ensure directory exists const path = require('path'); const fs = require('fs'); const dir = path.dirname(macroPath); if (!fs.existsSync(dir)) { fs.mkdirSync(dir, { recursive: true }); } // Set recording options swApp.SetUserPreferenceToggle(197, args.recordViewCommands); // swUserPreferenceToggle_e.swMacroRecordViewManipulation swApp.SetUserPreferenceToggle(198, args.recordFeatureManager); // swUserPreferenceToggle_e.swMacroRecordFeatureManager swApp.SetUserPreferenceToggle(199, args.recordSelections); // swUserPreferenceToggle_e.swMacroRecordSelections // Start recording using native SolidWorks API // This creates a proper VBA project with all necessary references const success = swApp.RecordMacro(macroPath); if (!success) { throw new Error('Failed to start macro recording'); } // Pause if requested if (args.pauseRecording) { swApp.PauseMacroRecording(); } return { success: true, message: 'Native macro recording started', macroPath, status: args.pauseRecording ? 'paused' : 'recording', options: { recordViewCommands: args.recordViewCommands, recordFeatureManager: args.recordFeatureManager, recordSelections: args.recordSelections } }; } catch (error) { return `Failed to start native macro recording: ${error}`; } } }, { name: 'stop_native_macro_recording', description: 'Stop the current native macro recording and save', inputSchema: z.object({ openInEditor: z.boolean().default(false).describe('Open macro in VBA editor after saving'), runMacro: z.boolean().default(false).describe('Run the macro immediately after saving') }), handler: (args, swApi) => { try { const swApp = swApi.getApp(); if (!swApp) throw new Error('SolidWorks application not connected'); // Stop recording - this properly saves the macro with all VBA initialization swApp.StopMacroRecording(); // Get the last recorded macro path const lastMacroPath = swApp.GetUserPreferenceStringValue(69); // swUserPreferenceStringValue_e.swFileLocationsMacros // Open in editor if requested if (args.openInEditor) { swApp.EditMacro(lastMacroPath); } // Run macro if requested if (args.runMacro) { swApp.RunMacro2(lastMacroPath, "main", // Default module name "main", // Default procedure name 1 // swRunMacroOption_e.swRunMacroUnloadAfterRun ); } return { success: true, message: 'Native macro recording stopped and saved', macroPath: lastMacroPath, openedInEditor: args.openInEditor, executed: args.runMacro }; } catch (error) { return `Failed to stop native macro recording: ${error}`; } } }, { name: 'pause_resume_macro_recording', description: 'Pause or resume the current macro recording', inputSchema: z.object({ action: z.enum(['pause', 'resume']).describe('Action to perform') }), handler: (args, swApi) => { try { const swApp = swApi.getApp(); if (!swApp) throw new Error('SolidWorks application not connected'); if (args.action === 'pause') { swApp.PauseMacroRecording(); } else { swApp.ResumeMacroRecording(); } return { success: true, message: `Macro recording ${args.action}d`, status: args.action === 'pause' ? 'paused' : 'recording' }; } catch (error) { return `Failed to ${args.action} macro recording: ${error}`; } } }, // ============================================ // MACRO EXECUTION & MANAGEMENT // ============================================ { name: 'run_macro', description: 'Run a SolidWorks macro file', inputSchema: z.object({ macroPath: z.string().describe('Full path to the macro file (.swp or .swb)'), moduleName: z.string().default('main').describe('Module name containing the macro'), procedureName: z.string().default('main').describe('Procedure/subroutine name to run'), arguments: z.array(z.any()).optional().describe('Arguments to pass to the macro'), unloadAfterRun: z.boolean().default(true).describe('Unload macro from memory after execution') }), handler: (args, swApi) => { try { const swApp = swApi.getApp(); if (!swApp) throw new Error('SolidWorks application not connected'); // Check if macro file exists const fs = require('fs'); if (!fs.existsSync(args.macroPath)) { throw new Error(`Macro file not found: ${args.macroPath}`); } // Determine run option const runOption = args.unloadAfterRun ? 1 : 0; // swRunMacroOption_e // Run the macro let success; if (args.arguments && args.arguments.length > 0) { // Run with arguments (requires special handling) const vbaApp = swApp.GetAddInObject("SldWorks.MacroRunner"); success = vbaApp.RunMacroWithArguments(args.macroPath, args.moduleName, args.procedureName, args.arguments); } else { // Run without arguments success = swApp.RunMacro2(args.macroPath, args.moduleName, args.procedureName, runOption); } if (!success) { throw new Error('Macro execution failed'); } return { success: true, message: 'Macro executed successfully', macroPath: args.macroPath, module: args.moduleName, procedure: args.procedureName, hadArguments: args.arguments ? args.arguments.length : 0 }; } catch (error) { return `Failed to run macro: ${error}`; } } }, { name: 'edit_macro', description: 'Open a macro in the SolidWorks VBA editor', inputSchema: z.object({ macroPath: z.string().describe('Full path to the macro file') }), handler: (args, swApi) => { try { const swApp = swApi.getApp(); if (!swApp) throw new Error('SolidWorks application not connected'); // Check if macro file exists const fs = require('fs'); if (!fs.existsSync(args.macroPath)) { throw new Error(`Macro file not found: ${args.macroPath}`); } // Open in VBA editor const success = swApp.EditMacro(args.macroPath); if (!success) { throw new Error('Failed to open macro in editor'); } return { success: true, message: 'Macro opened in VBA editor', macroPath: args.macroPath }; } catch (error) { return `Failed to edit macro: ${error}`; } } }, // ============================================ // MACRO INITIALIZATION & CONVERSION // ============================================ { name: 'create_initialized_macro', description: 'Create a new macro with proper SolidWorks VBA initialization', inputSchema: z.object({ macroPath: z.string().describe('Path where the macro will be saved'), macroName: z.string().describe('Name of the macro'), description: z.string().optional().describe('Macro description'), includeErrorHandling: z.boolean().default(true).describe('Include error handling code'), includeComments: z.boolean().default(true).describe('Include helpful comments'), template: z.enum(['basic', 'part', 'assembly', 'drawing']).default('basic').describe('Macro template type') }), handler: (args, swApi) => { try { const swApp = swApi.getApp(); if (!swApp) throw new Error('SolidWorks application not connected'); // Ensure macro path has correct extension let macroPath = args.macroPath; if (!macroPath.toLowerCase().endsWith('.swp')) { macroPath = macroPath.replace(/\.[^.]*$/, '') + '.swp'; } // Create directory if needed const path = require('path'); const fs = require('fs'); const dir = path.dirname(macroPath); if (!fs.existsSync(dir)) { fs.mkdirSync(dir, { recursive: true }); } // Start recording to create proper VBA project swApp.RecordMacro(macroPath); // Immediately stop to get the initialized project swApp.StopMacroRecording(); // Now edit the macro to add our template code swApp.EditMacro(macroPath); // Get VBA environment const vbaEditor = swApp.GetAddInObject("VBA.Editor"); const vbaProject = vbaEditor.ActiveVBProject; const codeModule = vbaProject.VBComponents("Module1").CodeModule; // Clear existing code if (codeModule.CountOfLines > 0) { codeModule.DeleteLines(1, codeModule.CountOfLines); } // Build template code based on type let templateCode = generateMacroTemplate(args); // Insert the template code codeModule.InsertLines(1, templateCode); // Save the macro vbaProject.Save(); return { success: true, message: 'Initialized macro created successfully', macroPath, macroName: args.macroName, template: args.template, linesOfCode: templateCode.split('\n').length }; } catch (error) { return `Failed to create initialized macro: ${error}`; } } }, { name: 'convert_text_to_native_macro', description: 'Convert plain text VBA code to a properly initialized SolidWorks macro', inputSchema: z.object({ vbaCode: z.string().describe('Plain text VBA code to convert'), outputPath: z.string().describe('Path where the converted macro will be saved'), macroName: z.string().describe('Name for the macro'), addInitialization: z.boolean().default(true).describe('Add SolidWorks initialization code'), addReferences: z.boolean().default(true).describe('Add required type library references') }), handler: (args, swApi) => { try { const swApp = swApi.getApp(); if (!swApp) throw new Error('SolidWorks application not connected'); // Ensure output path has correct extension let outputPath = args.outputPath; if (!outputPath.toLowerCase().endsWith('.swp')) { outputPath = outputPath.replace(/\.[^.]*$/, '') + '.swp'; } // Create an initialized macro first swApp.RecordMacro(outputPath); swApp.StopMacroRecording(); // Open in editor swApp.EditMacro(outputPath); // Get VBA environment const vbaEditor = swApp.GetAddInObject("VBA.Editor"); const vbaProject = vbaEditor.ActiveVBProject; // Add required references if needed if (args.addReferences) { const references = vbaProject.References; // Add SolidWorks type libraries if not present const requiredRefs = [ "SldWorks 2024 Type Library", "SldWorks 2024 Constant type library", "SldWorks 2024 Commands type library" ]; for (const refName of requiredRefs) { try { references.AddFromGuid(getSolidWorksTypeLibGuid(refName), 0, 0); } catch { // Reference might already exist } } } // Get the code module const codeModule = vbaProject.VBComponents("Module1").CodeModule; // Clear existing code if (codeModule.CountOfLines > 0) { codeModule.DeleteLines(1, codeModule.CountOfLines); } // Process the VBA code let processedCode = args.vbaCode; // Add initialization if needed if (args.addInitialization && !processedCode.includes('Dim swApp')) { const initCode = ` ' ${args.macroName} ' Converted from text VBA by SolidWorks MCP Server ' Date: ${new Date().toISOString()} Option Explicit ' SolidWorks Variables Dim swApp As SldWorks.SldWorks Dim swModel As SldWorks.ModelDoc2 Dim swPart As SldWorks.PartDoc Dim swAssembly As SldWorks.AssemblyDoc Dim swDrawing As SldWorks.DrawingDoc Dim boolStatus As Boolean Dim longStatus As Long, longWarnings As Long `; processedCode = initCode + processedCode; } // Ensure main subroutine exists if (!processedCode.includes('Sub main')) { processedCode = processedCode + ` Sub main() Set swApp = Application.SldWorks Set swModel = swApp.ActiveDoc If swModel Is Nothing Then MsgBox "Please open a document first." Exit Sub End If ' Call your main procedure here ${args.macroName} End Sub`; } // Insert the processed code codeModule.InsertLines(1, processedCode); // Save the macro vbaProject.Save(); return { success: true, message: 'VBA code converted to native macro successfully', outputPath, macroName: args.macroName, linesOfCode: processedCode.split('\n').length, referencesAdded: args.addReferences, initializationAdded: args.addInitialization }; } catch (error) { return `Failed to convert text to native macro: ${error}`; } } }, // ============================================ // MACRO BATCH OPERATIONS // ============================================ { name: 'batch_run_macros', description: 'Run multiple macros in sequence', inputSchema: z.object({ macros: z.array(z.object({ path: z.string().describe('Macro file path'), module: z.string().default('main').describe('Module name'), procedure: z.string().default('main').describe('Procedure name'), arguments: z.array(z.any()).optional().describe('Arguments'), continueOnError: z.boolean().default(true).describe('Continue if this macro fails') })).describe('Array of macros to run'), delayBetween: z.number().default(1000).describe('Delay between macros in milliseconds'), stopOnError: z.boolean().default(false).describe('Stop batch if any macro fails') }), handler: async (args, swApi) => { try { const swApp = swApi.getApp(); if (!swApp) throw new Error('SolidWorks application not connected'); const results = { total: args.macros.length, successful: 0, failed: 0, skipped: 0, details: [] }; for (let i = 0; i < args.macros.length; i++) { const macro = args.macros[i]; const result = { index: i, path: macro.path, status: 'pending', message: '', startTime: new Date().toISOString() }; try { // Check if file exists const fs = require('fs'); if (!fs.existsSync(macro.path)) { throw new Error('Macro file not found'); } // Run the macro const success = swApp.RunMacro2(macro.path, macro.module, macro.procedure, 1 // Unload after run ); if (!success) { throw new Error('Macro execution failed'); } result.status = 'success'; result.message = 'Macro executed successfully'; results.successful++; } catch (error) { result.status = 'failed'; result.message = String(error); results.failed++; if (args.stopOnError && !macro.continueOnError) { results.skipped = args.macros.length - i - 1; results.details.push(result); break; } } result.endTime = new Date().toISOString(); results.details.push(result); // Delay between macros if (i < args.macros.length - 1) { await new Promise(resolve => setTimeout(resolve, args.delayBetween)); } } return { success: results.failed === 0, message: `Batch execution completed: ${results.successful}/${results.total} successful`, results }; } catch (error) { return `Failed to run batch macros: ${error}`; } } } ]; // Helper function to generate macro templates function generateMacroTemplate(args) { const templates = { basic: ` ' Macro: ${args.macroName} ' Description: ${args.description || 'Basic SolidWorks macro'} ' Created: ${new Date().toISOString()} ' Generated by SolidWorks MCP Server Option Explicit ' SolidWorks Variables Dim swApp As SldWorks.SldWorks Dim swModel As SldWorks.ModelDoc2 Dim boolStatus As Boolean Dim longStatus As Long, longWarnings As Long Sub main() ${args.includeErrorHandling ? ' On Error GoTo ErrorHandler' : ''} ' Get SolidWorks application Set swApp = Application.SldWorks ' Get active document Set swModel = swApp.ActiveDoc ' Check if document is open If swModel Is Nothing Then MsgBox "Please open a document first." Exit Sub End If ${args.includeComments ? "' Your code here" : ''} MsgBox "Macro completed successfully!" ${args.includeErrorHandling ? `ErrorHandler: If Err.Number <> 0 Then MsgBox "Error " & Err.Number & ": " & Err.Description End If` : ''} End Sub`, part: ` ' Macro: ${args.macroName} ' Description: ${args.description || 'Part-specific SolidWorks macro'} ' Created: ${new Date().toISOString()} Option Explicit Dim swApp As SldWorks.SldWorks Dim swModel As SldWorks.ModelDoc2 Dim swPart As SldWorks.PartDoc Dim swFeature As SldWorks.Feature Dim swFeatMgr As SldWorks.FeatureManager Sub main() ${args.includeErrorHandling ? ' On Error GoTo ErrorHandler' : ''} Set swApp = Application.SldWorks Set swModel = swApp.ActiveDoc ' Verify this is a part document If swModel Is Nothing Then MsgBox "Please open a part document." Exit Sub End If If swModel.GetType <> swDocPART Then MsgBox "This macro only works with part documents." Exit Sub End If Set swPart = swModel Set swFeatMgr = swModel.FeatureManager ${args.includeComments ? "' Part-specific operations here" : ''} ${args.includeErrorHandling ? `ErrorHandler: If Err.Number <> 0 Then MsgBox "Error " & Err.Number & ": " & Err.Description End If` : ''} End Sub`, assembly: ` ' Macro: ${args.macroName} ' Description: ${args.description || 'Assembly-specific SolidWorks macro'} ' Created: ${new Date().toISOString()} Option Explicit Dim swApp As SldWorks.SldWorks Dim swModel As SldWorks.ModelDoc2 Dim swAssembly As SldWorks.AssemblyDoc Dim swComp As SldWorks.Component2 Sub main() ${args.includeErrorHandling ? ' On Error GoTo ErrorHandler' : ''} Set swApp = Application.SldWorks Set swModel = swApp.ActiveDoc ' Verify this is an assembly document If swModel Is Nothing Then MsgBox "Please open an assembly document." Exit Sub End If If swModel.GetType <> swDocASSEMBLY Then MsgBox "This macro only works with assembly documents." Exit Sub End If Set swAssembly = swModel ${args.includeComments ? "' Assembly-specific operations here" : ''} ${args.includeErrorHandling ? `ErrorHandler: If Err.Number <> 0 Then MsgBox "Error " & Err.Number & ": " & Err.Description End If` : ''} End Sub`, drawing: ` ' Macro: ${args.macroName} ' Description: ${args.description || 'Drawing-specific SolidWorks macro'} ' Created: ${new Date().toISOString()} Option Explicit Dim swApp As SldWorks.SldWorks Dim swModel As SldWorks.ModelDoc2 Dim swDrawing As SldWorks.DrawingDoc Dim swSheet As SldWorks.Sheet Dim swView As SldWorks.View Sub main() ${args.includeErrorHandling ? ' On Error GoTo ErrorHandler' : ''} Set swApp = Application.SldWorks Set swModel = swApp.ActiveDoc ' Verify this is a drawing document If swModel Is Nothing Then MsgBox "Please open a drawing document." Exit Sub End If If swModel.GetType <> swDocDRAWING Then MsgBox "This macro only works with drawing documents." Exit Sub End If Set swDrawing = swModel Set swSheet = swDrawing.GetCurrentSheet ${args.includeComments ? "' Drawing-specific operations here" : ''} ${args.includeErrorHandling ? `ErrorHandler: If Err.Number <> 0 Then MsgBox "Error " & Err.Number & ": " & Err.Description End If` : ''} End Sub` }; return templates[args.template] || templates.basic; } // Helper function to get SolidWorks type library GUIDs function getSolidWorksTypeLibGuid(libName) { const guids = { "SldWorks 2024 Type Library": "{83A33D31-27C5-11CE-BFD4-00400513BB57}", "SldWorks 2024 Constant type library": "{4687F359-55D0-4CD3-B6CF-2EB42C11F989}", "SldWorks 2024 Commands type library": "{0AC0837E-7365-48E8-9651-A141AAB75963}" }; return guids[libName] || ""; } //# sourceMappingURL=native-macro.js.map