Page 2 of 2

Re: self-compiled .net hybrids

Posted: 24 Jun 2015 08:03
by npocmaka_
Without redundant output:



Code: Select all

// 2>nul||@goto :batch
/*
:batch
@echo off

setlocal
:: find csc.exe
set "frm=%SystemRoot%\Microsoft.NET\Framework\"
for /f "tokens=* delims=" %%v in ('dir /b /a:d  /o:-n "%SystemRoot%\Microsoft.NET\Framework\v*.*"') do (
   set netver=%%v
   goto :break_loop
)
:break_loop
set csc=%frm%%netver%\csc.exe
:: csc.exe found
if not exist %~n0.exe (
   %csc% /nologo /out:"%~n0.exe" "%~dpsfnx0" >nul
)
%~n0.exe
echo -- redundant output has been cleared --

endlocal
exit /b 0
*/
public class Hello
{
   public static void Main() {
      ClearC();
      System.Console.WriteLine("Hello, C# World!");
   }

   public static void ClearC() {
      try {
         System.Console.CursorTop = System.Console.CursorTop - 1;
         System.Console.Write(new string(' ', System.Console.BufferWidth));
         System.Console.CursorTop = System.Console.CursorTop - 1;
      } catch (System.IO.IOException e) {
      }
   }
}


though if there are `echo`-es before the c# part you'll need to change the cursor position.And wont work if the file is redirected to a file.Also I'm not sure if Console.CursorTop is available in .net 2 and 3

Re: self-compiled .net hybrids

Posted: 24 Jun 2015 14:37
by Ben Mar
npocmaka_ wrote:Without redundant output:

You can do that trick with "cls" too :-)

Code: Select all

//>nul 2>nul||@goto :batch
/*
:batch
@echo off
setlocal
cls
:: find csc.exe
set "frm=%SystemRoot%\Microsoft.NET\Framework\"
for /f "tokens=* delims=" %%v in ('dir /b /a:d  /o:-n "%SystemRoot%\Microsoft.NET\Framework\v*"') do (
   set netver=%%v
   goto :break_loop
)
:break_loop
set csc=%frm%%netver%\csc.exe
:: csc.exe found

call %csc% /nologo /out:"%~n0.exe" "%~dpsfnx0"
%~n0.exe
endlocal
exit /b 0
*/
public class Hello
{
   public static void Main()
   {
      System.Console.WriteLine("Hello, C# World!");
   }
}

Re: self-compiled .net hybrids

Posted: 21 Mar 2016 10:56
by npocmaka_
I've just found this:

Code: Select all

https://gist.github.com/subTee/28b7439d3dfa07053b61


Looks like something that will allow platform invoke from JScript.net.
Not tested yet.
It will be good it works because in some cases will be a good replacement of C# and its redundant output.
Though it will be not so powerful as jscript does not allow passing by reference.

Re: self-compiled .net hybrids

Posted: 07 Oct 2016 06:15
by npocmaka_
using msbuild (without redundant output and without temp files ! ) :

Code: Select all

<!-- :
    @echo off


        echo -^- FROM BATCH

        set "CMD_ARGS=%*"
        ::::::  Starting C# code :::::::
        :: searching for msbuild location
        for /r "%SystemRoot%\Microsoft.NET\Framework\" %%# in ("*msbuild.exe") do  set "msb=%%#"

        if not defined  msb (
           echo no .net framework installed
           exit /b 10
        )

        rem ::::::::::  calling msbuid :::::::::
        call %msb% /nologo  /noconsolelogger "%~dpsfnx0"  /property:"H=From C#"
        rem ::::::::::::::::::::::::::::::::::::
        exit /b %errorlevel%
-->


