嵌入.bat文件的C#源代码

嵌入.bat文件的C#源代码,c#,.net,batch-file,compilation,csc,C#,.net,Batch File,Compilation,Csc,人们可能想知道-如何用嵌入式c#code制作一个.bat文件来“动态”编译和执行它? 有可能在一个文件中同时包含批处理指令和c代码吗?是的,有可能。 以下是一个例子: 示例.bat /* 2> nul @echo off && cls && echo Loading... && echo. set WinDirNet=%WinDir%\Microsoft.NET\Framework if exist "%WinDirNet%\v2.0.507

人们可能想知道-如何用嵌入式c#code制作一个
.bat
文件来“动态”编译和执行它?
有可能在一个文件中同时包含批处理指令和c代码吗?

是的,有可能。
以下是一个例子:

示例.bat

/* 2> nul
@echo off && cls && echo Loading... && echo.
set WinDirNet=%WinDir%\Microsoft.NET\Framework
if exist "%WinDirNet%\v2.0.50727\csc.exe" set csc="%WinDirNet%\v2.0.50727\csc.exe"
if exist "%WinDirNet%\v3.5\csc.exe" set csc="%WinDirNet%\v3.5\csc.exe"
if exist "%WinDirNet%\v4.0.30319\csc.exe" set csc="%WinDirNet%\v4.0.30319\csc.exe"
if "%csc%" == "" ( echo .NET Framework not found! && echo. && pause && exit )
%csc% /nologo /out:"%~dpnx0.exe" "%~dpnx0"
if not "%ERRORLEVEL%" == "0" ( echo. && pause && exit )
cls
"%~dpnx0.exe" %*
del "%~dpnx0.exe"
exit
*/

using System;
class Program
{
    static void Main()
    {
        System.Console.WriteLine("Hello, World!\r\nI am at " + System.Environment.Version);
    }
}
说明:此批处理文件由两部分组成:第一部分是批处理代码,第二部分是c#代码。执行时,命令shell将忽略c#-注释
/*
*/
作为错误行,并仅执行批处理代码。由于批处理块末尾有exit命令,执行永远不会到达c#代码。
文件的批处理部分搜索
csc.exe
(.NET编译器)。找到后,批处理文件将自身传递到
csc.exe
以编译c#代码。由于注释(/*和*/)的原因,批处理部分被忽略,只编译c#部分。编译后生成的.exe文件被执行并在执行后删除


编辑:
2>nul
将标准错误(描述符2)重定向为null以抑制“未找到”消息。

您可以注释掉批处理代码,但无法避免批处理将注释作为错误处理

错误本身可以被抑制,但至少会显示第一行

/* 2>NUL
@echo off
...
start the C# code
*/
...
C#-Code
由于C#似乎不接受其中一个
:@
字符作为文件中的第一个字符,因此我无法找到一个完美的解决方案

方法很少

1)与前面的答案类似,但自动检测.net framework的最新版本:

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

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

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

if not exist "%~n0.exe" (
   call %csc% /nologo /w:0 /out:"%~n0.exe" "%~dpsfnx0" || (
      exit /b %errorlevel% 
   )
)
%~n0.exe %*
endlocal & exit /b %errorlevel%

*/

using System;


class QE {
    static void Main(string[] args) {
         Console.WriteLine("Echo from C#");
    }
}
2)在windows 10中,默认情况下安装.net framework,并且在那里,msbuild允许内联任务,这样就可以进行内存内编译(即-没有额外的exe文件)和xml格式的嵌入,这意味着没有冗余输出。请注意,命令行参数保存在
CMD_ARGS
环境变量中:

<!-- :
    @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("Echo from C# with msBuild -- "+"$(MSBuildToolsVersion)"); 
      }
        ]]>
      </Code>
    </Task>
  </UsingTask>
</Project>

您将得到
“/*”不被识别为内部或外部命令、可操作程序或批处理文件。
但无论何时启动批处理文件:p@Nyerguds我认为,
cls
应该负责:p@Exerion哦,我从来没有怀疑过。只是没有一个真正的开始顺序对两者都完全有效。因为.bat不关心一个非法命令,而cs文件不会编译;),所以您只是选择了两个缺点中较小的一个哦,我找到了一个。使用
/*2>nul
作为第一行将抑制“未找到”消息:遗憾的是,由于这是在@echo关闭之前,它不会抑制显示的命令,因此它仍然需要
cls
。啊,我添加了一个小附录。cls仍然是需要的,因为命令在
@echo off
之前,这意味着它将出现在屏幕上。你也不能在它前面加一个
@
,因为这会再次使它C#无效。但我想,至少用户不会因为控制台上的错误信息在瞬间闪烁而担心。
<# : batch portion
@echo off & setlocal

set "CMD_ARGS=%~1"

powershell -noprofile "iex (${%~f0} | out-string)"
goto :EOF

: end batch / begin powershell #>

param($psArg1 = $env:psArg1)


$CS = @" 
namespace PS {
  public class CS
  {
    public static void csEcho(string arg)
    { System.Console.WriteLine("echo from C# " + arg); }
  }
}
"@

Add-Type -TypeDefinition $CS -Language CSharp


[PS.CS]::csEcho($psArg1 + " and PowerShell")
@if (@X)==(@Y) @end /* JScript comment
@echo off
setlocal

for /f "tokens=* delims=" %%v in ('dir /b /s /a:-d  /o:-n "%SystemRoot%\Microsoft.NET\Framework\*jsc.exe"') do (
   set "jsc=%%v"
)

if not exist "%~n0.exe" (
    "%jsc%" /nologo /out:"%~n0.exe" "%~dpsfnx0"
)

%~n0.exe %*

endlocal & exit /b %errorlevel%


*/

import System;
Console.Write("Echo from .NET")