分类目录归档:C#

C# .net framework不使用命令行或第三方库实现服务安装、卸载、停用,启用

网上资料通常都通过命令行调用sc.exe进行,这里介绍一种通过微软提供API实现的方法。代码更加简单,可控性更好。

使用方法

static void Main(string[] args)
{
    if (args.Length == 0) {
        // Run your service normally.
        ServiceBase[] ServicesToRun = new ServiceBase[] {new YourService()};
        ServiceBase.Run(ServicesToRun);
    } else if (args.Length == 1) {
        switch (args[0]) {
            case "-install":
                InstallService();
                StartService();
                break;
            case "-uninstall":
                StopService();
                UninstallService();
                break;
            default:
                throw new NotImplementedException();
        }
    }
}

ServiceControl 类

 public class ServiceControl
    {
        const string ServiceName = "MyService";

        public static bool IsInstalled()
        {
            using (ServiceController controller =
                new ServiceController(ServiceName))
            {
                try
                {
                    ServiceControllerStatus status = controller.Status;
                }
                catch
                {
                    return false;
                }
                return true;
            }
        }

        public static bool IsRunning()
        {
            using (ServiceController controller =
                new ServiceController(ServiceName))
            {
                if (!IsInstalled()) return false;
                return (controller.Status == ServiceControllerStatus.Running);
            }
        }

        public static AssemblyInstaller GetInstaller()
        {
            AssemblyInstaller installer = new AssemblyInstaller(
                typeof(MyService).Assembly, null);
            installer.UseNewContext = true;
            return installer;
        }

        public static void InstallService()
        {
            if (IsInstalled()) return;

            try
            {
                using (AssemblyInstaller installer = GetInstaller())
                {
                    IDictionary state = new Hashtable();
                    try
                    {
                        installer.Install(state);
                        installer.Commit(state);
                    }
                    catch
                    {
                        try
                        {
                            installer.Rollback(state);
                        }
                        catch { }
                        throw;
                    }
                }
            }
            catch
            {
                throw;
            }
        }

        public static void UninstallService()
        {
            if (!IsInstalled()) return;
            try
            {
                using (AssemblyInstaller installer = GetInstaller())
                {
                    IDictionary state = new Hashtable();
                    try
                    {
                        installer.Uninstall(state);
                    }
                    catch
                    {
                        throw;
                    }
                }
            }
            catch
            {
                throw;
            }
        }

        public static void StartService()
        {
            if (!IsInstalled()) return;

            using (ServiceController controller =
                new ServiceController(ServiceName))
            {
                try
                {
                    if (controller.Status != ServiceControllerStatus.Running)
                    {
                        controller.Start();
                        controller.WaitForStatus(ServiceControllerStatus.Running,
                            TimeSpan.FromSeconds(10));
                    }
                }
                catch
                {
                    throw;
                }
            }
        }

        public static void StopService()
        {
            if (!IsInstalled()) return;
            using (ServiceController controller =
                new ServiceController(ServiceName))
            {
                try
                {
                    if (controller.Status != ServiceControllerStatus.Stopped)
                    {
                        controller.Stop();
                        controller.WaitForStatus(ServiceControllerStatus.Stopped,
                             TimeSpan.FromSeconds(10));
                    }
                }
                catch
                {
                    throw;
                }
            }
        }
    }

参考

使用AutoUpdater.NET实现WPF和Winfoms项目自动更新

使用AutoUpdater.NET实现自动更新

AutoUpdater.NET是一个.net库,允许winforms和wpf应用实现自动更新,只需要以下几步:

1,定义一个升级文件;

<?xml version="1.0" encoding="UTF-8"?>
<item>
    <version>2.0.0.0</version>
    <url>http://rbsoft.org/downloads/AutoUpdaterTest.zip</url>
    <changelog>https://github.com/ravibpatel/AutoUpdater.NET/releases</changelog>
    <mandatory>false</mandatory>
</item>

2, 安装 Autoupdater.NET.Official扩展

PM> Install-Package Autoupdater.NET.Official

3,使用只需要在程序加载前加入以下代码即可

    protected override void OnStartup(StartupEventArgs e)
        {
            AutoUpdater.ParseUpdateInfoEvent += AutoUpdaterOnParseUpdateInfoEvent;
            //AutoUpdater.ReportErrors = true;
            AutoUpdater.Start("https://api.yunyin.la/file-helper/upgrade");
        }

将xml修改为json

        private void AutoUpdaterOnParseUpdateInfoEvent(ParseUpdateInfoEventArgs args)
        {
            dynamic json = JsonConvert.DeserializeObject(args.RemoteData);
            args.UpdateInfo = new UpdateInfoEventArgs
            {
                CurrentVersion = json.version,
                DownloadURL = json.url,
                Mandatory = new Mandatory
                {
                    Value = json.mandatory.value,
                    UpdateMode = json.mandatory.mode,
                }
            };
        }

json样例

{
   "version":"2.0.0.0",
   "url":"http://rbsoft.org/downloads/AutoUpdaterTest.zip",
   "changelog":"https://github.com/ravibpatel/AutoUpdater.NET/releases",
   "mandatory":{
      "value":true,
      "minVersion": "2.0.0.0",
      "mode":1
   },
   "checksum":{
      "value":"E5F59E50FC91A9E52634FFCB11F32BD37FE0E2F1",
      "hashingAlgorithm":"SHA1"
   }
}

参考

WPF点击关闭按钮最小化到系统托盘

包含点击关闭按钮后最小化系统托盘,点击系统托盘图标后自动弹出窗口,点击托盘右键菜单退出


    public partial class MainWindow : Window
    {

        private readonly System.Windows.Forms.NotifyIcon nIcon = new System.Windows.Forms.NotifyIcon();

        public MainWindow()
        {
            InitializeComponent();
            initNotifyIcon();
        }

        private void initNotifyIcon()
        {
            nIcon.Visible = true;
            nIcon.Icon = new Icon("./favicon.ico");
            nIcon.Text = "测试程序";
            nIcon.MouseClick += new System.Windows.Forms.MouseEventHandler(show_Click);
            nIcon.ContextMenu = new System.Windows.Forms.ContextMenu();
            System.Windows.Forms.MenuItem show = new System.Windows.Forms.MenuItem("打开");
            show.Click += new EventHandler(show_Click);
            nIcon.ContextMenu.MenuItems.Add(show);
            System.Windows.Forms.MenuItem exit = new System.Windows.Forms.MenuItem("退出");
            exit.Click += new EventHandler(exit_Click);
            nIcon.ContextMenu.MenuItems.Add(exit);

        }

        private void exit_Click(object sender, EventArgs e)
        {
            Environment.Exit(0);
        }

        private void show_Click(object Sender, EventArgs e)
        {
            if (WindowState == WindowState.Minimized)
                WindowState = WindowState.Normal;
            Show();
            Activate();
        }

        protected override void OnStateChanged(EventArgs e)
        {
            if (WindowState == WindowState.Minimized) Hide();

            base.OnStateChanged(e);
        }

        protected override void OnClosing(CancelEventArgs e)
        {
            e.Cancel = true;
            Hide();
            base.OnClosing(e);
        }

    }

参考

WPF自定义滚动条(含windows和apple两种风格)

测试结构

    <Grid>
        <ListView  VerticalAlignment="Top" HorizontalAlignment="Stretch">
            <ListViewItem>
                <TextBlock Text="xxxx1"/>
            </ListViewItem>
            <ListViewItem>
                <TextBlock Text="xxxx2"/>
            </ListViewItem>
            <ListViewItem>
                <TextBlock Text="xxxx3"/>
            </ListViewItem>
            <ListViewItem>
                <TextBlock Text="xxxx4"/>
            </ListViewItem>
            <ListViewItem>
                <TextBlock Text="xxxx5"/>
            </ListViewItem>
            <ListViewItem>
                <TextBlock Text="xxxx6"/>
            </ListViewItem>
            <ListViewItem>
                <TextBlock Text="xxxx7"/>
            </ListViewItem>
            <ListViewItem>
                <TextBlock Text="xxxx8"/>
            </ListViewItem>
            <ListViewItem>
                <TextBlock Text="xxxx9"/>
            </ListViewItem>
            <ListViewItem>
                <TextBlock Text="xxxx10"/>
            </ListViewItem>
            <ListViewItem>
                <TextBlock Text="xxxx11"/>
            </ListViewItem>
            <ListViewItem>
                <TextBlock Text="xxxx12"/>
            </ListViewItem>
            <ListViewItem>
                <TextBlock Text="xxxx13"/>
            </ListViewItem>
            <ListViewItem>
                <TextBlock Text="xxxx14"/>
            </ListViewItem>
            <ListViewItem>
                <TextBlock Text="xxxx15"/>
            </ListViewItem>
            <ListViewItem>
                <TextBlock Text="xxxx16"/>
            </ListViewItem>
            <ListViewItem>
                <TextBlock Text="xxxx17"/>
            </ListViewItem>
            <ListViewItem>
                <TextBlock Text="xxxx18"/>
            </ListViewItem>
            <ListViewItem>
                <TextBlock Text="xxxx19"/>
            </ListViewItem>
            <ListViewItem>
                <TextBlock Text="xxxx20"/>
            </ListViewItem>
        </ListView>
    </Grid>

Windows 风格

file

<Style x:Key="ScrollBarLineButton"
       TargetType="{x:Type RepeatButton}">
  <Setter Property="SnapsToDevicePixels"
          Value="True" />
  <Setter Property="OverridesDefaultStyle"
          Value="true" />
  <Setter Property="Focusable"
          Value="false" />
  <Setter Property="Template">
    <Setter.Value>
      <ControlTemplate TargetType="{x:Type RepeatButton}">
        <Border x:Name="Border"
                Margin="1"
                CornerRadius="2"
                BorderThickness="1">
          <Border.BorderBrush>
            <LinearGradientBrush StartPoint="0,0"
                                 EndPoint="0,1">
              <LinearGradientBrush.GradientStops>
                <GradientStopCollection>
                  <GradientStop Color="{DynamicResource BorderMediumColor}"
                                Offset="0.0" />
                  <GradientStop Color="{DynamicResource BorderDarkColor}"
                                Offset="1.0" />
                </GradientStopCollection>
              </LinearGradientBrush.GradientStops>
            </LinearGradientBrush>
          </Border.BorderBrush>
          <Border.Background>
            <LinearGradientBrush StartPoint="0,0"
                                 EndPoint="0,1">
              <LinearGradientBrush.GradientStops>
                <GradientStopCollection>
                  <GradientStop Color="{DynamicResource ControlLightColor}"/>
                  <GradientStop Color="{DynamicResource ControlMediumColor}"
                                Offset="1.0" />
                </GradientStopCollection>
              </LinearGradientBrush.GradientStops>
            </LinearGradientBrush>
          </Border.Background>
          <VisualStateManager.VisualStateGroups>
            <VisualStateGroup x:Name="CommonStates">
              <VisualState x:Name="Normal" />
              <VisualState x:Name="MouseOver" />
              <VisualState x:Name="Pressed">
                <Storyboard>
                  <ColorAnimationUsingKeyFrames Storyboard.TargetName="Border"
                                                Storyboard.TargetProperty="(Panel.Background).
                    (GradientBrush.GradientStops)[1].(GradientStop.Color)">
                    <EasingColorKeyFrame KeyTime="0"
                                         Value="{StaticResource ControlPressedColor}" />
                  </ColorAnimationUsingKeyFrames>
                </Storyboard>
              </VisualState>
              <VisualState x:Name="Disabled">
                <Storyboard>
                  <ColorAnimationUsingKeyFrames Storyboard.TargetName="Arrow"
                                                Storyboard.TargetProperty="(Shape.Fill).
                    (SolidColorBrush.Color)">
                    <EasingColorKeyFrame KeyTime="0"
                                         Value="{StaticResource DisabledForegroundColor}" />
                  </ColorAnimationUsingKeyFrames>
                </Storyboard>
              </VisualState>
            </VisualStateGroup>
          </VisualStateManager.VisualStateGroups>
          <Path x:Name="Arrow"
                HorizontalAlignment="Center"
                VerticalAlignment="Center"
                Data="{Binding Content, 
            RelativeSource={RelativeSource TemplatedParent}}" >
              <Path.Fill>
                  <SolidColorBrush Color="{DynamicResource GlyphColor}"/>
              </Path.Fill>
          </Path>
        </Border>
      </ControlTemplate>
    </Setter.Value>
  </Setter>
</Style>

<Style x:Key="ScrollBarPageButton"
       TargetType="{x:Type RepeatButton}">
  <Setter Property="SnapsToDevicePixels"
          Value="True" />
  <Setter Property="OverridesDefaultStyle"
          Value="true" />
  <Setter Property="IsTabStop"
          Value="false" />
  <Setter Property="Focusable"
          Value="false" />
  <Setter Property="Template">
    <Setter.Value>
      <ControlTemplate TargetType="{x:Type RepeatButton}">
        <Border Background="Transparent" />
      </ControlTemplate>
    </Setter.Value>
  </Setter>
</Style>

<Style x:Key="ScrollBarThumb"
       TargetType="{x:Type Thumb}">
  <Setter Property="SnapsToDevicePixels"
          Value="True" />
  <Setter Property="OverridesDefaultStyle"
          Value="true" />
  <Setter Property="IsTabStop"
          Value="false" />
  <Setter Property="Focusable"
          Value="false" />
  <Setter Property="Template">
    <Setter.Value>
      <ControlTemplate TargetType="{x:Type Thumb}">
        <Border CornerRadius="2"
                Background="{TemplateBinding Background}"
                BorderBrush="{TemplateBinding BorderBrush}"
                BorderThickness="1" />
      </ControlTemplate>
    </Setter.Value>
  </Setter>
</Style>

<ControlTemplate x:Key="VerticalScrollBar"
                 TargetType="{x:Type ScrollBar}">
  <Grid>
    <Grid.RowDefinitions>
      <RowDefinition MaxHeight="18" />
      <RowDefinition Height="0.00001*" />
      <RowDefinition MaxHeight="18" />
    </Grid.RowDefinitions>
    <Border Grid.RowSpan="3"
            CornerRadius="2"
            Background="#F0F0F0" />
    <RepeatButton Grid.Row="0"
                  Style="{StaticResource ScrollBarLineButton}"
                  Height="18"
                  Command="ScrollBar.LineUpCommand"
                  Content="M 0 4 L 8 4 L 4 0 Z" />
    <Track x:Name="PART_Track"
           Grid.Row="1"
           IsDirectionReversed="true">
      <Track.DecreaseRepeatButton>
        <RepeatButton Style="{StaticResource ScrollBarPageButton}"
                      Command="ScrollBar.PageUpCommand" />
      </Track.DecreaseRepeatButton>
      <Track.Thumb>
        <Thumb Style="{StaticResource ScrollBarThumb}"
               Margin="1,0,1,0">
          <Thumb.BorderBrush>

            <LinearGradientBrush StartPoint="0,0"
                                 EndPoint="1,0">
              <LinearGradientBrush.GradientStops>
                <GradientStopCollection>
                  <GradientStop Color="{DynamicResource BorderLightColor}"
                                Offset="0.0" />
                  <GradientStop Color="{DynamicResource BorderDarkColor}"
                                Offset="1.0" />
                </GradientStopCollection>
              </LinearGradientBrush.GradientStops>
            </LinearGradientBrush>

          </Thumb.BorderBrush>
          <Thumb.Background>

            <LinearGradientBrush StartPoint="0,0"
                                 EndPoint="1,0">
              <LinearGradientBrush.GradientStops>
                <GradientStopCollection>
                  <GradientStop Color="{DynamicResource ControlLightColor}"
                                Offset="0.0" />
                  <GradientStop Color="{DynamicResource ControlMediumColor}"
                                Offset="1.0" />
                </GradientStopCollection>
              </LinearGradientBrush.GradientStops>
            </LinearGradientBrush>

          </Thumb.Background>
        </Thumb>
      </Track.Thumb>
      <Track.IncreaseRepeatButton>
        <RepeatButton Style="{StaticResource ScrollBarPageButton}"
                      Command="ScrollBar.PageDownCommand" />
      </Track.IncreaseRepeatButton>
    </Track>
    <RepeatButton Grid.Row="2"
                  Style="{StaticResource ScrollBarLineButton}"
                  Height="18"
                  Command="ScrollBar.LineDownCommand"
                  Content="M 0 0 L 4 4 L 8 0 Z" />
  </Grid>
</ControlTemplate>