<Project ToolsVersion="$(MSBuildToolsVersion)" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Target Name="_">
    <_/>
  </Target>
  <UsingTask
    TaskName="_"
    TaskFactory="CodeTaskFactory"
    AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v$(MSBuildToolsVersion).dll" >

    <ParameterGroup  >
         <Z ParameterType="System.String">$(H)</Z>
    </ParameterGroup>

    <Task>
      <Using Namespace="System" />
      <Code Type="Fragment" Language="cs">
        <![CDATA[
            String CMD_ARGS=Environment.GetEnvironmentVariable("CMD_ARGS");
            System.Console.WriteLine("-- "+"$(H)"); 
        ]]>
      </Code>
    </Task>
  </UsingTask>
</Project>



Will have to experiment more with this to see how P/Invoke can be used (something I can't do neat with jscript.net)

https://msdn.microsoft.com/en-us/library/dd722601.aspx

Re: self-compiled .net hybrids

Posted: 06 Jan 2017 16:02
by npocmaka_
More notes on the msbuild technique.
If you need a reference to a dll you'll need to include it in the task node in the xml (alike the simple /r:some.dll in csc compiler)

you cant use the "--" directly in batch part because it will broke the xml parsing (I'll have to think how the batch part can be put in CDATA section... may be will be not possible)

The type can be fragment (as in the previous example) or class or method

Using a class needs more effort than a fragment - you need to implement ITask interface . Though it will be easier to inherit Task class which has some pipe work done. These are in Microsoft.Build.Framework and Microsoft.Build.Utilities namespaces. Doing so you'll have to override Execute method.

The class must be public (though you can have more non public classes) and it should have the same name as the task you want to execute.

Here's an example:

Code: Select all

<!-- :
    @echo off


        echo -^- FROM BATCH

        set "CMD_ARGS=%*"
        ::::::  Starting C# code :::::::
        :: searching for msbuild location
        for /r "%SystemRoot%\Microsoft.NET\Framework\" %%# in ("*msbuild.exe") do  set "msb=%%#"

        if not defined  msb (
           echo no .net framework installed
           exit /b 10
        )

        rem ::::::::::  calling msbuid :::::::::
        call %msb% /nologo  /noconsolelogger "%~dpsfnx0"  /property:"H=From C#"
        rem ::::::::::::::::::::::::::::::::::::
        exit /b %errorlevel%
      
-->


<Project ToolsVersion="$(MSBuildToolsVersion)" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Target Name="Program">
    <Program/>
  </Target>
  <UsingTask
    TaskName="Program"
    TaskFactory="CodeTaskFactory"
    AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v$(MSBuildToolsVersion).dll" >

    <ParameterGroup  >
         <Z ParameterType="System.String">$(H)</Z>
    </ParameterGroup>

    <Task>
     <Reference Include="$(MSBuildToolsPath)\System.Windows.Forms.dll"/>
      <Using Namespace="System" />
 
      <Code Type="Class" Language="cs">
        <![CDATA[
   using Microsoft.Build.Framework;
   using Microsoft.Build.Utilities;
   using System;
   
   public class Program:Task, ITask
    {
      public override bool Execute(){
         Console.WriteLine("Whoa");
         String CMD_ARGS=Environment.GetEnvironmentVariable("CMD_ARGS");
                        System.Console.WriteLine("-- "+"$(MSBuildToolsVersion)");
         return true;
      }
   }
        ]]>
      </Code>
    </Task>
  </UsingTask>
</Project>


Also the MSBuildToolsVersion and MSBuildToolsPath are no more hard coded in the xml.

As a reference I've used this - https://gist.github.com/subTee/6fa2b0cc ... 0e6d93f31a (in the subtee's gists there are pretty interesting things)

Still not tried to implement a method The msdn does not tell much -
If the value of Type is Method, then the code defines an override of the Execute method of the ITask interface.


I feel a little lonely in my excitement about this - but for sure will try and share the method type task too.


EDIT. Example with method (the msdn explanation was more than enough):

Code: Select all

<!-- :
    @echo off


        echo -^- FROM BATCH

        set "CMD_ARGS=%*"
        ::::::  Starting C# code :::::::
        :: searching for msbuild location
        for /r "%SystemRoot%\Microsoft.NET\Framework\" %%# in ("*msbuild.exe") do  set "msb=%%#"

        if not defined  msb (
           echo no .net framework installed
           exit /b 10
        )

        rem ::::::::::  calling msbuid :::::::::
        call %msb% /nologo  /noconsolelogger "%~dpsfnx0"
        rem ::::::::::::::::::::::::::::::::::::
        exit /b %errorlevel%
      
-->


<Project ToolsVersion="$(MSBuildToolsVersion)" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Target Name="_">
    <_/>
  </Target>
  <UsingTask
    TaskName="_"
    TaskFactory="CodeTaskFactory"
    AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v$(MSBuildToolsVersion).dll" >

    <Task>
     <Reference Include="$(MSBuildToolsPath)\System.Windows.Forms.dll"/>
      <Using Namespace="System" />
 
      <Code Type="Method" Language="cs">
        <![CDATA[

      public override bool Execute(){
         MyMethod();
         return true;
      }
      
      void MyMethod(){
         Console.WriteLine("Whoa");
         String CMD_ARGS=Environment.GetEnvironmentVariable("CMD_ARGS");
            System.Console.WriteLine("-- "+"$(MSBuildToolsVersion)");
      }
        ]]>
      </Code>
    </Task>
  </UsingTask>
</Project>

Re: self-compiled .net hybrids

Posted: 07 Jan 2017 08:58
by LotPings
Nice one npocmaka,

two questions
1. why do you call msbuild.exe?
2. are there remnant files from the build, if yes where are they located?

Wish you a happy new year.

Re: self-compiled .net hybrids

Posted: 07 Jan 2017 09:13
by npocmaka_
LotPings wrote:Nice one npocmaka,

two questions
1. why do you call msbuild.exe?
2. are there remnant files from the build, if yes where are they located?

Wish you a happy new year.


1.MSBuild works with xml files which can be used in batch files for comment lines without redundant output. the "<!-- :" will be executed as ":<!--" i.e. label and there will be nothing displayed in the console.

2.This is even more beautiful - there are no build files , no temp files - everything is loaded in the memory (may be this mean that it will be faster but I'n not sure). Except there's a compilation error - there will be some source files in the %temp% where you can see in more details what msbuild is doing.


WRONG:The only impediment is that you can't exit with custom error codes if the build is successful it returns 0 otherwise 1 , depending on what is returned from Execute() method.

Re: self-compiled .net hybrids

Posted: 01 Aug 2018 05:39
by npocmaka_
Probably the inline tasks for msbuild will remain the best method for .net hybridization. But this will require .net framework 4.6 (can it be installed on something different than windows 10?) so it is not so portable.

Using c# without msbuild will produce redundant output because of the '// 2>nul||@goto :batch' line (vb.net also will produce something similar). JScript.net does not support syntax sugaring for platform invokes but it is still possible (http://cx20.main.jp/blog/hello/2013/03/ ... net-world/):

Code: Select all

@if (@X)==(@Y) @end /* JScript comment
@echo off
setlocal

set "jsc="
for /r "%SystemRoot%\Microsoft.NET\Framework\" %%# in ("*jsc.exe") do  set "jsc=%%#"

if not exist "%jsc%" (
   echo no .net framework installed
   exit /b 10
)


::if not exist "%~n0.exe" (
	call "%jsc%"  /r:"System.Windows.Forms.dll" /nologo /out:"%~n0.exe" "%~dpsfnx0"||(
		exit /b %errorlevel%
	)
::)

"%~n0.exe"

endlocal & exit /b %errorlevel%

*/

import System;
import System.Reflection;
import System.Reflection.Emit;
import System.Runtime;
import System.Text;
 
// Invoke a Win32 P/Invoke call.
// http://www.leeholmes.com/blog/2006/07/21/get-the-owner-of-a-process-in-powershell-%e2%80%93-pinvoke-and-refout-parameters
function InvokeWin32(dllName:String, returnType:Type,
  methodName:String, parameterTypes:Type[], parameters:Object[])
{
  // Begin to build the dynamic assembly
  var domain = AppDomain.CurrentDomain;
  var name = new System.Reflection.AssemblyName('PInvokeAssembly');
  var assembly = domain.DefineDynamicAssembly(name, AssemblyBuilderAccess.Run);
  var module = assembly.DefineDynamicModule('PInvokeModule');
  var type = module.DefineType('PInvokeType',TypeAttributes.Public + TypeAttributes.BeforeFieldInit);
 
  // Define the actual P/Invoke method
  var method = type.DefineMethod(methodName, MethodAttributes.Public + MethodAttributes.HideBySig + MethodAttributes.Static + MethodAttributes.PinvokeImpl, returnType, parameterTypes);
 
  // Apply the P/Invoke constructor
  var ctor = System.Runtime.InteropServices.DllImportAttribute.GetConstructor([Type.GetType("System.String")]);
  var attr = new System.Reflection.Emit.CustomAttributeBuilder(ctor, [dllName]);
  method.SetCustomAttribute(attr);
 
  // Create the temporary type, and invoke the method.
  var realType = type.CreateType();
  return realType.InvokeMember(methodName, BindingFlags.Public + BindingFlags.Static + BindingFlags.InvokeMethod, null, null, parameters);
}
 
function MessageBox(hWnd:Int32, lpText:String, lpCaption:String, uType:Int32) 
{ 
   var parameterTypes:Type[] = [Type.GetType("System.Int32"),Type.GetType("System.String"),Type.GetType("System.String"),Type.GetType("System.Int32")];
   var parameters:Object[] = [hWnd, lpText, lpCaption, uType];
 
   return InvokeWin32("user32.dll", Type.GetType("System.Int32"), "MessageBoxA", parameterTypes,  parameters );
} 
 
MessageBox( 0, "Hello, Win32 API World!", "Hello, World!", 0 );
the interesting part is in the InvokeWin32 function (nothing so complicated and can't be used directly without knowing too much about reflection ).

Despite it is no more supported by MS jscript.net is the most backward compatible .net tool installed by default on Windows machines (it is not installed on win XP by default though it is highly probable ,but it is time to let XP die anyway).

With pure batch scripts and with WSH/jscript/vbscript there are limits that can't be overcome without accessing windows system libraries - so jscript.net is a worthy thing to dig in.

Probably I'll try to 'translate' the tools I've wrote with C# to jscript.net and if possible to update the examples in http://pinvoke.net/

Re: self-compiled .net hybrids

Posted: 24 Jul 2019 03:06
by Ruchipatil
:lol: Thank you for the information it was very useful.

Re: self-compiled .net hybrids

Posted: 28 Jul 2019 09:53
by jfl
One small improvement to the batch initialization:
During the JS development phase, it's necessary to recompile the source script every time it's updated.
The following code automates that:

Code: Select all

@echo off
setlocal

set "jsc="
for /r "%SystemRoot%\Microsoft.NET\Framework\" %%# in ("*jsc.exe") do  set "jsc=%%#"
if not exist "%jsc%" echo No .NET framework installed & exit /b 10

set "EXE=%~dpn0.exe" &:# Full pathname of the compiled executable
if exist "%EXE%" ( :# If the EXE exists and the BAT is newer, then delete the EXE
  xcopy /d /y /l "%~f0" "%EXE%" | findstr "%~d0" >NUL && del "%EXE%"
)
if not exist "%EXE%" (
  "%jsc%" /nologo /out:"%EXE%" "%~f0" || exit /b
)

"%EXE%" %*

endlocal & exit /b %errorlevel%