- Aug
- 2,799
- 144
This is a not ready for prime time example of how to Write/Run your C# code in a .btm file.
Use it as a starting point for your own C# code.
Joe
Use it as a starting point for your own C# code.
Code:
:: Demonstrates how to use C# code from TCC via PSHELL
::
:: Compile the C# code in-memory
:: and/or
:: Compile the C# code to a .dll
::
:: Call the C# functions via PShell
::
@setlocal
@echo off
:: If useDLL=Y then use @name[%_batchname].dll
:: If useDLL=N then use @name[%_batchname].cs
set useDLL=Y
:: If rebuildDLL=Y then rebuild @name[%_batchname].dll from @name[%_batchname].cs
:: If rebuildDLL=N then use the existing @name[%_batchname].dll
set rebuildDLL=N
set theDLL=%@name[%_batchname].dll
set theCS=%@name[%_batchname].cs
set theDLLDir=%@path[%_batchname]
iff not isdir %theDLLDir then
echo %theDLLDir does not exist.
quit
endiff
::
:: Generate the C# Code
::
Gosub CSCode
::
:: Rebuild DLL
::
iff %RebuildDLL eq Y .and. exist %theDLLDir\%theDLL then
del %theDLLDir\%theDLL /q
Gosub BuildDLL
endiff
iff %RebuildDLL eq Y .and. not exist %theDLLDir\%theDLL then
Gosub BuildDLL
endiff
::
:: UseDLL
::
iff %useDLL eq Y then
iff not exist %theDLLDir\%theDLL then
Gosub BuildDLL
Gosub LoadDLL
else
:: theDLL exists, so just LoadDLL
Gosub LoadDLL
endiff
endiff
iff %useDLL eq N .and. defined theCS .and. exist %theDLLDir\%theCS then
:: Load the C# code
:: NOTE: This LOCKS the Type (Code) in Memory.
:: To remove, exit TCC and re-start TCC
pshell /s "add-type -path %theDLLDir\%theCS"
set InternalExitCode=%_?
set ExternalExitCode=%?
iff %InternalExitCode ne 0 .or. %ExternalExitCode ne 0 then
echo External Command Exit Code: %ExternalExitCode
echo Internal Command Exit Code: %InternalExitCode
echo.
echo %theDLLDir\%theCS exists,
echo but there is a problem with the %theDLLDir\%theCS source code.
echo.
echo File %_batchname near line %_batchline
quit
endiff
unset InternalExitCode
unset ExternalExitCode
endiff
iff %useDLL eq N .and. not exist %theDLLDir\%theCS then
echo Problem at Line: %_batchline
echo %theDLLDir\%theCS does not exist.
quit
endiff
::
:: Execute a Function contained in the assembly
::
echo Days in month (%_year %_month) %@pshell[[Utils]::DaysInMonth(%_year,%_month)]
pshell /s "[Utils]::TestLoop(1000)"
:: set results=%@pshell[[Utils]::StringBuilderTest()]
:: set results
function GetUserName=`%@pshell[[advapi32]::GetUserName()]`
function DaysInMonth=`%@pshell[[utils]::DaysInMonth(%1,%2)]`
echo GetUserName: %@GetUserName[]
echos GetUserName:` `
pshell /s "[advapi32]::GetUserName()"
echos ShellTray:` `
pshell /s "[user32]::ShellTray()"
echo Days in month (%_year %_month) %@DaysInMonth[%_year, %_month]
echo Lambda: %@pshell[[utils]::SortNumbers("24 +13+12 +21 +46 +14+10+20+14+ 30 +18+ 50")]
tmp /c tmp9:
pshell /s "$PSVersionTable" |! tpipe /simple=11 /output=tmp9:
type tmp9:
iff %UseDLL eq N then
iff defined theCS then
if exist %theDLLDir\%theCS del /q %theDLLDir\%theCS
endiff
endiff
endlocal
quit
::----------------------------------------
:BuildDLL
:: The Microsoft (R) Visual C# Compiler version 4.14.0-3.25412.6 (c167adef) compiler
:: is required to build the .dll
::
:: U:\>which csc
:: csc is an alias : "C:\Program Files\Microsoft Visual Studio\2022\Community\MSBuild\Current\Bin\Roslyn\csc.exe"
csc -platform:x64 -target:library %theDLLDir\%@name[%_batchname].cs
set InternalExitCode=%_?
set ExternalExitCode=%?
iff %InternalExitCode ne 0 .or. %ExternalExitCode ne 0 then
echo External Command Exit Code: %ExternalExitCode
echo Internal Command Exit Code: %InternalExitCode
echo.
if defined theCS echo Error compiling %theDLLDir\%theCS
if defined theVB echo Error compiling %theDLLDir\%theVB
echo.
echo File %_batchname near line %_batchline
quit
endiff
unset InternalExitCode
unset ExternalExitCode
describe %theDLLDir\%theDLL /D"csc -platform:x64 -target:library %theDLLDir\%theCS"
Return
::----------------------------------------
:LoadDLL
::
:: Load the C# code into memory
::
:: NOTE: Once you load the C# code into memory,
:: using LoadFrom(),
:: it can only be unloaded by exiting TCC
::
:: pshell /s "[System.Reflection.Assembly]::LoadFrom('%theDLLDir\%theDLL')"
::
:: I'm using .NET Framework 4.8
::
:: https://stackoverflow.com/a/37468429/14824505
:: Load the assembly without locking it during the duration of the PowerShell session
pshell /s "$bytes = [System.IO.File]::ReadAllBytes('%theDLLDir\%theDLL')"
pshell /s "[System.Reflection.Assembly]::Load($bytes)" > nul
Return
:CSCode
type <<- endtext > %theDLLDir\%theCS
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
using System.Linq;
public class Utils
{
public static long DaysInMonth(long year, long month)
{
int daysInMonth = DateTime.DaysInMonth((int)year, (int)month);
return daysInMonth;
}
public static string StringBuilderTest()
{
StringBuilder builder = new StringBuilder();
for (int i = 1; i <= 1000; i++)
{
builder.Append("Step " + i + "\r\n");
}
return builder.ToString();
}
public static long TestLoop(long A)
{
long index;
for (index = 1; index <= A; index++)
{
// no-op
}
return index;
}
public static long Squared(long A)
{
long squared = A * A;
return squared;
}
public static string SortNumbers(string input)
{
//string input = "82 +13+12 +21 +46 +14+10+20+14+ 30 +18+ 50";
var sortedNumbers = input
.Split('+')
.Select(s => int.Parse(s.Trim()))
.OrderBy(n => n)
.ToArray();
return string.Join("+", sortedNumbers);
}
}
public class advapi32
{
public static string GetUserName()
{
StringBuilder buffer = new StringBuilder(256);
int size = buffer.Capacity;
bool ok = Win32API.GetUserName(buffer, ref size);
if (!ok)
return string.Empty;
return buffer.ToString();
}
}
public class user32
{
public static long ShellTray()
{
return Win32API.FindWindow("Shell_TrayWnd", null);
}
}
internal class Win32API
{
[DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern bool GetUserName(StringBuilder lpBuffer, ref int nSize);
[DllImport("user32.dll", EntryPoint = "FindWindowA", CharSet = CharSet.Ansi)]
public static extern long FindWindow(string lpClassName, string lpWindowName);
}
endtext
Return
Joe
Last edited: