I've been using Grok and realized that it often tries to use classes or commands that aren't valid, which led me astray for a while. I would paste the resulting error messages back into Grok, and it would respond with suggestions like missing reference files or a corrupt installation—none of which were actually the problem.
Eventually, I figured out the root issue and started looking for a way to "teach" Grok which classes, structures, and methods are actually valid within the various namespaces. AI suggested I use "reflection" to do that and it wrote the code for it - which produced a JSON file for each DLL associated with the Civil 3D Namespaces.
I'm still using Grok 3, since I haven’t upgraded to version 4 yet. Sometimes it reads the JSON files correctly, but other times it either truncates them or claims to have read them but produces inconsistent results. Hopefully version 4 handles JSON more reliably.
When it *does* work, it's incredibly helpful. The AI realizes it's using an invalid command, searches for a valid one in the JSON, and rewrites the .cs code accordingly. I have one DLL with 600 lines of C# code to map custom properties to storm structures for various purposes—something I never could have written from scratch on my own. I originally made one JSON file with all of the DLLs but it was 122MB in size and too large for AI uploading... so I made one JSON for each of the important DLL files.
Having the reflected JSON files for the various DLL files (accoremgd, acbdmgd, acmgd, AecBaseMgd, AeccDbMgd, and AecPropDataMgd) has been key to keeping AI on track with valid C# code generation. I would upload these files to the forum, but it's currently blocking .json file uploads.
Here's the .cs code for JSON reflection if you want it. One created, just run NETLOAD to load it and ExtractDllInfoToJson to run it. Should produce JSON files up to about 5MB in size.
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.EditorInput;
using System.Reflection;
using System.IO;
using System;
using System.Linq;
using System.Collections.Generic;
using System.Windows.Forms; // For FolderBrowserDialog
using Newtonsoft.Json;
public class DllInfo
{
public string Name { get; set; }
public string Version { get; set; }
public string FullName { get; set; }
public List<TypeInfo> Types { get; set; }
}
public class TypeInfo
{
public string Name { get; set; }
public bool IsPublic { get; set; }
public List<MethodInfo> Methods { get; set; }
public List<PropertyInfo> Properties { get; set; }
}
public class MethodInfo
{
public string Name { get; set; }
public string ReturnType { get; set; }
public List<string> Parameters { get; set; }
}
public class PropertyInfo
{
public string Name { get; set; }
public string Type { get; set; }
}
public class Commands
{
[CommandMethod("ExtractDllInfoToJson")]
public void ExtractDllInfoToJson()
{
var doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
var ed = doc.Editor;
try
{
// Prompt for DLL file
PromptOpenFileOptions dllPrompt = new PromptOpenFileOptions("\nSelect DLL file to process")
{
Filter = "DLL files (*.dll)|*.dll|All Files (*.*)|*.*",
DialogCaption = "Select DLL File"
};
PromptFileNameResult dllResult = ed.GetFileNameForOpen(dllPrompt);
if (dllResult.Status != PromptStatus.OK)
{
ed.WriteMessage("\nDLL selection cancelled.");
return;
}
string dllPath = dllResult.StringResult;
// Prompt for output folder using FolderBrowserDialog
string outputPath; // Declare outputPath here to ensure scope
using (FolderBrowserDialog folderDialog = new FolderBrowserDialog())
{
folderDialog.Description = "Select Output Folder for JSON File";
folderDialog.SelectedPath = @"C:\Users\MarkMcGuire\Desktop";
folderDialog.ShowNewFolderButton = true;
DialogResult result = folderDialog.ShowDialog();
if (result != DialogResult.OK)
{
ed.WriteMessage("\nOutput folder selection cancelled.");
return;
}
outputPath = folderDialog.SelectedPath;
}
// Ensure output directory exists
if (!Directory.Exists(outputPath))
{
try
{
Directory.CreateDirectory(outputPath);
ed.WriteMessage($"\nCreated output directory: {outputPath}");
}
catch (System.Exception ex)
{
ed.WriteMessage($"\nError creating output directory {outputPath}: {ex.Message}");
return;
}
}
// Define paths for dependency resolution
string civil3dPath = @"C:\Program Files\Autodesk\AutoCAD 2024\";
string civil3dC3DPath = @"C:\Program Files\Autodesk\AutoCAD 2024\C3D\";
string netFrameworkPath = @"C:\Windows\Microsoft.NET\Framework64\v4.0.30319\";
string netAssemblyPath = @"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\";
string programFilesPath = @"C:\Program Files (x86)\Microsoft SDKs\Expression\Blend\.NETFramework\v4.5\";
// Set up dependency resolution
AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve += (sender, args) =>
{
string assemblyName = new AssemblyName(args.Name).Name;
// Check Civil 3D-specific folder
string assemblyPath = Path.Combine(civil3dC3DPath, assemblyName + ".dll");
if (File.Exists(assemblyPath))
{
ed.WriteMessage($"\nResolved dependency: {assemblyPath}");
return Assembly.ReflectionOnlyLoadFrom(assemblyPath);
}
// Check main AutoCAD folder
assemblyPath = Path.Combine(civil3dPath, assemblyName + ".dll");
if (File.Exists(assemblyPath))
{
ed.WriteMessage($"\nResolved dependency: {assemblyPath}");
return Assembly.ReflectionOnlyLoadFrom(assemblyPath);
}
// Check .NET Framework folder
assemblyPath = Path.Combine(netFrameworkPath, assemblyName + ".dll");
if (File.Exists(assemblyPath))
{
ed.WriteMessage($"\nResolved dependency: {assemblyPath}");
return Assembly.ReflectionOnlyLoadFrom(assemblyPath);
}
// Check .NET Reference Assemblies
assemblyPath = Path.Combine(netAssemblyPath, assemblyName + ".dll");
if (File.Exists(assemblyPath))
{
ed.WriteMessage($"\nResolved dependency: {assemblyPath}");
return Assembly.ReflectionOnlyLoadFrom(assemblyPath);
}
// Check Microsoft SDKs for System.Windows.Interactivity
assemblyPath = Path.Combine(programFilesPath, assemblyName + ".dll");
if (File.Exists(assemblyPath))
{
ed.WriteMessage($"\nResolved dependency: {assemblyPath}");
return Assembly.ReflectionOnlyLoadFrom(assemblyPath);
}
try
{
return Assembly.ReflectionOnlyLoad(args.Name);
}
catch (System.Exception ex)
{
ed.WriteMessage($"\nFailed to resolve dependency {assemblyName}: {ex.Message}");
return null;
}
};
// Process the selected DLL
ed.WriteMessage($"\nProcessing DLL: {dllPath}");
Assembly assembly = Assembly.ReflectionOnlyLoadFrom(dllPath);
var assemblyInfo = new DllInfo
{
Name = assembly.GetName().Name,
Version = assembly.GetName().Version.ToString(),
FullName = assembly.GetName().FullName,
Types = new List<TypeInfo>()
};
int totalTypes = 0;
int includedTypes = 0;
try
{
foreach (Type type in assembly.GetTypes())
{
totalTypes++;
try
{
if (!type.FullName.StartsWith("Autodesk.AutoCAD.") &&
!type.FullName.StartsWith("Autodesk.Aec.") &&
!type.FullName.StartsWith("Autodesk.Civil."))
continue;
if (!type.IsPublic)
continue;
includedTypes++;
var typeInfo = new TypeInfo
{
Name = type.FullName,
IsPublic = type.IsPublic,
Methods = new List<MethodInfo>(),
Properties = new List<PropertyInfo>()
};
foreach (var method in type.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly))
{
try
{
var methodInfo = new MethodInfo
{
Name = method.Name,
ReturnType = method.ReturnType.FullName,
Parameters = method.GetParameters().Select(p => p.ParameterType.FullName + " " + p.Name).ToList()
};
typeInfo.Methods.Add(methodInfo);
}
catch (System.Exception ex)
{
ed.WriteMessage($"\nError processing method {method.Name} in type {type.FullName}: {ex.Message}");
}
}
foreach (var property in type.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly))
{
try
{
var propertyInfo = new PropertyInfo
{
Name = property.Name,
Type = property.PropertyType.FullName
};
typeInfo.Properties.Add(propertyInfo);
}
catch (System.Exception ex)
{
ed.WriteMessage($"\nError processing property {property.Name} in type {type.FullName}: {ex.Message}");
}
}
assemblyInfo.Types.Add(typeInfo);
}
catch (System.Exception ex)
{
ed.WriteMessage($"\nError processing type {type?.FullName}: {ex.Message}");
}
}
}
catch (ReflectionTypeLoadException ex)
{
ed.WriteMessage($"\nError loading types from DLL {dllPath}:");
foreach (var loaderEx in ex.LoaderExceptions)
{
if (loaderEx != null)
ed.WriteMessage($"\n - LoaderException: {loaderEx.Message}");
}
}
catch (System.Exception ex)
{
ed.WriteMessage($"\nError processing DLL {dllPath}: {ex.Message}");
}
ed.WriteMessage($"\nProcessed {totalTypes} total types, included {includedTypes} in {assemblyInfo.Name}");
string json = JsonConvert.SerializeObject(assemblyInfo, Formatting.Indented);
string outputFile = Path.Combine(outputPath, assemblyInfo.Name + ".json");
File.WriteAllText(outputFile, json);
ed.WriteMessage($"\nOutput written to: {outputFile}");
}
catch (System.Exception ex)
{
ed.WriteMessage($"\nGeneral error: {ex.Message}");
}
}
}