<ControlTemplate x:Key="HorizontalScrollBar"
                 TargetType="{x:Type ScrollBar}">
  <Grid>
    <Grid.ColumnDefinitions>
      <ColumnDefinition MaxWidth="18" />
      <ColumnDefinition Width="0.00001*" />
      <ColumnDefinition MaxWidth="18" />
    </Grid.ColumnDefinitions>
    <Border Grid.ColumnSpan="3"
            CornerRadius="2"
            Background="#F0F0F0" />
    <RepeatButton Grid.Column="0"
                  Style="{StaticResource ScrollBarLineButton}"
                  Width="18"
                  Command="ScrollBar.LineLeftCommand"
                  Content="M 4 0 L 4 8 L 0 4 Z" />
    <Track x:Name="PART_Track"
           Grid.Column="1"
           IsDirectionReversed="False">
      <Track.DecreaseRepeatButton>
        <RepeatButton Style="{StaticResource ScrollBarPageButton}"
                      Command="ScrollBar.PageLeftCommand" />
      </Track.DecreaseRepeatButton>
      <Track.Thumb>
        <Thumb Style="{StaticResource ScrollBarThumb}"
               Margin="0,1,0,1">

          <Thumb.BorderBrush>

            <LinearGradientBrush StartPoint="0,0"
                                 EndPoint="1,0">
              <LinearGradientBrush.GradientStops>
                <GradientStopCollection>
                  <GradientStop Color="{DynamicResource BorderLightColor}"
                                Offset="0.0" />
                  <GradientStop Color="{DynamicResource BorderDarkColor}"
                                Offset="1.0" />
                </GradientStopCollection>
              </LinearGradientBrush.GradientStops>
            </LinearGradientBrush>

          </Thumb.BorderBrush>
          <Thumb.Background>

            <LinearGradientBrush StartPoint="0,0"
                                 EndPoint="0,1">
              <LinearGradientBrush.GradientStops>
                <GradientStopCollection>
                  <GradientStop Color="{DynamicResource ControlLightColor}"
                                Offset="0.0" />
                  <GradientStop Color="{DynamicResource ControlMediumColor}"
                                Offset="1.0" />
                </GradientStopCollection>
              </LinearGradientBrush.GradientStops>
            </LinearGradientBrush>

          </Thumb.Background>
        </Thumb>
      </Track.Thumb>
      <Track.IncreaseRepeatButton>
        <RepeatButton Style="{StaticResource ScrollBarPageButton}"
                      Command="ScrollBar.PageRightCommand" />
      </Track.IncreaseRepeatButton>
    </Track>
    <RepeatButton Grid.Column="2"
                  Style="{StaticResource ScrollBarLineButton}"
                  Width="18"
                  Command="ScrollBar.LineRightCommand"
                  Content="M 0 0 L 4 4 L 0 8 Z" />
  </Grid>
</ControlTemplate>

<Style x:Key="{x:Type ScrollBar}"
       TargetType="{x:Type ScrollBar}">
  <Setter Property="SnapsToDevicePixels"
          Value="True" />
  <Setter Property="OverridesDefaultStyle"
          Value="true" />
  <Style.Triggers>
    <Trigger Property="Orientation"
             Value="Horizontal">
      <Setter Property="Width"
              Value="Auto" />
      <Setter Property="Height"
              Value="18" />
      <Setter Property="Template"
              Value="{StaticResource HorizontalScrollBar}" />
    </Trigger>
    <Trigger Property="Orientation"
             Value="Vertical">
      <Setter Property="Width"
              Value="18" />
      <Setter Property="Height"
              Value="Auto" />
      <Setter Property="Template"
              Value="{StaticResource VerticalScrollBar}" />
    </Trigger>
  </Style.Triggers>
</Style>

需要的资源

<!--Control colors.-->
<Color x:Key="WindowColor">#FFE8EDF9</Color>
<Color x:Key="ContentAreaColorLight">#FFC5CBF9</Color>
<Color x:Key="ContentAreaColorDark">#FF7381F9</Color>

<Color x:Key="DisabledControlLightColor">#FFE8EDF9</Color>
<Color x:Key="DisabledControlDarkColor">#FFC5CBF9</Color>
<Color x:Key="DisabledForegroundColor">#FF888888</Color>

<Color x:Key="SelectedBackgroundColor">#FFC5CBF9</Color>
<Color x:Key="SelectedUnfocusedColor">#FFDDDDDD</Color>

<Color x:Key="ControlLightColor">White</Color>
<Color x:Key="ControlMediumColor">#FF7381F9</Color>
<Color x:Key="ControlDarkColor">#FF211AA9</Color>

<Color x:Key="ControlMouseOverColor">#FF3843C4</Color>
<Color x:Key="ControlPressedColor">#FF211AA9</Color>

<Color x:Key="GlyphColor">#FF444444</Color>
<Color x:Key="GlyphMouseOver">sc#1, 0.004391443, 0.002428215, 0.242281124</Color>

<!--Border colors-->
<Color x:Key="BorderLightColor">#FFCCCCCC</Color>
<Color x:Key="BorderMediumColor">#FF888888</Color>
<Color x:Key="BorderDarkColor">#FF444444</Color>

<Color x:Key="PressedBorderLightColor">#FF888888</Color>
<Color x:Key="PressedBorderDarkColor">#FF444444</Color>

<Color x:Key="DisabledBorderLightColor">#FFAAAAAA</Color>
<Color x:Key="DisabledBorderDarkColor">#FF888888</Color>

<Color x:Key="DefaultBorderBrushDarkColor">Black</Color>

