• CDTray, 打开,关闭光驱的系统托盘程序


    今天买了一台内置刻录机,安装完成后发现机箱提供的面板设计不太合理:光驱门打开后,按钮就根本没有用了,因为它附着在门上,与光驱本身提供的开仓按钮根本连不上了,于是我只能用手推动光盘托才能把光驱门给关上. 

    郁闷之余,写了一个小工具来解决这个问题:

    最核心的东西--开关光驱门,其实很简单:

    Code
            public static void Open(string driveLetter)
            {
                
    string returnString = "";
                mciSendStringA(
    "set cdaudio!" + driveLetter + " door open", returnString, 00);
            }

            
    public static void Close(string driveLetter)
            {
                
    string returnString = "";
                mciSendStringA(
    "set cdaudio!" + driveLetter + " door closed", returnString, 00);
            }

            [DllImport(
    "winmm.dll", EntryPoint = "mciSendStringA")]
            
    public static extern void mciSendStringA(string lpstrCommand, string lpstrReturnString, long uReturnLength, long hwndCallback);

    上面的代码是从网上搜索得到的.我本来想判断一下光驱本身的状态--是开还是关,但是搜索了十来分钟,没找到相关资料,觉得这个也不是特别有必要,于是放弃了.

    好了,下面就要获取系统里所有光驱了,其实很简单,一行代码就搞定:

    Code
            public static string[] GetCDRoms()
            {
                
    return DriveInfo.GetDrives().Where(x => x.DriveType == DriveType.CDRom).Select(x => x.Name).ToArray();
            }

    为了让程序用起来更方便,我希望它能设置为随Windows自动启动.这个也没什么困难的,就是操作注册表而已,于是我从原来写的代码里扒出了一段,重新加工了一下:

    Code
        class AutoLaunch
        {
            
    string registryKey;

            
    public AutoLaunch(string registryKey)
            {
                
    this.registryKey = registryKey;
            }

            
    string GetRunningExePath()
            {
                
    return Application.ExecutablePath;
            }

            
    public bool Enabled
            {
                
    get
                {
                    
    try
                    {
                        RegistryKey key 
    = Registry.CurrentUser.OpenSubKey("Software");
                        key 
    = key.OpenSubKey("Microsoft");
                        key 
    = key.OpenSubKey("Windows");
                        key 
    = key.OpenSubKey("CurrentVersion");
                        key 
    = key.OpenSubKey("Run"true);

                        
    string cmdline = key.GetValue(registryKey) as string;
                        
    if (cmdline == null)
                        {
                            
    return false;
                        }
                        
    else
                        {
                            
    if (!string.Equals(cmdline, GetRunningExePath(), StringComparison.OrdinalIgnoreCase))
                                key.SetValue(registryKey, GetRunningExePath());
                            
    return true;
                        }
                    }
                    
    catch (NullReferenceException)
                    {
                        
    return false;
                    }
                }
                
    set
                {
                    RegistryKey key 
    = Registry.CurrentUser.OpenSubKey("Software");
                    key 
    = key.OpenSubKey("Microsoft");
                    key 
    = key.OpenSubKey("Windows");
                    key 
    = key.OpenSubKey("CurrentVersion");
                    key 
    = key.OpenSubKey("Run"true);

                    
    if (value)
                    {
                        key.SetValue(registryKey, GetRunningExePath());
                    }
                    
    else
                    {
                        key.DeleteValue(registryKey, 
    false);
                    }
                }
            }

        }

    好了,现在可以做界面了.由于程序非常的简单,我选择了使用Windows Forms,而且决定一个窗口都不要,用户能看到的全部界面就是通知区域的一个图标.

    那好的,在一个空白的Form上扔一个NotifyIcon,和一个ContextMenuStrip,并把NotifyIcon的ContextMenuStrip属性设置好.

    然后就是我们的代码了,用于在Form的构造时,动态生成菜单内容:

    Code
            AutoLaunch autoLaunch;
            
    public Form1()
            {
                InitializeComponent();
                Init();
            }

            
    private void Init()
            {

                ShowInTaskbar 
    = false;
                WindowState 
    = FormWindowState.Minimized;
                autoLaunch 
    = new AutoLaunch("CDTool_deerchao");

                LoadMenu();
            }
    Code
            private void LoadMenu()
            {
                var menuItems 
    = new List<ToolStripItem>();

                menuItems.Add(
    new ToolStripMenuItem
                {
                    Text 
    = "By deerchao",
                });
                menuItems.Add(
    new ToolStripSeparator());

                
    foreach (var cd in CDDrive.GetCDRoms())
                {
                    menuItems.AddRange(LoadMenu(cd).Cast
    <ToolStripItem>());

                    menuItems.Add(
    new ToolStripSeparator());
                }

                var autoStart 
    = new ToolStripMenuItem("&Start with Windows"null, (s, e) => autoLaunch.Enabled = ((ToolStripMenuItem)s).Checked)
                {
                    CheckOnClick 
    = true,
                    Checked 
    = autoLaunch.Enabled,
                };

                var exit 
    = new ToolStripMenuItem("E&xit"null, (s, e) => Application.Exit());
                menuItems.Add(autoStart);
                menuItems.Add(exit);

                contextMenu.Items.AddRange(menuItems.ToArray());
            }

            
    private IEnumerable<ToolStripMenuItem> LoadMenu(string cd)
            {
                var open 
    = new ToolStripMenuItem("&Open " + cd.Substring(02), null, (s, e) => CDDrive.Open(cd));
                var close 
    = new ToolStripMenuItem("&Close " + cd.Substring(02), null, (s, e) => CDDrive.Close(cd));

                
    yield return open;
                
    yield return close;
            }

    很好,现在运行起来就一切OK了.

    但是,追求完美的我们怎么会如此轻易罢休呢..我们可以看到,代码里多处用到了Linq扩展方法,比如Where, Cast, Select, ToArray等. 而Linq则是.Net 3.5里才有的新东西..那意味着这个程序的用户,要去下载200多M的.Net 3.5安装程序,然后花两个小时来安装它,最后才能使用这个不到200K的小工具...

    怎么办?打造山塞版的Linq吧,还好,我们使用到的Linq特性并不多,只要几十行代码就能完成:

    Code
    using System.Collections;
    using System.Collections.Generic;

    namespace System.Linq
    {
        
    delegate TResult Func<TSource, TResult>(TSource source);

        
    static class Enumerable
        {
            
    public static IEnumerable<T> Where<T>(this IEnumerable<T> source, Predicate<T> predict)
            {
                
    foreach (var v in source)
                    
    if (predict(v))
                        
    yield return v;
            }

            
    public static IEnumerable<TDest> Cast<TDest>(this IEnumerable source)
            {
                
    foreach (var v in source)
                    
    yield return (TDest)v;
            }

            
    public static IEnumerable<TResult> Select<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> mapping)
            {
                
    foreach (var v in source)
                    
    yield return mapping(v);
            }

            
    public static List<T> ToList<T>(this IEnumerable<T> source)
            {
                
    return new List<T>(source);
            }

            
    public static T[] ToArray<T>(this IEnumerable<T> source)
            {
                
    return ToList(source).ToArray();
            }
        }

    }

    namespace System.Runtime.CompilerServices
    {
        
    class ExtensionAttribute : Attribute
        {
        }
    }

    OK,把针对的.Net Framework版本改成2.0,砍掉不必要的引用项,重新编译,搞定!

    现在唯一让我不爽的就是没有一个好图标了...好吧,我们从微软那里借一个来吧.操起刚Google来的图标编辑工具IcoFx,在File\Extract里选择C:\Windows\System32\imagers.dll,从里边挑选一个光盘图标,保存.

    在项目里设置好图标以后,重新编译,That's All!

    你可以从这里下载全部源代码.

  • 相关阅读:
    水晶报表 VS2010 应用
    crystalreport使用方法
    spring MVC核心思想
    一台服务器配置多个TOMCAT
    SQL server索引
    锁机制
    JAVA书籍
    Live 直播过程
    html5 video微信浏览器视频不能自动播放
    设计模式 抽象工厂模式
  • 原文地址:https://www.cnblogs.com/deerchao/p/1405552.html
Copyright © 2020-2023  润新知