























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

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

最核心的东西--开关光驱门,其实很简单:
Code
public static void Open(string driveLetter)
{
string returnString = "";
mciSendStringA("set cdaudio!" + driveLetter + " door open", returnString, 0, 0);
}public static void Close(string driveLetter)
{
string returnString = "";
mciSendStringA("set cdaudio!" + driveLetter + " door closed", returnString, 0, 0);
}
[DllImport(
"winmm.dll", EntryPoint = "mciSendStringA")]上面的代码是从网上搜索得到的.我本来想判断一下光驱本身的状态--是开还是关,但是搜索了十来分钟,没找到相关资料,觉得这个也不是特别有必要,于是放弃了.
好了,下面就要获取系统里所有光驱了,其实很简单,一行代码就搞定:
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; LoadMenu();
}
Code
private void LoadMenu()
{
var menuItems = new List<ToolStripItem>();
menuItems.Add(
new ToolStripMenuItemmenuItems.Add(
new ToolStripSeparator());var autoStart
= new ToolStripMenuItem("&Start with Windows", null, (s, e) => autoLaunch.Enabled = ((ToolStripMenuItem)s).Checked)var exit
= new ToolStripMenuItem("E&xit", null, (s, e) => Application.Exit()); contextMenu.Items.AddRange(menuItems.ToArray());
}
很好,现在运行起来就一切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.CompilerServicesOK,把针对的.Net Framework版本改成2.0,砍掉不必要的引用项,重新编译,搞定!
现在唯一让我不爽的就是没有一个好图标了...好吧,我们从微软那里借一个来吧.操起刚Google来的图标编辑工具IcoFx,在File\Extract里选择C:\Windows\System32\imagers.dll,从里边挑选一个光盘图标,保存.
在项目里设置好图标以后,重新编译,That's All!
你可以从这里下载全部源代码.
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。