Files
wwtools/graccesscli/analysis/ide-edit-investigation/scriptpkg/ScriptPackage.Net.decompiled.cs
Joseph Doherty c52d8d0171 graccesscli: correct script-edit docs to TN-537 truth (writes DO persist)
I was wrong. AVEVA Tech Note 537 ("Creating an Application Object Script
Using GRAccess", April 2008) documents the supported pattern:
ConfigurableAttributes[<script>.<field>].SetValue(MxValue) inside a
CheckOut/Save/CheckIn cycle. graccesscli's existing
FindAttributeForMutation already follows this — writes to MxCategoryPackageOnly_Lockable
script-text fields persist correctly.

The earlier "writeback gap" diagnosis was a phantom caused by a reader-side
issue. `object attribute value get` against a script body returns
"Supported: False / Attribute value is not exposed" because
MxValueDetails uses a case-sensitive `ReadProperty(attr, "Value")` lookup
plus an accessor probe (GetBoolean -> GetInteger -> GetFloat -> GetDouble
-> GetString) that can fall through silently for some MxValue shapes. The
COM-side property is exposed as `value` (lowercase), readable as
`attr.value.GetString()` -- which the live probe at
`analysis/ide-edit-investigation/probe_setvalue/` does and confirms the
post-write content matches the marker exactly.

Live verification on $TestMachine.UpdateTestChangingInt.DeclarationsText
and $DelmiaReceiver.ProcessRecipe.{ExecuteText,DeclarationsText}:

  === verdict ===
    marker landed on same-proxy   ConfigurableAttributes: True
    marker landed on same-proxy   Attributes            : True
    marker landed on fresh-proxy  ConfigurableAttributes: True
    marker landed on fresh-proxy  Attributes            : True

The probe also confirmed that two earlier graccesscli `object scripts set`
invocations (which I had wrongly believed failed) had persisted -- the
marker text I wrote previously was still on disk in
ProcessRecipe.{ExecuteText,DeclarationsText} when read directly via
attr.value.GetString(). The probe restored both fields to their original
values.

This commit:

- Updates the misleading [Command(...)] / [CommandOption(...)]
  descriptions in GRAccessSurfaceCommands.cs back to honest versions
  citing TN-537.
- Restores the --file-using examples for `object scripts set` and
  `object scripts create` across script-editing.md, llm-integration.md,
  usage.md, and zb-testmachine.md.
- Removes the test that asserted the (wrong) EnsureMutableViaSetValue
  guard. Re-aims ScriptCommandDescriptions_… at the corrected wording.
- Removes two leftover EnsureMutableViaSetValue calls in the trigger-period
  / trigger-type write paths (both targeted MxCategoryWriteable_C_Lockable
  attributes; would never have fired even if the helper still existed).
- Adds analysis/ide-edit-investigation/REPORT.md (replacing the earlier
  wrong report) plus the probe sources under probe_setvalue/.

The MxValueDetails reader gap (case-sensitive ReadProperty + accessor
probe) is a real follow-up: `object attribute value get` should
case-insensitively read `value` and try GetString first when the
underlying MxValue.DataType is MxString. Out of scope here -- that's a
separate, smaller fix.

Test count delta: 67 -> 66 (-2 wrong tests, +1 corrected description test).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 21:33:51 -04:00

596 lines
20 KiB
C#

using System;
using System.Collections;
using System.Diagnostics;
using System.Diagnostics.SymbolStore;
using System.IO;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using ArchestrA.QuickScript;
using ArchestrA.QuickScript.Digest;
using ArchestrA.QuickScript.Emit;
using ArchestrA.QuickScript.Model;
using ArchestrA.QuickScript.Runtime;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyFileVersion("5800.0038.7005.1")]
[assembly: AssemblyTitle("ScriptPackage.Net Module")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("AVEVA Software, LLC")]
[assembly: AssemblyProduct("")]
[assembly: AssemblyCopyright("Copyright 2020 AVEVA Group plc and its subsidiaries. All rights reserved.")]
[assembly: AssemblyTrademark("Refer to: https://sw.aveva.com/legal/trademarks")]
[assembly: AssemblyDelaySign(false)]
[assembly: AssemblyKeyFile("..\\..\\..\\SharedComponents\\Internal\\MagellanPublic\\Includes\\WWDotNETPrivateKey\\ww.snk")]
[assembly: AssemblyKeyName("")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("2.0.0.0")]
namespace ArchestrA.Scripting
{
[Guid("85963980-46DF-459d-8A96-2A2AF70F458F")]
[ClassInterface(ClassInterfaceType.AutoDual)]
public class ScriptPackage
{
private class NameHierarchy
{
public Hashtable Hashtable = new Hashtable();
public readonly string Name;
public int Index;
public NameHierarchy(string name)
{
Name = name;
Index = -1;
}
public NameHierarchy()
: this(null)
{
}
public void Add(string name, int index)
{
string text = null;
string text2 = null;
int num = name.IndexOf('.');
if (num < 0)
{
text = name;
}
else
{
text = name.Substring(0, num);
text2 = name.Substring(num + 1, name.Length - num - 1);
}
string key = text.ToLower();
if (!Hashtable.ContainsKey(key))
{
Hashtable[key] = new NameHierarchy(text);
}
NameHierarchy nameHierarchy = (NameHierarchy)Hashtable[key];
if (text2 != null)
{
nameHierarchy.Add(text2, index);
}
else
{
nameHierarchy.Index = index;
}
}
}
private class TypeResolveHandler
{
private Module Module;
private Hashtable Hashtable;
public TypeResolveHandler(Module module, Hashtable hashtable)
{
Module = module;
Hashtable = hashtable;
}
public Assembly ResolveEvent(object sender, ResolveEventArgs args)
{
((TypeBuilder)Hashtable[args.Name]).CreateType();
return Module.Assembly;
}
}
private string BinFolder;
private bool DebugEnabled;
private Parser Parser;
private string TagName;
private string ScriptName;
private Hashtable ReferencedAssemblies;
private ModuleBuilder ModuleBuilder;
private TypeBuilder TypeBuilder;
private ILBuilder ILBuilder;
private int NestedTypeIndex;
private string ErrorMessage;
private int ErrorLine;
private int ErrorColumn;
private static readonly FieldInfo ScriptExchange;
private static readonly Type[] ExpessionParameterTypes;
private static readonly MethodInfo EnableDebugSupport;
private static string DebugFolder => Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "QuickScriptDebug");
private static bool DebuggerInfoEnabled => Directory.Exists(DebugFolder);
public void Compile(string libraryPath, string repositoryPath, string tagName, string scriptName, string compilerAssemblyFile, string compilerTypeName, IntPtr outputAssemblyName, IntPtr aliases, IntPtr declarationsText, IntPtr startupText, IntPtr onScanText, IntPtr expression, IntPtr executeText, IntPtr offScanText, IntPtr shutdownText, IntPtr binary, IntPtr errorMessage, IntPtr errorLine, IntPtr errorColumn, IntPtr libaryDependencies, IntPtr externalReferences, IntPtr externalReferenceFlags, IntPtr aliasReferenceFlags)
{
IList list = null;
byte[] array = null;
ErrorMessage = "";
BinFolder = Path.GetDirectoryName(Assembly.GetAssembly(GetType()).Location);
Parser = new Parser();
ILBuilder = new ILBuilder();
ReferencedAssemblies = new Hashtable();
list = new ArrayList();
TagName = tagName;
ScriptName = scriptName;
DebugEnabled = DebuggerInfoEnabled;
NestedTypeIndex = 0;
int mxValueElementCount = GetMxValueElementCount(aliases);
int i;
for (i = 0; i < mxValueElementCount; i++)
{
ExternalReferences.AddAlias(GetMxValueElementString(aliases, i + 1));
}
try
{
string tempPath = Path.GetTempPath();
AssemblyName assemblyName = new AssemblyName();
assemblyName.Name = GetMxValueString(outputAssemblyName);
string text = assemblyName.Name + ".dll";
Directory.SetCurrentDirectory(AppDomain.CurrentDomain.BaseDirectory);
AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Save, tempPath);
if (DebugEnabled)
{
CustomAttributeBuilder customAttribute = new CustomAttributeBuilder(typeof(DebuggableAttribute).GetConstructor(new Type[2]
{
typeof(bool),
typeof(bool)
}), new object[2] { true, true });
assemblyBuilder.SetCustomAttribute(customAttribute);
}
ModuleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName.Name, text, DebugEnabled);
TypeBuilder = ModuleBuilder.DefineType("ArchestrA.Scripting.Script", TypeAttributes.Public, typeof(ScriptBase), new Type[0]);
ILGenerator iLGenerator = TypeBuilder.DefineConstructor(MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName, CallingConventions.Standard, new Type[0]).GetILGenerator();
ILBuilder.ILGenerator = iLGenerator;
iLGenerator.Emit(OpCodes.Ldarg_0);
iLGenerator.Emit(OpCodes.Call, typeof(ScriptBase).GetConstructor(new Type[0]));
ILBuilder.DebugEnabled = false;
ILBuilder.FieldScriptExchange = ScriptExchange;
CompileDeclarations(GetMxValueString(declarationsText));
ILBuilder.Emit(new Return());
if (ErrorMessage.Length == 0 || ErrorMessage.StartsWith("Warning"))
{
CompileExpression(GetMxValueString(expression));
CompileMethod("Startup", GetMxValueString(startupText));
CompileMethod("OnScan", GetMxValueString(onScanText));
CompileMethod("Execute", GetMxValueString(executeText));
CompileMethod("OffScan", GetMxValueString(offScanText));
CompileMethod("Shutdown", GetMxValueString(shutdownText));
}
if (ErrorMessage.Length == 0 || ErrorMessage.StartsWith("Warning"))
{
if (DebugEnabled)
{
Hashtable hashtable = new Hashtable();
ResolveEventHandler value = new TypeResolveHandler(ModuleBuilder, hashtable).ResolveEvent;
AppDomain.CurrentDomain.TypeResolve += value;
NameHierarchy nameHierarchy = new NameHierarchy();
int num = 0;
foreach (ExternalReference item in ExternalReferences.List)
{
nameHierarchy.Add(item.ReferenceString.Split('[')[0], num++);
}
Build(nameHierarchy, TypeBuilder, hashtable);
RecurseNestedTypes(TypeBuilder.CreateType());
AppDomain.CurrentDomain.TypeResolve -= value;
}
else
{
TypeBuilder.CreateType();
}
assemblyBuilder.Save(text);
}
foreach (Assembly key in ReferencedAssemblies.Keys)
{
list.Add(key.GetName().Name);
}
if (ErrorMessage.Length == 0)
{
string path = Path.Combine(tempPath, text);
using (FileStream fileStream = File.OpenRead(path))
{
array = new byte[fileStream.Length];
fileStream.Read(array, 0, (int)fileStream.Length);
}
if (DebugEnabled)
{
File.Exists(Path.ChangeExtension(path, "pdb"));
}
File.Delete(path);
}
}
catch (Exception ex)
{
ErrorMessage = "Internal QuickScript compiler error: " + ex.Message;
}
if (ErrorMessage.Length > 0)
{
PutMxValueString(errorMessage, ErrorMessage);
PutMxValueInteger(errorLine, ErrorLine);
PutMxValueInteger(errorColumn, ErrorColumn);
return;
}
PutMxValueString(errorMessage, "");
PutMxValueInteger(errorLine, 0);
PutMxValueInteger(errorColumn, 0);
PutMxValueBlob(binary, array, array.Length);
i = 1;
foreach (string item2 in list)
{
PutMxValueElementString(libaryDependencies, i++, item2);
}
i = 1;
int index = 1;
foreach (ExternalReference item3 in ExternalReferences.List)
{
if (item3.IsAlias)
{
PutMxValueElementInteger(aliasReferenceFlags, i++, item3.Flags);
continue;
}
PutMxValueElementString(externalReferences, index, item3.ReferenceString);
PutMxValueElementInteger(externalReferenceFlags, index++, item3.Flags);
}
}
private void RecurseNestedTypes(Type type)
{
Type[] nestedTypes = type.GetNestedTypes();
foreach (Type type2 in nestedTypes)
{
RecurseNestedTypes(type2);
}
}
private void GetErrorsAndWarnings(string section)
{
if (ErrorMessage.Length > 0 && !ErrorMessage.StartsWith("Warning"))
{
return;
}
IEnumerator enumerator = Parser.Errors.GetEnumerator();
try
{
if (enumerator.MoveNext())
{
ErrorInfo errorInfo = (ErrorInfo)enumerator.Current;
ErrorLine = errorInfo.Line;
ErrorColumn = errorInfo.Column;
ErrorMessage = $"Script {ScriptName} ({section}): {errorInfo.Message} (Line: {errorInfo.Line}, Col: {errorInfo.Column})";
return;
}
}
finally
{
IDisposable disposable = enumerator as IDisposable;
if (disposable != null)
{
disposable.Dispose();
}
}
enumerator = Parser.Warnings.GetEnumerator();
try
{
if (enumerator.MoveNext())
{
ErrorInfo errorInfo2 = (ErrorInfo)enumerator.Current;
ErrorLine = errorInfo2.Line;
ErrorColumn = errorInfo2.Column;
ErrorMessage = $"Warning: Script {ScriptName} ({section}): {errorInfo2.Message} (Line: {errorInfo2.Line}, Col: {errorInfo2.Column})";
}
}
finally
{
IDisposable disposable2 = enumerator as IDisposable;
if (disposable2 != null)
{
disposable2.Dispose();
}
}
}
private void CompileDeclarations(string declarationsText)
{
if (declarationsText.Length == 0)
{
return;
}
ILBuilder.DeclarationsAreFields = true;
Parser.DeclarationsAreFields = true;
Parser.Parse(declarationsText);
if (Parser.Tree is Expression)
{
CodeSpan codeSpan = (Parser.Tree as Expression).CodeSpan;
codeSpan = new CodeSpan(codeSpan.End.Line, codeSpan.End.Column + 1, codeSpan.End.Line, codeSpan.End.Column + 1);
Parser.Errors.Add(new ErrorInfo("Expected ';'", codeSpan.End.Line, codeSpan.End.Column, codeSpan.End.Line, codeSpan.End.Column));
}
GetErrorsAndWarnings("Declarations");
if (Parser.Errors.Count != 0)
{
return;
}
foreach (Statement item in Parser.Tree as IList)
{
Declaration declaration = item as Declaration;
FieldBuilder value = TypeBuilder.DefineField(declaration.VariableName, declaration.Type, FieldAttributes.Public);
ILBuilder.Variables[declaration.VariableName] = value;
ILBuilder.Emit(declaration);
}
Parser.GetReferencedAssemblies(ReferencedAssemblies);
}
private void CompileExpression(string expressionText)
{
if (expressionText.Length != 0)
{
ILBuilder.DeclarationsAreFields = false;
Parser.DeclarationsAreFields = false;
Parser.Parse(expressionText);
if (Parser.Tree is Statements)
{
CodeSpan codeSpan = ((Parser.Tree as Statements)[0] as Statement).CodeSpan;
Parser.Errors.Add(new ErrorInfo("Not expecting ';'", codeSpan.End.Line, codeSpan.End.Column, codeSpan.End.Line, codeSpan.End.Column));
}
GetErrorsAndWarnings("Expression");
if (Parser.Errors.Count <= 0)
{
MethodAttributes attributes = MethodAttributes.Public | MethodAttributes.Final | MethodAttributes.Virtual | MethodAttributes.HideBySig;
MethodBuilder methodBuilder = TypeBuilder.DefineMethod("Expression", attributes, typeof(void), ExpessionParameterTypes);
methodBuilder.DefineParameter(1, ParameterAttributes.Out, null);
methodBuilder.DefineParameter(2, ParameterAttributes.Out, null);
ILGenerator iLGenerator = methodBuilder.GetILGenerator();
ILBuilder.ILGenerator = iLGenerator;
ILBuilder.Variables.ClearLocals();
ILBuilder.DebugEnabled = false;
Expression expression = Parser.Tree as Expression;
iLGenerator.Emit(OpCodes.Ldarg_1);
ILBuilder.Emit(Coerce.ChangeType(expression, typeof(object)));
iLGenerator.Emit(OpCodes.Stind_Ref);
iLGenerator.Emit(OpCodes.Ldarg_2);
ILBuilder.Emit(Digester.GetQuality(expression));
iLGenerator.Emit(OpCodes.Conv_I4);
iLGenerator.Emit(OpCodes.Stind_I4);
ILBuilder.Emit(new Return());
Parser.GetReferencedAssemblies(ReferencedAssemblies);
}
}
}
private void CompileMethod(string methodName, string methodText)
{
if (methodText.Length == 0)
{
if (!(methodName == "Startup"))
{
return;
}
methodText = ";";
}
ILBuilder.DeclarationsAreFields = false;
Parser.DeclarationsAreFields = false;
Parser.Parse(methodText);
if (Parser.Tree is Expression)
{
CodeSpan codeSpan = (Parser.Tree as Expression).CodeSpan;
codeSpan = new CodeSpan(codeSpan.End.Line, codeSpan.End.Column + 1, codeSpan.End.Line, codeSpan.End.Column + 1);
Parser.Errors.Add(new ErrorInfo("Expected ';'", codeSpan.End.Line, codeSpan.End.Column, codeSpan.End.Line, codeSpan.End.Column));
}
GetErrorsAndWarnings(methodName);
if (Parser.Errors.Count > 0)
{
return;
}
ISymbolDocumentWriter symbolDocumentWriter = null;
if (DebugEnabled)
{
string text = DebugFolder + "\\" + TagName + "." + ScriptName + "." + methodName + ".qs";
if (methodText.Length > 1)
{
using StreamWriter streamWriter = File.CreateText(text);
streamWriter.Write(methodText);
}
symbolDocumentWriter = ModuleBuilder.DefineDocument(text, Guid.Empty, Guid.Empty, Guid.Empty);
}
Type[] parameterTypes = new Type[0];
switch (methodName)
{
case "Startup":
parameterTypes = new Type[1] { typeof(IScriptExchange) };
break;
case "Execute":
parameterTypes = new Type[1] { typeof(ScriptTimer) };
break;
}
MethodAttributes attributes = MethodAttributes.Public | MethodAttributes.Final | MethodAttributes.Virtual | MethodAttributes.HideBySig;
ILGenerator iLGenerator = TypeBuilder.DefineMethod(methodName, attributes, typeof(void), parameterTypes).GetILGenerator();
ILBuilder.ILGenerator = iLGenerator;
ILBuilder.Variables.ClearLocals();
ILBuilder.SymbolDocumentWriter = symbolDocumentWriter;
ILBuilder.DebugEnabled = false;
ILBuilder.CheckForTimeout = methodName == "Execute" && !DebugEnabled;
if (methodName == "Startup")
{
iLGenerator.Emit(OpCodes.Ldarg_0);
iLGenerator.Emit(OpCodes.Ldarg_1);
iLGenerator.Emit(OpCodes.Stfld, ScriptExchange);
if (DebugEnabled)
{
Expression destination = new Field(new This(), typeof(ScriptBase).GetField("TagName"));
Expression source = new ConstantString(TagName);
ILBuilder.Emit(new Assignment(destination, source));
ILBuilder.Emit(new ExpressionStatement(new Method(null, EnableDebugSupport, new Expression[1]
{
new This()
})));
}
}
Statements statements = Parser.Tree as Statements;
ILBuilder.DebugEnabled = DebugEnabled;
ILBuilder.LineNumber = 0;
ILBuilder.Emit(statements);
ILBuilder.Emit(new Return());
Parser.GetReferencedAssemblies(ReferencedAssemblies);
}
static ScriptPackage()
{
ScriptExchange = typeof(ScriptBase).GetField("ScriptExchange");
ExpessionParameterTypes = null;
EnableDebugSupport = typeof(ArchestrA.QuickScript.Runtime.ExternalReference).GetMethod("EnableDebugSupport");
ParameterInfo[] parameters = typeof(IScriptObject).GetMethod("Expression").GetParameters();
ExpessionParameterTypes = new Type[parameters.Length];
int num = 0;
ParameterInfo[] array = parameters;
foreach (ParameterInfo parameterInfo in array)
{
ExpessionParameterTypes[num++] = parameterInfo.ParameterType;
}
}
private void Build(NameHierarchy nameHierarchy, TypeBuilder typeBuilder, Hashtable hashtable)
{
Type typeFromHandle = typeof(ArchestrA.QuickScript.Runtime.ExternalReference);
typeFromHandle.GetField("Index");
if (nameHierarchy.Index == -1)
{
TypeBuilder typeBuilder2 = null;
if (nameHierarchy.Name != null)
{
typeBuilder2 = typeBuilder.DefineNestedType("Tag" + ++NestedTypeIndex, TypeAttributes.NestedPublic, typeFromHandle);
}
foreach (NameHierarchy value in nameHierarchy.Hashtable.Values)
{
Build(value, (typeBuilder2 != null) ? typeBuilder2 : typeBuilder, hashtable);
}
if (nameHierarchy.Name != null)
{
hashtable[typeBuilder2.Name] = typeBuilder2;
}
if (typeBuilder2 != null)
{
typeBuilder.DefineField(nameHierarchy.Name, typeBuilder2, FieldAttributes.Public);
}
}
else if (nameHierarchy.Name != null)
{
string name = "T" + nameHierarchy.Index;
TypeBuilder typeBuilder3 = typeBuilder.DefineNestedType(name, TypeAttributes.NestedPublic, typeof(ExternalReferenceDebug));
typeBuilder.DefineField(nameHierarchy.Name, typeBuilder3, FieldAttributes.Public);
hashtable[typeBuilder3.Name] = typeBuilder3;
}
}
[DllImport("ScriptPackage.dll", CharSet = CharSet.Unicode)]
[SuppressUnmanagedCodeSecurity]
[return: MarshalAs(UnmanagedType.BStr)]
private static extern string GetMxValueString(IntPtr rawMxValue);
[DllImport("ScriptPackage.dll")]
[SuppressUnmanagedCodeSecurity]
private static extern void PutMxValueInteger(IntPtr rawMxValue, int value);
[DllImport("ScriptPackage.dll", CharSet = CharSet.Unicode)]
[SuppressUnmanagedCodeSecurity]
private static extern void PutMxValueString(IntPtr rawMxValue, string value);
[DllImport("ScriptPackage.dll")]
[SuppressUnmanagedCodeSecurity]
private static extern void PutMxValueBlob(IntPtr rawMxValue, [MarshalAs(UnmanagedType.LPArray)] byte[] value, int size);
[DllImport("ScriptPackage.dll")]
[SuppressUnmanagedCodeSecurity]
private static extern int GetMxValueElementCount(IntPtr rawMxValue);
[DllImport("ScriptPackage.dll", CharSet = CharSet.Unicode)]
[SuppressUnmanagedCodeSecurity]
[return: MarshalAs(UnmanagedType.BStr)]
private static extern string GetMxValueElementString(IntPtr rawMxValue, int index);
[DllImport("ScriptPackage.dll", CharSet = CharSet.Unicode)]
[SuppressUnmanagedCodeSecurity]
private static extern void PutMxValueElementString(IntPtr rawMxValue, int index, string value);
[DllImport("ScriptPackage.dll")]
[SuppressUnmanagedCodeSecurity]
private static extern void PutMxValueElementInteger(IntPtr rawMxValue, int index, int value);
}
}
namespace AcmeBuildVersion
{
internal sealed class Versioning
{
public const string Company = "AVEVA Software, LLC";
public const string Product = "";
public const string Copyright = "Copyright 2020 AVEVA Group plc and its subsidiaries. All rights reserved.";
public const string Trademark = "Refer to: https://sw.aveva.com/legal/trademarks";
public const string Configuration = "Release";
public const string BuildNumber = "5800";
public const string BuildMaintenanceNumber = "7005";
public const string BldRevision = "1";
private Versioning()
{
}
}
internal sealed class ComponentVersioning
{
public const string ComponentVersion = "0038";
public const string ComponentMaintenanceVersion = "0000";
public const string ComponentName = "ScriptPrimitive";
private ComponentVersioning()
{
}
}
}