среда, 30 мая 2018 г.

C# и CLI

Задался вопросом: как компилировать программы на C# не имея установленных средств разработки типа Visual Studio или там Sharp Develop. Ну просто и компьютер слабоват, и вообще... Выяснилось, что можно - соответствующие компиляторы и утилиты штатно поставляются вместе с .NET Framework - но, конечно, не так комфортно, как во всех этих WYSIWYG редакторах.

При разработке интерфейсов показалось более удобным воспользоваться XAML, поэтому возникла вторая задача - как этот самый XAML использовать тоже из командной строки.

Кроме того, есть существенная особенность - всё происходит под Windows XP с установленным на ней .NET Framework v3.5. Итак, приступим.

1. Простейшее консольное приложение
Файл Program.cs
using System;  

class HelloWorld  
{  
    static void Main()  
    {  
        Console.WriteLine("Привет, мир!");  
    }  
}  
как оказалось, без проблем компилируется командой:
C:\WINDOWS\Microsoft.NET\Framework\v3.5\csc.exe  Program.cs
Причем компилятор каким-то чудесным образом корректно обрабатывает русские буквы, при этом автоматически определяя кодировку исходного файла.

2. Если приложение посложнее, то знающие люди советуют не пользоваться компилятором напрямую ввиду обилия разнообразных опций, которые потребуется выставить, а использовать утилиту MS Build. Утилита берёт настройки из файла *.csproj, так что проект дополняется ещё одним файлом:
Файл project.csproj
<?xml version="1.0" encoding="utf-8"?>
<Project  DefaultTargets="Rebuild"  xmlns="http://schemas.microsoft.com/developer/msbuild/2003">  

 <PropertyGroup>

  <!-- имя сборки -->
  <AssemblyName>main</AssemblyName>  

  <!-- в какую папку будет компилироваться сборка -->
  <OutputPath>bin\</OutputPath>  

 </PropertyGroup>  


 <ItemGroup>  
  <Compile Include="Program.cs" />  
 </ItemGroup>  


 <Target Name="Clean">  
  <Delete Files="$(OutputPath)$(AssemblyName).exe" Condition="Exists('$(OutputPath)')" />  
 </Target>  

 <Target Name="Build">  

  <!-- если папка, в которую будет компилироваться проект, не существует, создаём её -->
  <MakeDir Directories="$(OutputPath)" Condition="!Exists('$(OutputPath)')" />  

  <!-- компилируем сборку -->
  <Csc Sources="@(Compile)" OutputAssembly="$(OutputPath)$(AssemblyName).exe" />

 </Target>

 <Target Name="Rebuild" DependsOnTargets="Clean;Build" /> 

</Project>
и собирается следующей командой:
C:\WINDOWS\Microsoft.NET\Framework\v3.5\msbuild.exe  project.csproj
Тут уже можно задавать некую структуру проекта, например, создавать отдельную папку для результата компиляции. Кстати, если присмотреться, секции <Target> идеологически сильно напоминают правила линуксовой утилиты make.

3. Но пришло время перейти к оконным приложениям. Поскольку за кулисами оконного интерфейса скрывается экземпляр класса System.Windows.Forms.Application, то изменяем файл Program.cs - теперь там этот самый экземпляр будет создаваться и вводиться в работу:
Файл Program.cs
using System;
using System.Windows.Forms;

namespace myProject
{
 static class Program
 {
  /// <summary>
  /// Точка входа в программу
  /// </summary>
  [STAThread]
  static void Main()
  {
   Application.EnableVisualStyles();
   Application.SetCompatibleTextRenderingDefault(false);
   Application.Run(new MainForm());
  }
 }
}
Кроме того, теперь требуется описать окно нашего приложения. В Visual Studio его описание разбито на несколько файлов, и нужно согласиться, что это достаточно удобно - вся рутина, посвященная созданию окна и расположенных на нем компонентов, вынесена в отдельный файл *.Designer.cs. Мы последуем этому примеру и создадим наши два файла для описания главного окна:
Файл MainForm.cs
using System;
using System.Windows.Forms;