<!--Control-specific resources.-->
<Color x:Key="HeaderTopColor">#FFC5CBF9</Color>
<Color x:Key="DatagridCurrentCellBorderColor">Black</Color>
<Color x:Key="SliderTrackDarkColor">#FFC5CBF9</Color>

<Color x:Key="NavButtonFrameColor">#FF3843C4</Color>

<LinearGradientBrush x:Key="MenuPopupBrush"
                     EndPoint="0.5,1"
                     StartPoint="0.5,0">
  <GradientStop Color="{DynamicResource ControlLightColor}"
                Offset="0" />
  <GradientStop Color="{DynamicResource ControlMediumColor}"
                Offset="0.5" />
  <GradientStop Color="{DynamicResource ControlLightColor}"
                Offset="1" />
</LinearGradientBrush>

<LinearGradientBrush x:Key="ProgressBarIndicatorAnimatedFill"
                     StartPoint="0,0"
                     EndPoint="1,0">
  <LinearGradientBrush.GradientStops>
    <GradientStopCollection>
      <GradientStop Color="#000000FF"
                    Offset="0" />
      <GradientStop Color="#600000FF"
                    Offset="0.4" />
      <GradientStop Color="#600000FF"
                    Offset="0.6" />
      <GradientStop Color="#000000FF"
                    Offset="1" />
    </GradientStopCollection>
  </LinearGradientBrush.GradientStops>
</LinearGradientBrush>

Apple风格

file

<!--Scrollbar Thumbs-->
<Style x:Key="ScrollThumbs" TargetType="{x:Type Thumb}">
<Setter Property="Template">
    <Setter.Value>
        <ControlTemplate TargetType="{x:Type Thumb}">
            <Grid x:Name="Grid">
                <Rectangle HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Width="Auto" Height="Auto" Fill="Transparent" />
                <Border x:Name="Rectangle1" CornerRadius="5" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Width="Auto" Height="Auto" Background="{TemplateBinding Background}" />
            </Grid>
            <ControlTemplate.Triggers>
                <Trigger Property="Tag" Value="Horizontal">
                    <Setter TargetName="Rectangle1" Property="Width" Value="Auto" />
                    <Setter TargetName="Rectangle1" Property="Height" Value="7" />
                </Trigger>
            </ControlTemplate.Triggers>
        </ControlTemplate>
    </Setter.Value>
</Setter>
</Style>
<!--ScrollBars-->
<Style x:Key="{x:Type ScrollBar}" TargetType="{x:Type ScrollBar}">
<Setter Property="Stylus.IsFlicksEnabled" Value="false" />
<Setter Property="Foreground" Value="#8C8C8C" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="Width" Value="8" />
<Setter Property="Template">
    <Setter.Value>
        <ControlTemplate TargetType="{x:Type ScrollBar}">
            <Grid x:Name="GridRoot" Width="8" Background="{TemplateBinding Background}">
                <Grid.RowDefinitions>
                    <RowDefinition Height="0.00001*" />
                </Grid.RowDefinitions>
                <Track x:Name="PART_Track" Grid.Row="0" IsDirectionReversed="true" Focusable="false">
                    <Track.Thumb>
                        <Thumb x:Name="Thumb" Background="{TemplateBinding Foreground}" Style="{DynamicResource ScrollThumbs}" />
                    </Track.Thumb>
                    <Track.IncreaseRepeatButton>
                        <RepeatButton x:Name="PageUp" Command="ScrollBar.PageDownCommand" Opacity="0" Focusable="false" />
                    </Track.IncreaseRepeatButton>
                    <Track.DecreaseRepeatButton>
                        <RepeatButton x:Name="PageDown" Command="ScrollBar.PageUpCommand" Opacity="0" Focusable="false" />
                    </Track.DecreaseRepeatButton>
                </Track>
            </Grid>
            <ControlTemplate.Triggers>
                <Trigger SourceName="Thumb" Property="IsMouseOver" Value="true">
                    <Setter Value="{DynamicResource ButtonSelectBrush}" TargetName="Thumb" Property="Background" />
                </Trigger>
                <Trigger SourceName="Thumb" Property="IsDragging" Value="true">
                    <Setter Value="{DynamicResource DarkBrush}" TargetName="Thumb" Property="Background" />
                </Trigger>
                <Trigger Property="IsEnabled" Value="false">
                    <Setter TargetName="Thumb" Property="Visibility" Value="Collapsed" />
                </Trigger>
                <Trigger Property="Orientation" Value="Horizontal">
                    <Setter TargetName="GridRoot" Property="LayoutTransform">
                        <Setter.Value>
                            <RotateTransform Angle="-90" />
                        </Setter.Value>
                    </Setter>
                    <Setter TargetName="PART_Track" Property="LayoutTransform">
                        <Setter.Value>
                            <RotateTransform Angle="-90" />
                        </Setter.Value>
                    </Setter>
                    <Setter Property="Width" Value="Auto" />
                    <Setter Property="Height" Value="8" />
                    <Setter TargetName="Thumb" Property="Tag" Value="Horizontal" />
                    <Setter TargetName="PageDown" Property="Command" Value="ScrollBar.PageLeftCommand" />
                    <Setter TargetName="PageUp" Property="Command" Value="ScrollBar.PageRightCommand" />
                </Trigger>
            </ControlTemplate.Triggers>
        </ControlTemplate>
    </Setter.Value>