namespace myProject
{
 public partial class MainForm : Form
 {
  public MainForm()
  {
   InitializeComponent();
  }
 }
}
Файл MainForm.Designer.cs
namespace myProject
{
 partial class MainForm
 {
  private void InitializeComponent()
  {
   System.Windows.Forms.Button button1 = new System.Windows.Forms.Button();

   button1.Location = new System.Drawing.Point(8, 8);
   button1.Name = "button1";
   button1.Size = new System.Drawing.Size(75, 23);
   button1.TabIndex = 0;
   button1.Text = "Кнопка";

   this.Controls.Add(button1);
  }
 }
}
Кроме того, изменения, очевидно, коснутся файла проекта - теперь он будет выглядеть так:
Файл project.csproj
<?xml version="1.0" encoding="utf-8"?>
<Project  DefaultTargets="Rebuild"  xmlns="http://schemas.microsoft.com/developer/msbuild/2003">  

 <PropertyGroup>

  <!-- имя сборки -->
  <AssemblyName>main</AssemblyName>  

  <!-- в какую папку будет компилироваться сборка -->
  <OutputPath>bin\</OutputPath>  

 </PropertyGroup>  


 <ItemGroup>  

  <Compile Include="Program.cs" />

  <!-- главное окно программы -->
  <Compile Include="MainForm.Designer.cs" />
  <Compile Include="MainForm.cs" />

 </ItemGroup>


 <Target Name="Clean">  
  <Delete Files="$(OutputPath)$(AssemblyName).exe" Condition="Exists('$(OutputPath)')" />  
 </Target>  

 <Target Name="Build">  

  <!-- если папка, в которую будет компилироваться проект, не существует, создаём её -->
  <MakeDir Directories="$(OutputPath)" Condition="!Exists('$(OutputPath)')" />  

  <!-- компилируем сборку -->
  <Csc Sources="@(Compile)" OutputAssembly="$(OutputPath)$(AssemblyName).exe" />

 </Target>

 <Target Name="Rebuild" DependsOnTargets="Clean;Build" /> 

</Project>

4. Как видим, всё хорошо, но описать форму можно удобнее. Воспользуемся таким инструментом, как XAML. Для этого заменяем файл Program.cs на его эквивалент:
Файл Program.xaml
<?xml version="1.0" encoding="utf-8"?>
<Application x:Class="myProject.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    StartupUri="MainWindow.xaml">
</Application>
и заменяем файлы с описанием главного окна программы (MainForm.Designer.cs и MainForm.cs) на вот такие:
Файл MainWindow.xaml
<?xml version="1.0" encoding="utf-8"?>
<Window x:Class="myProject.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Тестовое окно"
 Height="300"
 Width="400"
 >
    <Grid>
        <Button Height="35" Margin="8,8,8,8" Name="button1" VerticalAlignment="Top">Test</Button>
    </Grid>
</Window>
Файл MainWindow.xaml.cs
using System;
using System.Windows;

namespace myProject
{
 /// <summary>
 /// Логика работы окна MainWindow.xaml
 /// </summary>
 public partial class MainWindow : Window
 {
  public MainWindow()
  {
   InitializeComponent();
  }
 }
}
Эти изменения, разумеется, найдут своё отражение в файле проекта:
Файл project.csproj
<?xml version="1.0" encoding="utf-8"?>
<Project  xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">  

 <PropertyGroup>

  <!-- имя сборки -->
  <AssemblyName>main</AssemblyName>  

  <!-- в какую папку будет компилироваться сборка -->
  <OutputPath>bin\</OutputPath> 

  <OutputType>winexe</OutputType>
  <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>

 </PropertyGroup>  


 <ItemGroup>

  <Reference Include="System"/>
  <Reference Include="WindowsBase"/>
  <Reference Include="PresentationCore"/>
  <Reference Include="PresentationFramework"/>

  <ApplicationDefinition Include="Program.xaml"/>

  <Page Include="MainWindow.xaml"/>
  <Compile Include="MainWindow.xaml.cs"/>

 </ItemGroup>  


 <!-- вся магия на самом деле скрыта тут -->
 <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />

</Project>

Таким образом, можно вполне создавать оконные приложения .NET имея под рукой только блокнот. Не скажу, что этот вариант хоть в чем-то выигрывает по сравнению с IDE, но само наличие такой возможности не может не радовать.

Литература
Walkthrough: Creating an MSBuild Project File from Scratch
MSBuild

воскресенье, 27 мая 2018 г.

Ubuntu: отключить автомонтирование

С некоторых пор начало раздражать автомонтирование подключаемого жесткого диска. Есть подозрение, что это пытается услужить файловый менеджер Thunar.

К счастью, говорят, это можно отключить. В редакторе настроек (вызывается командой dconf-editor) нужно найти и снять соответствующие галочки в разделе /org/gnome/desktop/media-handling. Нашел. Снял. Посмотрю, поможет ли.

Литература
Mount/USB (Ubuntu documentation, Community Help Wiki)
Tip: Using UUID for mounting disks, the convenient way