</Setter>
</Style>

参考

如何获取和设置打印机私有驱动配置参数

大部分打印机都有自己的私有驱动,私有驱动的参数都是二进制的,无法被识别,但是还是可以通过一些办法获取和保存。

参考

Windows自动化打印Office文件(Word,PDF,Excel,PPT等)

Windows(C++)

WPF(.net C#)

打印机自助打印代码(队列监控拦截+取消+状态获取)(附C#,C++,VB实现)

Monitor jobs in a printer queue (.NET)

https://www.codeproject.com/Articles/51085/Monitor-jobs-in-a-printer-queue-NET

c# 完整代码展示了如何获取打印机任务状态

file

Print Spooler API

https://docs.microsoft.com/zh-cn/windows/win32/printdocs/print-spooler-api

The Print Spooler API provides an interface to the print spooler for applications to manage printers and print jobs.

The Print Spooler API is used by an application as part of its programming and not directly by end users.

PrintQueue.GetPrintJobInfoCollection Method

Creates a collection that contains a PrintSystemJobInfo object for each job in the queue.

https://docs.microsoft.com/en-us/dotnet/api/system.printing.printqueue.getprintjobinfocollection?view=netframework-4.8

"Virtual Printer" or "Moving Printjobs" (C++)

https://cboard.cprogramming.com/windows-programming/108156-virtual-printer-moving-printjobs.html

Monitoring a Printer Queue from VB.NET

https://www.codeproject.com/Articles/3313/Monitoring-a-Printer-Queue-from-VB-NET

How to catch printer event in python

https://stackoverflow.com/questions/15748386/how-to-catch-printer-event-in-python

Printers and SafeHandles

https://www.codeproject.com/Articles/14690/Printers-and-SafeHandles

Printers and SafeHandles (Part 2)

https://www.codeproject.com/Articles/15084/Printers-and-SafeHandles-Part-2

C#实现自动打印PDF

采用PDFRender4NET

//打印机设置
PrinterSettings settings = new PrinterSettings();
settings.PrinterName = printername;
settings.PrintToFile = false;
settings.Copies = 1;
settings.PrintRange = PrintRange.AllPages;
//设置纸张大小(可以不设置取,取默认设置)
PaperSize ps = new PaperSize("Your Paper Name",595,842);
ps.RawKind = 9; //如果是自定义纸张,就要大于118

//打印设置
PDFRender.Printing.PDFPrintSettings pdfPrintSettings = new PDFRender.Printing.PDFPrintSettings(settings);
pdfPrintSettings.AutoRotate = false;            //自动旋转
pdfPrintSettings.BitmapPrintResolution = 560;   //图片打印精度                    
pdfPrintSettings.PaperSize = ps;                //纸张尺寸
pdfPrintSettings.PageScaling = PDFRender.Printing.PageScaling.FitToPrinterMarginsProportional;

pdfFile.Print(pdfPrintSettings);

代码详见: https://github.com/HiRaygo/DocumentPrint/blob/master/PdfPrint.cs

采用SumatraPDF或Acrobat Reader方案

 public static PrintEngine SumatraPDF = new PrintEngine("Sumatra PDF Reader",
            ((printerName, filePath, documentName) => 
            {
                string app = Path.Combine(Program.localPath, "SumatraPDF.exe");
                string args = string.Format("-silent -exit-on-print -print-to \"{0}\" \"{1}\"", printerName, filePath);

                Process p = new Process();
                p.StartInfo = new ProcessStartInfo()
                {
                    CreateNoWindow = true,
                    WindowStyle = ProcessWindowStyle.Hidden,
                    FileName = app,
                    Arguments = args
                };
                //if (User.isNetworkService())
                //{
                //    p.StartInfo.UserName = Program.config.serviceLogin;
                //    p.StartInfo.Password = tools.secureString(tools.Decrypt(Program.config.servicePass));
                //    p.StartInfo.Domain = Program.config.serviceDomain;
                //    p.StartInfo.LoadUserProfile = true;
                //    p.StartInfo.UseShellExecute = false;
                //}
                p.Start();

            })){};

        /// <summary>
        /// Print via external programm Acrobat Reader
        /// </summary>
        public static PrintEngine AcrobatReader = new PrintEngine("Acrobat Reader",
            ((printerName, filePath, documentName) =>
            {                
                string app = Registry.LocalMachine.OpenSubKey(
                        @"SOFTWARE\Microsoft\Windows\CurrentVersion" +
                        @"\App Paths\AcroRd32.exe"
                    ).GetValue("").ToString()
                ;
                string args = string.Format("/h /t \"{0}\" \"{1}\"", filePath, printerName);

                Process p = new Process();
                p.StartInfo = new ProcessStartInfo()
                {
                    CreateNoWindow = true,
                    WindowStyle = ProcessWindowStyle.Hidden,
                    FileName = app,
                    Arguments = args
                };
                //if (User.isNetworkService())
                //{

                //    p.StartInfo.UserName = Program.config.serviceLogin;
                //    p.StartInfo.Password = tools.secureString(tools.Decrypt(Program.config.servicePass));
                //    p.StartInfo.Domain = Program.config.serviceDomain;
                //    p.StartInfo.LoadUserProfile = true;
                //    p.StartInfo.UseShellExecute = false;
                //}
                p.Start();

})){};

代码详见: https://github.com/RepairShopr/AutoPrintr-win/blob/master/AutoPrintr/modules/PrintEngines.cs

Windows监控打印机任务实现付费打印

如何拦截打印任务

参考:

  • Intercept any print job and prompt for password.

    FindFirstPrinterChangeNotification()
    FindNextPrinterChangeNotification()
    if pdwChange = PRINTER_CHANGE_ADD_JOB you get the Job ID from PRINTER_NOTIFY_INFO_DATA
    You pause the Job with
    SetJob() and JOB_CONTROL_PAUSE
    You call your Dialog Box, then

    you resume the Job with
    SetJob() and JOB_CONTROL_RESUME
    or you cancel it with
    SetJob() and JOB_CONTROL_DELETE

  • Monitor jobs in a printer queue (.NET)

    There is a lot of code available in the internet (CodeProject as well as other sites) about the API calls to do print spool monitoring. However, I was not able to find any code that would help the user to enable monitoring one or more print queues with minimal code changes. So, I created a class (PrintQueueMonitor) that would allow the user to monitor the print queue for job changes and raise an event as and when jobs get added to the queue or job status gets changed in the queue.

C#编写的可供PHP调用的com dll(Visual studio 2017)

新增类库项目

依次选择“文件”》“新建”》“项目”,然后选择“类库(.net framework)”

添加引用

在“解决方案资源管理器”的“引用”点击鼠标右键,才程序集中搜索“InteropServices”,勾选“System.Runtime.InteropServices”

com可见

在“解决方案资源管理器”的项目名称上点击鼠标右键,选择“属性”,然后在“应用程序”面板选择“程序集信息”,勾选“使程序集COM可见”

签名

在“解决方案资源管理器”的项目名称上点击鼠标右键,选择“属性”,然后在“签名”面板勾选“为程序集签名”,然后在下拉菜单选择“新建”,输入“签名文件名称”,取消“使用密码保护密钥文件”勾选,点击确认

创建程序

using System.Runtime.InteropServices;

namespace HelloWorld
{ 
    [ComVisible(true)]
    public class Say
    {
        public string Hello()
        {
            return "Hello World";
        }
    }
}

发布dll

点击主菜单“生成”》“生成解决方案”(或者按F6)

注册com

按键盘上的win键,打开开始菜单,输入”vs”搜索,鼠标右键点击”VS 2017开发人员命令提示符”,选择用管理员身份打开;

进入生成的dll目录(通常在项目的bin/release目录下)

cd d:/helloworld/bin/release
regasm HelloWord.dll
gacutil /i HelloWord.dll

PHP调用com

<?php  
$r=new Com("HelloWorld.Say");  
$s=$r->Hello();  
echo $s;

调用出现Uncaught com_exception: Failed to create COM object

http://www.drupalonwindows.com/en/blog/calling-net-framework-and-net-assemblies-php