| 雷's profileAbbeyGong's SpacesPhotosBlog | Help |
|
AbbeyGong's Spaces梦想离欲望远一点,快乐靠自己近一点! 4/26/2009 C#读取修改配制文件(Framework2.0)在VS 2005中设置和读取配置文件已经变的很简单了,而且是强类型的,读取的值可以直接赋值给相应的变量,无需强制转换。 // 读取设置 3. 保存 User 范围配置文件(保存 User 范围的应用程序设置) // 保存 User 范围的设置 User 范围配置文件没有保存在应用程序文件夹下,而是保存在这里:X:\Documents and Settings\Windows登录用户\Local Settings\Application Data。 // 保存 Applicationi 范围的设置 顺便说一下:使用 Properties.Settings.Default.Reset() 可以恢复 User 范围设置的默认值(从 app.config 中恢复)。 转自:http://www.cnblogs.com/anjou/archive/2007/03/27/690465.html 这下面两个方法也类似,摘抄下来做个备份学习: private void SaveConfig(string ConnenctionString) 2/18/2009 tor + privoxyTor用户在本机运行一个洋葱代理服务器(onion proxy),这个代理周期性地与其他Tor交流,从而在Tor网络中构成虚拟环路(virtual circuit)。 Tor是在7层protocol stack中的application layer进行加密(也就是按照'onion'的模式)而它之所以被称为onion是因为它的结构就跟洋葱相同,你只能看出它的外表而想要看到核心就必须把它层层的剥开。即每个router间的传输都经过symmetric key来加密,形成有层次的结构。它中间所经过的各节点,都好像洋葱的一层皮,把客户端包在里面,算是保护信息来源的一种方式,这样在洋葱路由器之间可以保持通讯安全。同时对于客户端,洋葱代理服务器又作为SOCKS接口。一些应用程序就可以将Tor作为代理服务器,网络通讯就可以通过Tor的虚拟环路来进行。进入Tor网络后,加密信息在路由器间传递,最后到达“退出节点”(exit node),明文数据从这个节点直接发往原来的目的地。对于目的主机而言,是从“退出节点”发来信息。由于在TCP数据流的级别通讯,Tor显得卓然独立于其他匿名网络。通过使用Tor,一般的应用程序都可以实现匿名,比如IRC、即时通讯,以及浏览网页。浏览网页时,Tor常常与Privoxy联合使用,Privoxy是一个代理服务器,可以在应用层增加保护隐私。 其实明白这个就好:Privoxy是支持HTTP、SOCKS代理以及HTTP转换为SOCKS代理,Tor支持SOCKS。所以要通过tor浏览就要通过Privoxy的HTTP转SOCKS。也可以只使用Privoxy上网,相当于过滤,其过滤功能也很突出,如果会用的话,各种广告、弹出窗口啊都可以过滤,超强的说。 注意几点: 1、Privoxy里面要设置协议转换:forward-socks4a / localhost:9050 .。后面一点不能漏掉。因为原始格式是forward-socks4a / socks_proxy[:port] http_parent[:port]。最后那一点是http_parent[:port],表示直接连接,也可以再加上了个HTTP代理来跳转。 2、Privoxy里面可以关掉日志记录,不然每一个连接都会记录下来,在配置里面屏蔽以下两行即可。 #logfile privoxy.log #jarfile jar.log 2/8/2009 解决WGA(xp)、OGA方法(office2003)
最新可以用的Windows和Office序列号
2/5/2009 [案例分析]用博弈论解5海盗分100宝石问题 5个海盗抢到了100颗宝石,每一颗都一样的大小和价值连城。他们决定这么分: 10/27/2008 [案例分析]震惊全国的“四年赚十亿的惊人内幕”(转载)《智囊》杂志曾经登过一篇文章:“‘空手道’四年赚十亿元方案”,我们来看看他们是怎样设计的,对我们有什么启发? 9/24/2008 什么是美国次贷危机,看后你就明了在美国,贷款是非常普遍的现象,从房子到汽车,从信用卡到电话账单,贷款无处不在。当地人很少全款买房,通常都是长时间贷款。可是我们也知道,在这里失业和再就业是很常见的现象。这些收入并不稳定甚至根本没有收入的人,他们怎么买房呢?因为信用等级达不到标准,他们就被定义为次级贷款者。 (注:Credit Default Swap,信用违约交换)好了,华尔街就是这些天才产品的床:不是都觉得原来的CDO风险高吗,那我投保好了,每年从CDO里面拿出一部分钱作为保金,白送给保险公司,但是将来出了风险,大家一起承担。 9/19/2008 “老头子,我要走了,抱抱我吧。”老太太醒过来了,心脏跳的忽快忽慢的,让她有些吃不消了。 9/17/2008 sqlserver 提取一定范围记录select top N * from table 9/13/2008 MCP68 主板开启AHCI模式攻略1、在SATA普通状态安装Windows XP(或Windows 2003)。 9/6/2008 英文地址翻译翻译原则:先小后大。 9/3/2008 动态链接库什么是动态链接库?DLL三个字母对于你来说一定很熟悉吧,它是Dynamic Link Library 的缩写形式,动态链接库 (DLL) 是作为共享函数库的可执行文件。动态链接提供了一种方法,使进程可以调用不属于其可执行代码的函数。函数的可执行代码位于一个 DLL 中,该 DLL 包含一个或多个已被编译、链接并与使用它们的进程分开存储的函数。DLL 还有助于共享数据和资源。多个应用程序可同时访问内存中单个 DLL 副本的内容。 和大多数程序员一样,你一定很使用过DLL吧。也曾感受到它的带给你程序设计和编码上的好错吧今天我想和大家探讨一个主题:如何在C#创建和调用DLL(动态链接库), 其实在很大意义上而讲,DLL让我更灵活的组织编写我们的应用程序,作为软件设计者,可一个根据它来达到很高的代码重用效果。下面我来介绍一下在C#中如何创建和调用DLL。 二、准备工作 我们需要对我们接下来要做的事情做个简单的介绍,在本文我们将利用C#语言创建一个名为 MyDLL.DLL的动态链接库,在这个动态链接库文件中我们将提供两个功能一个是对两个参数交换他们的值,另一个功能是求两个参数的最大公约数。然后创建一个应用程序使用这个DLL。运行并输出结果。 三、创建DLL 让我们创建以下三个C#代码文件: 1、 MySwap.cs using System; namespace MyMethods { public class SwapClass { public static bool Swap(ref long i,ref long j) { i = i+j; j = i-j; i = i-j; return true; } } } 2、 MyMaxCD.cs using System; namespace MyMethods { public class MaxCDClass { public static long MaxCD(long i, long j) { long a,b,temp; if(i>j) { a = i; b = j; } else { b = i; a = j; } temp = a % b; while(temp!=0) { a = b; b = temp; temp = a % b; } return b; } } } }需要注意的是:我们在制作这两个文件的时候可以用Visual Studio.NET或者其他的文本编辑器,就算是记事本也可以。这两个文件虽然不在同一个文件里面,但是他们是属于同一个namespace(名称空间)这对以后我们使用这两个方法提供了方便。当然他们也可以属于不同的名称空间,这是完全可以的,但只是在我们应用他们的时候就需要引用两个不同的名称空间,所以作者建议还是写在一个名称空间下面比较好。 using MyMethods; //这里我们引用刚才定义的名称空间,如果刚才的两个文件我们写在两个不同的名称空间 { public static void Main(string[] args) { if (args.Length != 2) { Console.WriteLine("Usage: MyClient <num1> <num2>"); return; } long num1 = long.Parse(args[0]); long num2 = long.Parse(args[1]); SwapClass.Swap(ref num1,ref num2); // 请注意,文件开头的 using 指令使您得以在编译时使用未限定的类名来引用 DLL 方法 Console.WriteLine("The result of swap is num1 = {0} and num2 ={1}",num1, num2); long maxcd = MaxCDClass.MaxCD(num1,num2); Console.WriteLine("The MaxCD of {0} and {1} is {2}",num1, num2, maxcd); } } 若要生成可执行文件 MyClient.exe,请使用以下命令行: csc /out:MyClient.exe /reference:MyLibrary.DLL MyClient.cs /out 编译器选项通知编译器输出 EXE 文件并且指定输出文件名 (MyClient.exe)。/reference 编译器选项指定该程序所引用的 DLL 文件。 五、执行 若要运行程序,请输入 EXE 文件的名称,文件名的后面跟两个数字,例如: MyClient 123 456 六、输出 The result of s wap is num1 = 456 and num2 = 123 The MaxCD of 456 and 123 is 3 七、小结 动态链接具有下列优点: 节省内存和减少交换操作。很多进程可以同时使用一个 DLL,在内存中共享该 DLL 的一个副本。相反,对于每个用静态链接库生成的应用程序,Windows 必须在内存中加载库代码的一个副本。 c#调用DLL每种编程语言调用DLL的方法都不尽相同,在此只对用C#调用DLL的方法进行介绍。首先,您需要了解什么是托管,什么是非托管。一般可以认为:非托管代码主要是基于win 32平台开发的DLL,activeX的组件,托管代码是基于.net平台开发的。如果您想深入了解托管与非托管的关系与区别,及它们的运行机制,请您自行查找资料,本文件在此不作讨论。 (一) 调用DLL中的非托管函数一般方法 首先,应该在C#语言源程序中声明外部方法,其基本形式是: [DLLImport(“DLL文件”)] 修饰符 extern 返回变量类型 方法名称 (参数列表) 其中: DLL文件:包含定义外部方法的库文件。 修饰符: 访问修饰符,除了abstract以外在声明方法时可以使用的修饰符。 返回变量类型:在DLL文件中你需调用方法的返回变量类型。 方法名称:在DLL文件中你需调用方法的名称。 参数列表:在DLL文件中你需调用方法的列表。 注意:需要在程序声明中使用System.Runtime.InteropServices命名空间。 DllImport只能放置在方法声明上。 DLL文件必须位于程序当前目录或系统定义的查询路径中(即:系统环境变量中Path所设置的路径)。 返回变量类型、方法名称、参数列表一定要与DLL文件中的定义相一致。 若要使用其它函数名,可以使用EntryPoint属性设置,如: [DllImport("user32.dll", EntryPoint="MessageBoxA")] static extern int MsgBox(int hWnd, string msg, string caption, int type); 其它可选的 DllImportAttribute 属性: CharSet 指示用在入口点中的字符集,如:CharSet=CharSet.Ansi; SetLastError 指示方法是否保留 Win32"上一错误",如:SetLastError=true; ExactSpelling 指示 EntryPoint 是否必须与指示的入口点的拼写完全匹配,如:ExactSpelling=false; PreserveSig指示方法的签名应当被保留还是被转换, 如:PreserveSig=true; CallingConvention指示入口点的调用约定, 如:CallingConvention=CallingConvention.Winapi; 此外,关于“数据封送处理”及“封送数字和逻辑标量”请参阅其它一些文章[2]。 C#例子: 1. 启动VS.NET,新建一个项目,项目名称为“Tzb”,模板为“Windows 应用程序”。 2. 在“工具箱”的“ Windows 窗体”项中双击“Button”项,向“Form1”窗体中添加一个按钮。 3. 改变按钮的属性:Name为 “B1”,Text为 “用DllImport调用DLL弹出提示框”,并将按钮B1调整到适当大小,移到适当位置。 4. 在类视图中双击“Form1”,打开“Form1.cs”代码视图,在“namespace Tzb”上面输入“using System.Runtime.InteropServices;”,以导入该命名空间。 5. 在“Form1.cs[设计]”视图中双击按钮B1,在“B1_Click”方法上面使用关键字 static 和 extern 声明方法“MsgBox”,将 DllImport 属性附加到该方法,这里我们要使用的是“user32.dll”中的“MessageBoxA”函数,具体代码如下: [DllImport("user32.dll", EntryPoint="MessageBoxA")] static extern int MsgBox(int hWnd, string msg, string caption, int type); 然后在“B1_Click”方法体内添加如下代码,以调用方法“MsgBox”: MsgBox(0," 这就是用 DllImport 调用 DLL 弹出的提示框哦! "," 挑战杯 ",0x30); 6. 按“F5”运行该程序,并点击按钮B1,便弹出如下提示框:
(二) 动态装载、调用DLL中的非托管函数 在上面已经说明了如何用DllImport调用DLL中的非托管函数,但是这个是全局的函数,假若DLL中的非托管函数有一个静态变量S,每次调用这个函数的时候,静态变量S就自动加1。结果,当需要重新计数时,就不能得出想要的结果。下面将用例子说明: 1. DLL的创建 1) 启动Visual C++ 6.0; 2) 新建一个“Win32 Dynamic-Link Library”工程,工程名称为“Count”; 3) 在“Dll kind”选择界面中选择“A simple dll project”; 4) 打开Count.cpp,添加如下代码: // 导出函数,使用“ _stdcall ” 标准调用 extern "C" _declspec(dllexport)int _stdcall count(int init); int _stdcall count(int init) {//count 函数,使用参数 init 初始化静态的整形变量 S ,并使 S 自加 1 后返回该值 static int S=init; S++; return S; } 5) 按“F7”进行编译,得到Count.dll(在工程目录下的Debug文件夹中)。 2. 用DllImport调用DLL中的count函数 1) 打开项目“Tzb”,向“Form1”窗体中添加一个按钮。 2) 改变按钮的属性:Name为 “B2”,Text为 “用DllImport调用DLL中count函数”,并将按钮B1调整到适当大小,移到适当位置。 3) 打开“Form1.cs”代码视图,使用关键字 static 和 extern 声明方法“count”,并使其具有来自 Count.dll 的导出函数count的实现,代码如下: [DllImport("Count.dll")] static extern int count(int init); 4) 在“Form1.cs[设计]”视图中双击按钮B2,在“B2_Click”方法体内添加如下代码: MessageBox.Show(" 用 DllImport 调用 DLL 中的 count 函数, n 传入的实参为 0 ,得到的结果是: "+count(0).ToString()," 挑战杯 "); MessageBox.Show(" 用 DllImport 调用 DLL 中的 count 函数, n 传入的实参为 10 ,得到的结果是: "+count(10).ToString()+"n 结果可不是想要的 11 哦!!! "," 挑战杯 "); MessageBox.Show(" 所得结果表明: n 用 DllImport 调用 DLL 中的非托管 n 函数是全局的、静态的函数!!! "," 挑战杯 "); 5) 把Count.dll复制到项目“Tzb”的binDebug文件夹中,按“F5”运行该程序,并点击按钮B2,便弹出如下三个提示框:
第1个提示框显示的是调用“count(0)”的结果,第2个提示框显示的是调用“count(10)”的结果,由所得结果可以证明“用DllImport调用DLL中的非托管函数是全局的、静态的函数”。所以,有时候并不能达到我们目的,因此我们需要使用下面所介绍的方法:C#动态调用DLL中的函数。 3. C#动态调用DLL中的函数 因为C#中使用DllImport是不能像动态load/unload assembly那样,所以只能借助API函数了。在kernel32.dll中,与动态库调用有关的函数包括[3]: ①LoadLibrary(或MFC 的AfxLoadLibrary),装载动态库。 ②GetProcAddress,获取要引入的函数,将符号名或标识号转换为DLL内部地址。 ③FreeLibrary(或MFC的AfxFreeLibrary),释放动态链接库。 它们的原型分别是: HMODULE LoadLibrary(LPCTSTR lpFileName); FARPROC GetProcAddress(HMODULE hModule, LPCWSTR lpProcName); BOOL FreeLibrary(HMODULE hModule); 现在,我们可以用IntPtr hModule=LoadLibrary(“Count.dll”);来获得Dll的句柄,用IntPtr farProc=GetProcAddress(hModule,”_count@4”);来获得函数的入口地址。 但是,知道函数的入口地址后,怎样调用这个函数呢?因为在C#中是没有函数指针的,没有像C++那样的函数指针调用方式来调用函数,所以我们得借助其它方法。经过研究,发现我们可以通过结合使用System.Reflection.Emit及System.Reflection.Assembly里的类和函数达到我们的目的。为了以后使用方便及实现代码的复用,我们可以编写一个类。 1) dld类的编写: 1. 打开项目“Tzb”,打开类视图,右击“Tzb”,选择“添加”-->“类”,类名设置为“dld”,即dynamic loading dll 的每个单词的开头字母。 2. 添加所需的命名空间及声明参数传递方式枚举: using System.Runtime.InteropServices; // 用 DllImport 需用此命名空间 using System.Reflection; // 使用 Assembly 类需用此 命名空间 using System.Reflection.Emit; // 使用 ILGenerator 需用此命名空间 在“public class dld”上面添加如下代码声明参数传递方式枚举: /// <summary> /// 参数传递方式枚举 ,ByValue 表示值传递 ,ByRef 表示址传递 /// </summary> public enum ModePass { ByValue = 0x0001, ByRef = 0x0002 } 3. 声明LoadLibrary、GetProcAddress、FreeLibrary及私有变量hModule和farProc: /// <summary> /// 原型是 :HMODULE LoadLibrary(LPCTSTR lpFileName); /// </summary> /// <param name="lpFileName">DLL 文件名 </param> /// <returns> 函数库模块的句柄 </returns> [DllImport("kernel32.dll")] static extern IntPtr LoadLibrary(string lpFileName); /// <summary> /// 原型是 : FARPROC GetProcAddress(HMODULE hModule, LPCWSTR lpProcName); /// </summary> /// <param name="hModule"> 包含需调用函数的函数库模块的句柄 </param> /// <param name="lpProcName"> 调用函数的名称 </param> /// <returns> 函数指针 </returns> [DllImport("kernel32.dll")] static extern IntPtr GetProcAddress(IntPtr hModule, string lpProcName); /// <summary> /// 原型是 : BOOL FreeLibrary(HMODULE hModule); /// </summary> /// <param name="hModule"> 需释放的函数库模块的句柄 </param> /// <returns> 是否已释放指定的 Dll</returns> [DllImport("kernel32",EntryPoint="FreeLibrary",SetLastError=true)] static extern bool FreeLibrary(IntPtr hModule); /// <summary> /// Loadlibrary 返回的函数库模块的句柄 /// </summary> private IntPtr hModule=IntPtr.Zero; /// <summary> /// GetProcAddress 返回的函数指针 /// </summary> private IntPtr farProc=IntPtr.Zero; 4. 添加LoadDll方法,并为了调用时方便,重载了这个方法: /// <summary> /// 装载 Dll /// </summary> /// <param name="lpFileName">DLL 文件名 </param> public void LoadDll(string lpFileName) { hModule=LoadLibrary(lpFileName); if(hModule==IntPtr.Zero) throw(new Exception(" 没有找到 :"+lpFileName+"." )); } 若已有已装载Dll的句柄,可以使用LoadDll方法的第二个版本: public void LoadDll(IntPtr HMODULE) { if(HMODULE==IntPtr.Zero) throw(new Exception(" 所传入的函数库模块的句柄 HMODULE 为空 ." )); hModule=HMODULE; } 5. 添加LoadFun方法,并为了调用时方便,也重载了这个方法,方法的具体代码及注释如下: /// <summary> /// 获得函数指针 /// </summary> /// <param name="lpProcName"> 调用函数的名称 </param> public void LoadFun(string lpProcName) { // 若函数库模块的句柄为空,则抛出异常 if(hModule==IntPtr.Zero) throw(new Exception(" 函数库模块的句柄为空 , 请确保已进行 LoadDll 操作 !")); // 取得函数指针 farProc = GetProcAddress(hModule,lpProcName); // 若函数指针,则抛出异常 if(farProc==IntPtr.Zero) throw(new Exception(" 没有找到 :"+lpProcName+" 这个函数的入口点 ")); } /// <summary> /// 获得函数指针 /// </summary> /// <param name="lpFileName"> 包含需调用函数的 DLL 文件名 </param> /// <param name="lpProcName"> 调用函数的名称 </param> public void LoadFun(string lpFileName,string lpProcName) { // 取得函数库模块的句柄 hModule=LoadLibrary(lpFileName); // 若函数库模块的句柄为空,则抛出异常 if(hModule==IntPtr.Zero) throw(new Exception(" 没有找到 :"+lpFileName+"." )); // 取得函数指针 farProc = GetProcAddress(hModule,lpProcName); // 若函数指针,则抛出异常 if(farProc==IntPtr.Zero) throw(new Exception(" 没有找到 :"+lpProcName+" 这个函数的入口点 ")); } 6. 添加UnLoadDll及Invoke方法,Invoke方法也进行了重载: /// <summary> /// 卸载 Dll /// </summary> public void UnLoadDll() { FreeLibrary(hModule); hModule=IntPtr.Zero; farProc=IntPtr.Zero; } 用Visual C#调用Windows API函数Api函数是构筑Windws应用程序的基石,每一种Windows应用程序开发工具,它提供的底层函数都间接或直接地调用了Windows API函数,同时为了实现功能扩展,一般也都提供了调用WindowsAPI函数的接口, 也就是说具备调用动态连接库的能力。Visual C#和其它开发工具一样也能够调用动态链接库的API函数。.NET框架本身提供了这样一种服务,允许受管辖的代码调用动态链接库中实现的非受管辖函数,包括操作系统提供的Windows API函数。它能够定位和调用输出函数,根据需要,组织其各个参数(整型、字符串类型、数组、和结构等等)跨越互操作边界。 下面以C#为例简单介绍调用API的基本过程: 动态链接库函数的声明 动态链接库函数使用前必须声明,相对于VB,C#函数声明显得更加罗嗦,前者通过 Api Viewer粘贴以后,可以直接使用,而后者则需要对参数作些额外的变化工作。 动态链接库函数声明部分一般由下列两部分组成,一是函数名或索引号,二是动态链接库的文件名。 譬如,你想调用User32.DLL中的MessageBox函数,我们必须指明函数的名字MessageBoxA或MessageBoxW,以及库名字User32.dll,我们知道Win32 API对每一个涉及字符串和字符的函数一般都存在两个版本,单字节字符的ANSI版本和双字节字符的UNICODE版本。 下面是一个调用API函数的例子: [DllImport("KERNEL32.DLL", EntryPoint="MoveFileW", SetLastError=true, CharSet=CharSet.Unicode, ExactSpelling=true, CallingConvention=CallingConvention.StdCall)] public static extern bool MoveFile(String src, String dst); 其中入口点EntryPoint标识函数在动态链接库的入口位置,在一个受管辖的工程中,目标函数的原始名字和序号入口点不仅标识一个跨越互操作界限的函数。而且,你还可以把这个入口点映射为一个不同的名字,也就是对函数进行重命名。重命名可以给调用函数带来种种便利,通过重命名,一方面我们不用为函数的大小写伤透脑筋,同时它也可以保证与已有的命名规则保持一致,允许带有不同参数类型的函数共存,更重要的是它简化了对ANSI和Unicode版本的调用。CharSet用于标识函数调用所采用的是Unicode或是ANSI版本,ExactSpelling=false将告诉编译器,让编译器决定使用Unicode或者是Ansi版本。其它的参数请参考MSDN在线帮助. 在C#中,你可以在EntryPoint域通过名字和序号声明一个动态链接库函数,如果在方法定义中使用的函数名与DLL入口点相同,你不需要在EntryPoint域显示声明函数。否则,你必须使用下列属性格式指示一个名字和序号。 [DllImport("dllname", EntryPoint="Functionname")] [DllImport("dllname", EntryPoint="#123")] 值得注意的是,你必须在数字序号前加“#” 下面是一个用MsgBox替换MessageBox名字的例子: [C#] using System.Runtime.InteropServices; public class Win32 { [DllImport("user32.dll", EntryPoint="MessageBox")] public static extern int MsgBox(int hWnd, String text, String caption, uint type); } 许多受管辖的动态链接库函数期望你能够传递一个复杂的参数类型给函数,譬如一个用户定义的结构类型成员或者受管辖代码定义的一个类成员,这时你必须提供额外的信息格式化这个类型,以保持参数原有的布局和对齐。 C#提供了一个StructLayoutAttribute类,通过它你可以定义自己的格式化类型,在受管辖代码中,格式化类型是一个用StructLayoutAttribute说明的结构或类成员,通过它能够保证其内部成员预期的布局信息。布局的选项共有三种: 布局选项 描述 LayoutKind.Automatic 为了提高效率允许运行态对类型成员重新排序。 注意:永远不要使用这个选项来调用不受管辖的动态链接库函数。 LayoutKind.Explicit 对每个域按照FieldOffset属性对类型成员排序 LayoutKind.Sequential 对出现在受管辖类型定义地方的不受管辖内存中的类型成员进行排序。 传递结构成员 下面的例子说明如何在受管辖代码中定义一个点和矩形类型,并作为一个参数传递给User32.dll库中的PtInRect函数, 函数的不受管辖原型声明如下: BOOL PtInRect(const RECT *lprc, POINT pt); 注意你必须通过引用传递Rect结构参数,因为函数需要一个Rect的结构指针。 [C#] using System.Runtime.InteropServices; [StructLayout(LayoutKind.Sequential)] public struct Point { public int x; public int y; } [StructLayout(LayoutKind.Explicit] public struct Rect { [FieldOffset(0)] public int left; [FieldOffset(4)] public int top; [FieldOffset(8)] public int right; [FieldOffset(12)] public int bottom; } class Win32API { [DllImport("User32.dll")] public static extern Bool PtInRect(ref Rect r, Point p); } 类似你可以调用GetSystemInfo函数获得系统信息: ? using System.Runtime.InteropServices; [StructLayout(LayoutKind.Sequential)] public struct SYSTEM_INFO { public uint dwOemId; public uint dwPageSize; public uint lpMinimumApplicationAddress; public uint lpMaximumApplicationAddress; public uint dwActiveProcessorMask; public uint dwNumberOfProcessors; public uint dwProcessorType; public uint dwAllocationGranularity; public uint dwProcessorLevel; public uint dwProcessorRevision; } [DllImport("kernel32")] static extern void GetSystemInfo(ref SYSTEM_INFO pSI); SYSTEM_INFO pSI = new SYSTEM_INFO(); GetSystemInfo(ref pSI); 类成员的传递 同样只要类具有一个固定的类成员布局,你也可以传递一个类成员给一个不受管辖的动态链接库函数,下面的例子主要说明如何传递一个sequential顺序定义的MySystemTime类给User32.dll的GetSystemTime函数, 函数用C/C++调用规范如下: void GetSystemTime(SYSTEMTIME* SystemTime); 不像传值类型,类总是通过引用传递参数. [C#] [StructLayout(LayoutKind.Sequential)] public class MySystemTime { public ushort wYear; public ushort wMonth; public ushort wDayOfWeek; public ushort wDay; public ushort wHour; public ushort wMinute; public ushort wSecond; public ushort wMilliseconds; } class Win32API { [DllImport("User32.dll")] public static extern void GetSystemTime(MySystemTime st); } 回调函数的传递: 从受管辖的代码中调用大多数动态链接库函数,你只需创建一个受管辖的函数定义,然后调用它即可,这个过程非常直接。 如果一个动态链接库函数需要一个函数指针作为参数,你还需要做以下几步: 首先,你必须参考有关这个函数的文档,确定这个函数是否需要一个回调;第二,你必须在受管辖代码中创建一个回调函数;最后,你可以把指向这个函数的指针作为一个参数创递给DLL函数,. 回调函数及其实现: 回调函数经常用在任务需要重复执行的场合,譬如用于枚举函数,譬如Win32 API 中的EnumFontFamilies(字体枚举), EnumPrinters(打印机), EnumWindows (窗口枚举)函数. 下面以窗口枚举为例,谈谈如何通过调用EnumWindow 函数遍历系统中存在的所有窗口 分下面几个步骤: 1. 在实现调用前先参考函数的声明 BOOL EnumWindows(WNDENUMPROC lpEnumFunc, LPARMAM IParam) 显然这个函数需要一个回调函数地址作为参数. 2. 创建一个受管辖的回调函数,这个例子声明为代表类型(delegate),也就是我们所说的回调,它带有两个参数hwnd和lparam,第一个参数是一个窗口句柄,第二个参数由应用程序定义,两个参数均为整形。 当这个回调函数返回一个非零值时,标示执行成功,零则暗示失败,这个例子总是返回True值,以便持续枚举。 3. 最后创建以代表对象(delegate),并把它作为一个参数传递给EnumWindows 函数,平台会自动地 把代表转化成函数能够识别的回调格式。 [C#] using System; using System.Runtime.InteropServices; public delegate bool CallBack(int hwnd, int lParam); public class EnumReportApp { [DllImport("user32")] public static extern int EnumWindows(CallBack x, int y); public static void Main() { CallBack myCallBack = new CallBack(EnumReportApp.Report); EnumWindows(myCallBack, 0); } public static bool Report(int hwnd, int lParam) { Console.Write("窗口句柄为"); Console.WriteLine(hwnd); return true; } } 指针类型参数传递: 在Windows API函数调用时,大部分函数采用指针传递参数,对一个结构变量指针,我们除了使用上面的类和结构方法传递参数之外,我们有时还可以采用数组传递参数。 下面这个函数通过调用GetUserName获得用户名 BOOL GetUserName( LPTSTR lpBuffer, // 用户名缓冲区 LPDWORD nSize // 存放缓冲区大小的地址指针 ); [DllImport("Advapi32.dll", EntryPoint="GetComputerName", ExactSpelling=false, SetLastError=true)] static extern bool GetComputerName ( [MarshalAs(UnmanagedType.LPArray)] byte[] lpBuffer, [MarshalAs(UnmanagedType.LPArray)] Int32[] nSize ); 这个函数接受两个参数,char * 和int *,因为你必须分配一个字符串缓冲区以接受字符串指针,你可以使用String类代替这个参数类型,当然你还可以声明一个字节数组传递ANSI字符串,同样你也可以声明一个只有一个元素的长整型数组,使用数组名作为第二个参数。上面的函数可以调用如下: byte[] str=new byte[20]; Int32[] len=new Int32[1]; len[0]=20; GetComputerName (str,len); MessageBox.Show(System.Text.Encoding.ASCII.GetString(str)); 最后需要提醒的是,每一种方法使用前必须在文件头加上: using System.Runtime.InteropServices; 8/9/2008 sqlserver 只显示日期不显示时间try: 7/20/2008 微软的正则表达式教程(五):选择/编组和后向引用选择与编组选择允许使用 '|' 字符来在两个或多个候选项中进行选择。通过扩展章节标题的正则表达式,可以将其扩充为不仅仅适用于章节标题的表达式。不过,这可没有想象的那么直接。在使用选择时,将匹配'|' 字符每边最可能的表达式。你可能认为下面的 JScript 和 VBScript 表达式将匹配位于一行的开始和结束位置且后跟一个或两个数字的 'Chapter' 或 'Section':
不幸的是,真正的情况是上面所示的正则表达式要么匹配位于一行开始处的单词 'Chapter',要么匹配一行结束处的后跟任何数字的 'Section'。如果输入字符串为 'Chapter 22',上面的表达式将只匹配单词 'Chapter'。如果输入字符串为 'Section 22',则该表达式将匹配 'Section 22'。但这种结果不是我们此处的目的,因此必须有一种办法来使正则表达式对于所要做的更易于响应,而且确实也有这种方法。 可以使用圆括号来限制选择的范围,也就是说明确该选择只适用于这两个单词 'Chapter' 和 'Section'。不过,圆括号同样也是难处理的,因为它们也用来创建子表达式,有些内容将在后面关于子表达式的部分介绍。通过采用上面所示的正则表达式并在适当位置添加圆括号,就可以使该正则表达式既可以匹配 'Chapter 1',也可以匹配 'Section 3'。 下面的正则表达式使用圆括号将 'Chapter' 和 'Section' 组成一组,所以该表达式才能正确工作。对 JScript 为:
对 VBScript 为:
这些表达式工作正确,只是产生了一个有趣的副产品。在 'Chapter|Section' 两边放置圆括号建立了适当的编组,但也导致两个待匹配单词之一都被捕获供今后使用。由于在上面所示的表达式中只有一组圆括号,因此只能有一个捕获的 submatch。可以使用 VBScript 的Submatches 集合或者JScript 中RegExp 对象的 $1-$9 属性来引用这个子匹配。 有时捕获一个子匹配是所希望的,有时则是不希望的。在说明所示的示例中,真正想做的就是使用圆括号对单词 'Chapter' 或 'Section' 之间的选择编组。并不希望在后面再引用该匹配。实际上,除非真的是需要捕获子匹配,否则请不要使用。由于不需要花时间和内存来存储那些子匹配,这种正则表达式的效率将更高。 可以在正则表达式模式圆括号内部的前面使用 '?:'来防止存储该匹配供今后使用。对上面所示正则表达式的下述修改提供了免除子匹配存储的相同功能。对 JScript:
对 VBScript:
除了 '?:' 元字符,还有两个非捕获元字符用于称之为预查的匹配。一个为正向预查,用 ?= 表示, 在任何开始匹配圆括号内的正则表达式模式的位置来匹配搜索字符串。一个为负向预查,用 '?!' 表示,在任何开始不匹配该正则表达式模式的位置来匹配搜索字符串。 例如,假定有一个包含引用有 Windows 3.1、Windows 95、Windows 98 以及 Windows NT 的文档。进一步假设需要更新该文档,方法是查找所有对 Windows 95、Windows 98 以及 Windows NT 的引用,并将这些引用更改为 Windows 2000。可以使用下面的 JScript 正则表达式,这是一个正向预查,来匹配 Windows 95、Windows 98 以及 Windows NT:
在 VBScript 要进行同样的匹配可以使用下述表达式:
找到一个匹配后,紧接匹配到的文字(而不包括预查中使用的字符)就开始对下一次匹配的搜索。例如,如果上面所示的表达式匹配到 'Windows 98',则将从 'Windows' 而不是 '98' 之后继续查找。 后向引用正则表达式一个最重要的特性就是将匹配成功的模式的某部分进行存储供以后使用这一能力。请回想一下,对一个正则表达式模式或部分模式两边添加圆括号将导致这部分表达式存储到一个临时缓冲区中。可以使用非捕获元字符 '?:', '?=', or '?!' 来忽略对这部分正则表达式的保存。 所捕获的每个子匹配都按照在正则表达式模式中从左至右所遇到的内容存储。存储子匹配的缓冲区编号从 1 开始,连续编号直至最大 99 个子表达式。每个缓冲区都可以使用 '\n' 访问,其中 n 为一个标识特定缓冲区的一位或两位十进制数。 后向引用一个最简单,最有用的应用是提供了确定文字中连续出现两个相同单词的位置的能力。请看下面的句子:
根据所写内容,上面的句子明显存在单词多次重复的问题。如果能有一种方法无需查找每个单词的重复现象就能修改该句子就好了。下面的 JScript 正则表达式使用一个子表达式就可以实现这一功能。
等价的 VBScript 表达式为:
在这个示例中,子表达式就是圆括号之间的每一项。所捕获的表达式包括一个或多个字母字符,即由'[a-z]+' 所指定的。该正则表达式的第二部分是对前面所捕获的子匹配的引用,也就是由附加表达式所匹配的第二次出现的单词。'\1'用来指定第一个子匹配。单词边界元字符确保只检测单独的单词。如果不这样,则诸如 "is issued" 或 "this is" 这样的短语都会被该表达式不正确地识别。 在 JScript 表达式中,正则表达式后面的全局标志 ('g') 表示该表达式将用来在输入字符串中查找尽可能多的匹配。大小写敏感性由表达式结束处的大小写敏感性标记 ('i') 指定。多行标记指定可能出现在换行符的两端的潜在匹配。对 VBScript 而言,在表达式中不能设置各种标记,但必须使用 RegExp 对象的属性来显式设置。 使用上面所示的正则表达式,下面的 JScript 代码可以使用子匹配信息,在一个文字字符串中将连续出现两次的相同单词替换为一个相同的单词:
最接近的等价 VBScript 代码如下:
请注意在 VBScript 代码中,全局、大小写敏感性以及多行标记都是使用 RegExp 对象的适当属性来设置的。 在replace 方法中使用 $1 来引用所保存的第一个子匹配。如果有多个子匹配,则可以用 $2, $3 等继续引用。 后向引用的另一个用途是将一个通用资源指示符 (URI) 分解为组件部分。假定希望将下述的URI 分解为协议 (ftp, http, etc),域名地址以及页面/路径:
下面的正则表达式可以提供这个功能。对 JScript,为:
对 VBScript 为:
第一个附加子表达式是用来捕获该 web 地址的协议部分。该子表达式匹配位于一个冒号和两个正斜杠之前的任何单词。第二个附加子表达式捕获该地址的域名地址。该子表达式匹配不包括 '^'、 '/' 或 ':' 字符的任何字符序列。第三个附加子表达式捕获网站端口号码,如果指定了该端口号。该子表达式匹配后跟一个冒号的零或多个数字。最后,第四个附加子表达式捕获由该 web 地址指定的路径以及\或者页面信息。该子表达式匹配一个和多个除'#' 或空格之外的字符。 将该正则表达式应用于上面所示的 URI 后,子匹配包含下述内容: RegExp.$1 包含 "http" RegExp.$2 包含 "msdn.microsoft.com" RegExp.$3 包含 ":80" RegExp.$4 包含 "/scripting/default.htm" 微软的正则表达式教程(四):限定符和定位符限定符有时候不知道要匹配多少字符。为了能适应这种不确定性,正则表达式支持限定符的概念。这些限定符可以指定正则表达式的一个给定组件必须要出现多少次才能满足匹配。 下表给出了各种限定符及其含义的说明: 字符 * + ? {n} {n,} {n,m} 对一个很大的输入文档而言,章节数很轻易就超过九章,因此需要有一种方法来处理两位数或者三位数的章节号。限定符就提供了这个功能。下面的JScript 正则表达式可以匹配具有任何位数的章节标题:
下面的 VBScript 正则表达式执行同样的匹配:
请注意限定符出现在范围表达式之后。因此,它将应用于所包含的整个范围表达式,在本例中,只指定了从 0 到 9 的数字。 这里没有使用 '+' 限定符,因为第二位或后续位置上并不一定需要一个数字。同样也没有使用 '?' 字符,因为这将把章节数限制为只有两位数字。在 'Chapter' 和空格字符之后至少要匹配一个数字。 如果已知章节数限制只有99 章,则可以使用下面的 JScript 表达式来指定至少有一位数字,但不超过两个数字。
对 VBScript 可以使用下述正则表达式:
上述表达式的缺点是如果有一个章节号大于 99,它仍只会匹配前两位数字。另一个缺点是某些人可以创建一个 Chapter 0,而且仍能匹配。一个更好的用来匹配两位数的 JScript 表达式如下:
或者
对 VBScript 而言,下述表达式与上面等价:
或者
' 例如,你可能要搜索一个 HTML 文档来查找一处包含在 H1 标记中的章节标题。在文档中该文字可能具有如下形式:
下面的表达式匹配从开始的小于号 (<) 到 H1 标记结束处的大于号之间的所有内容。
VBScript 的正则表达式为:
如果所要匹配的就是开始的 H1 标记,则下述非贪婪地表达式就只匹配 <H1>。
或者
通过在 '*'、 '+' 或 '?' 限定符后放置 '?',该表达式就从贪婪匹配转为了非贪婪或最小匹配。 定位符到现在为止,所看到的示例都只考虑查找任何地方出现的章节标题。出现的任何一个字符串 'Chapter' 后跟一个空格和一个数字可能是一个真正的章节标题,也可能是对其他章节的交叉引用。由于真正的章节标题总是出现在一行的开始,因此需要设计一个方法只查找标题而不查找交叉引用。 定位符提供了这个功能。定位符可以将一个正则表达式固定在一行的开始或结束。也可以创建只在单词内或只在单词的开始或结尾处出现的正则表达式。下表包含了正则表达式及其含义的列表: 字符 ^ $ \b \B 不能对定位符使用限定符。因为在一个换行符或者单词边界的前面或后面不会有连续多个位置,因此诸如 '^*' 的表达式是不允许的。 要匹配一行文字开始位置的文字,请在正则表达式的开始处使用 '^' 字符。不要把 '^' 的这个语法与其在括号表达式中的语法弄混。它们的语法根本不同。 要匹配一行文字结束位置的文字,请在正则表达式的结束处使用 '$' 字符。 要在查找章节标题时使用定位符,下面的 JScript 正则表达式将匹配位于一行的开始处最多有两个数字的章节标题:
VBScript 中相同功能的正则表达式如下:
一个真正的章节标题不仅出现在一行的开始,而且这一行中也仅有这一个内容,因此,它必然也位于一行的结束。下面的表达式确保所指定的匹配只匹配章节而不会匹配交叉引用。它是通过创建一个只匹配一行文字的开始和结束位置的正则表达式来实现的。
对 VBScript 则使用:
匹配单词边界有少许不同,但却给正则表达式增加了一个非常重要的功能。单词边界就是单词和空格之间的位置。非单词边界就是其他任何位置。下面的 JScript 表达式将匹配单词 'Chapter' 的前三个字符,因为它们出现在单词边界后:
对 VBScript 为:
这里 '\b' 操作符的位置很关键。如果它位于要匹配的字符串的开始,则将查找位于单词开头处的匹配;如果它位于改字符串的末尾,则查找位于单词结束处的匹配。例如,下面的表达式将匹配单词 'Chapter' 中的 'ter',因为它出现在单词边界之前:
以及
下面的表达式将匹配 'apt',因为它位于 'Chapter' 中间,但不会匹配 'aptitude' 中的'apt':
以及
这是因为在单词 'Chapter' 中 'apt' 出现在非单词边界位置,而在单词 'aptitude' 中位于单词边界位置。非单词边界操作符的位置不重要,因为匹配与一个单词的开头或结尾无关。 微软的正则表达式教程(三):字符匹配普通字符普通字符由所有那些未显式指定为元字符的打印和非打印字符组成。这包括所有的大写和小写字母字符,所有数字,所有标点符号以及一些符号。 最简单的正则表达式是一个单独的普通字符,可以匹配所搜索字符串中的该字符本身。例如,单字符模式 'A' 可以匹配所搜索字符串中任何位置出现的字母 'A'。这里有一些单字符正则表达式模式的示例:
等价的 VBScript 单字符正则表达式为:
可以将多个单字符组合在一起得到一个较大的表达式。例如,下面的 JScript 正则表达式不是别的,就是通过组合单字符表达式 'a'、'7'以及 'M' 所创建出来的一个表达式。
等价的 VBScript 表达式为:
请注意这里没有连接操作符。所需要做的就是将一个字符放在了另一个字符后面。 特殊字符有不少元字符在试图对其进行匹配时需要进行特殊的处理。要匹配这些特殊字符,必须首先将这些字符转义,也就是在前面使用一个反斜杠 (\)。下表给出了这些特殊字符及其含义: 特殊字符 $ ( ) * + . [ ? \ ^ { | 非打印字符有不少很有用的非打印字符,偶尔必须使用。下表显示了用来表示这些非打印字符的转义序列: 字符 \cx \f \n \r \s \S \t \v 字符匹配句点 (.) 匹配一个字符串中任何单个的打印或非打印字符,除了换行符 (\n) 之外。下面的 JScript 正则表达式可以匹配 'aac'、'abc'、'acc'、'adc'如此等等,同样也可以匹配 'a1c'、'a2c'、a-c'以及 a#c':
等价的 VBScript 正则表达式为:
如果试图匹配一个包含文件名的字符串,其中句点 (.) 是输入字符串的一部分,则可以在正则表达式中的句点前面加上一个反斜杠 (\) 字符来实现这一要求。举例来说,下面的 JScript 正则表达式就能匹配 'filename.ext':
对 VBScript 而言,等价的表达式如下所示:
这些表达式仍然是相当有限的。它们只允许匹配任何单字符。很多情况下,对从列表中匹配特殊字符十分有用。例如,如果输入文字中包含用数字表示为Chapter 1, Chapter 2诸如此类的章节标题,你可能需要找到这些章节标题。 括号表达式可以在一个方括号 ([ 和 ]) 中放入一个或多个单字符,来创建一个待匹配的列表。如果字符被放入括号中括起来,则该列表称为括号表达式。括号内和其他任何地方一样,普通字符代表其本身,也就是说,它们匹配输入文字中出现的一处自己。大多数特殊字符在位于括号表达式中时都将失去其含义。这里有一些例外:
括号表达式中所包含的字符只匹配该括号表达式在正则表达式中所处位置的一个单字符。下面的 JScript 正则表达式可以匹配 'Chapter 1'、'Chapter 2'、'Chapter 3'、'Chapter 4' 以及 'Chapter 5':
在 VBScript 中要匹配同样的章节标题,请使用下面的表达式:
请注意单词 'Chapter' 及后面的空格与括号内的字符的位置关系是固定的。因此,括号表达式只用来指定满足紧跟在单词 'Chapter' 和一个空格之后的单字符位置的字符集合。这里是第九个字符位置。 如果希望使用范围而不是字符本身来表示待匹配的字符,则可以使用连字符将该范围的开始和结束字符分开。每个字符的字符值将决定其在一个范围内的相对顺序。下面的 JScript 正则表达式包含了一个等价于上面所示的括号列表的范围表达式。
VBScipt 中相同功能的表达式如下所示:
如果以这种方式指定范围,则开始和结束值都包括在该范围内。有一点特别需要注意的是,在 Unicode 排序中起始值一定要在结束值之前。 如果想在括号表达式中包括连字符,则必须使用下述方法之一:
同样,通过在列表开始处放置一个插入符(^),就可以查找所有不在列表或范围中的字符。如果该插入符出现在列表的其他位置,则匹配其本身,没有任何特殊含义。下面的 JScript 正则表达式匹配章节号大于 5 的章节标题:
对 VBScript 则使用:
在上面所示的示例中,表达式将匹配第九个位置处除1, 2, 3, 4, or 5 之外的任何数字字符。因此, 'Chapter 7' 为一个匹配,同样 'Chapter 9' 也是如此。 上面的表达式可以使用连字符 (-) 表示。对 JScript 为:
或者,对 VBScript 为:
括号表达式的典型用法是指定对任何大写或小写字母字符或任何数字的匹配。下面的 JScript 表达式给出了这一匹配:
等价的 VBScript 表达式为: 微软的正则表达式教程(二):正则表达式语法和优先权顺序正则表达式语法一个正则表达式就是由普通字符(例如字符 a 到 z)以及特殊字符(称为元字符)组成的文字模式。该模式描述在查找文字主体时待匹配的一个或多个字符串。正则表达式作为一个模板,将某个字符模式与所搜索的字符串进行匹配。 这里有一些可能会遇到的正则表达式示例: JScript /^\[ \t]*$/ /\d{2}-\d{5}/ /<(.*)>.*<\/\1>/ 下表是元字符及其在正则表达式上下文中的行为的一个完整列表: 字符 \ ^ $ * + ? {n} {n,} {n,m} ? . (pattern) (?:pattern) (?=pattern) (?!pattern) x|y [xyz] [^xyz] [a-z] [^a-z] \b \B \cx \d \D \f \n \r \s \S \t \v \w \W \xn \num \n \nm \nml \un 正则表达式的优先权顺序在构造正则表达式之后,就可以象数学表达式一样来求值,也就是说,可以从左至右并按照一个优先权顺序来求值。 下表从最高优先级到最低优先级列出各种正则表达式操作符的优先权顺序: 操作符 \ (), (?:), (?=), [] *, +, ?, {n}, {n,}, {n,m} ^, $, \anymetacharacter | 正则表达式基础知识一个正则表达式就是由普通字符(例如字符 a 到 z)以及特殊字符(称为元字符)组成的文字模式。该模式描述在查找文字主体时待匹配的一个或多个字符串。正则表达式作为一个模板,将某个字符模式与所搜索的字符串进行匹配。如: JScript /^\[ \t]*$/ /\d{2}-\d{5}/ /<(.*)>.*<\/\1>/ 下表是元字符及其在正则表达式上下文中的行为的一个完整列表: 字符 \ ^ $ * + ? {n} {n,} {n,m} ? . (pattern) (?:pattern) (?=pattern) (?!pattern) x|y [xyz] [^xyz] [a-z] [^a-z] \b \B \cx \d \D \f \n \r \s \S \t \v \w \W \xn \num \n \nm \nml \un 下面看几个例子: "ab*":表示一个字符串有一个a后面跟着零个或若干个b。("a", "ab", "abbb",……); 也可以使用范围,用大括号括起,用以表示重复次数的范围。 "ab{2}":表示一个字符串有一个a跟着2个b("abb"); 请注意,你必须指定范围的下限(如:"{0,2}"而不是"{,2}")。还有,你可能注意到了,'*','+'和 "hi¦hello":表示一个字符串里有"hi"或者"hello"; '.'可以替代任何字符: "a.[0-9]":表示一个字符串有一个"a"后面跟着一个任意字符和一个数字; 方括号表示某些字符允许在一个字符串中的某一特定位置出现: "[ab]":表示一个字符串有一个"a"或"b"(相当于"a¦b"); 你也可以在方括号里用'^'表示不希望出现的字符,'^'应在方括号里的第一位。(如:"%[^a-zA-Z]%"表 为了逐字表达,必须在"^.$()¦*+?{\"这些字符前加上转移字符'\'。 请注意在方括号中,不需要转义字符。 7/15/2008 修改远程桌面端口打开注册表,进入以下路径: 6/19/2008 C#中的字符串格式String.FormatString.Format()和ToString()是一回事。就是给个参数,再给个字符串格式,然后按照给定的格式输出参数。详细信息可以在这个链接看到, http://msdn.microsoft.com/zh-cn/library/fbxft59x.aspx Topic: Formatting Types 1. 标准数字格式 ----- C 或者c , 货币。 默认是小数点后两位,有时候后面跟个数字,比如C3,就是小数点后三位的意思。不同的文化设置,前面的货币符号是不同的。 double money = 123.456; money.ToString("C", CultureInfo.CreateSpecificCulture("en-US" ))); //输出是$123.45 money.ToString("C3", CultureInfo.CreateSpecificCulture("en-US" ))); //输出是$123.456 int value = 12345; value.ToString(" D" ); //输出是12345 value.ToString(" D7" );//输出是0012345 ---- E 或者 e 科学计数法,就是前面是一个1-10的小数,后面跟着10的多少次方的表达形式。后面跟着个数,表示小数点后有几位的意思,不足的位数用零补齐。 double data = 12345.678; data.ToString ( " e " ); //输出是1.2345678E+004 data.ToString( “ e4" );//输出是1.2345E+004 ---- F 或者 f 就是小数点后固定几位。写个数,就表示位数。只写f,表示默认两位。 double data = 12345.678; ---- G 或者 g 表示General ---- N 或者 n 就是按照千位,三个三个分组那种。后面接的数字表示小数点后的位数 doule data = 123456789.1234; ---- P 或者 p,百分比形式输出 ---- R 或者 r Round UP --- X 或者 x 十六进制 基本思想就是用占位符写个字符串格式,然后照着填写就是了。 0 代表 0-9,就是不足位数,用零补齐的意思,也包括在左侧的零。 # 代表空格,0-9,包括前后的零自动抹去。 ,是千位分隔符 % 百分号 ; 区间分割符。在这个之前的,是正数的表达格式,后面是负数的表达格式。 说明白了,下面就举例子 格式 0.00 数值是1.1 输出是 1.10 00.00 数值是1.1 输出是 01.10 #.## 数值是1.1 输出是1.1 (###)###-#### 数值是1234567890 输出是(123)456-7890 [##-##-##] 数值是123456 输出是[12-34-56] #0.###% 数值是 .086 输出是8.6% #,# 数值是12345678 输出是12,345,678 ##;(##) 数值是23 输出是 23 ##;(##) 数值是-23 输出是 (23) 3. Datetime的常用格式 用法大致如下, DateTime curDate; curDate.ToString(" D" ); 输出时间格式 2008年5月3日 4. DateTime 自定义格式 就是用一些参数组合起来的意思。相关参数如下 d 就是日期。 如1,2,20等。 dd就是二位数日期,如01, 02, 22等 ddd 就是三位字母的星期。如: Mon,Tue等 dddd就是星期的全名,如Monday, Sunday 等。 f 就是秒的小数部分。 如 SS.f,就是几秒几的意思。 ff就是秒的两位小数部分。fff, fffff,以及FF,FFF意思都差不多,就是几位小数的意思。 g就是在时间后面的额外部分,如B.C, A.D等等 h,0-12的小时。hh,两位表述的小时。 H,0-23的小时。HH,两位表述的小时。 K,表示当前的时区号。 m,mm,表示不限位和两位表示的分钟。 M,MMM,MMMM表示月份。分别如: 1, Jan, January s, ss 表示不限位和两位的秒。如1, 01等 t, tt,表示上午下午, AM, 或者PM y, yy, yyyy,yyyyy不同位数的年份 z,zz,zzzz不同位数的时区 4/22/2008 远程控制 RemotelyAnywhere v8.0.605 附注册码RemotelyAnywhere是一个小巧的,利用浏览器进行远程控制的小程序。把它安装在NT计算机上。然后你就可以通过任何浏览器对远程计算机进行控制了。通过它,你可以管理远程计算机上的各种服务、进程、用户和文件,甚至远程重启。这一软件的可贵之处是,你不需要安装任何客户端软件,只要具备兼容javascript的浏览器就可以。 4/9/2008 Alcohol 120%右键菜单没了我用的是Alcohol 120%虚拟光驱,不知道为什么在映像文件的右键菜单中的加载映像文件选项没有了,只能在Alcohol120%主程序中进行加载和卸载映像文件。非常不方便,请问如何修复? 【答】:这是由于Alcohol 120%的一个组件没有被成功注册而导致。单击“开始/运行”,"regsvr32 c:\Program Files\Alcohol Soft\Alcohol 120\AXShlEx.dll"重新注册此组件程序即可。另外,安装最新版的Alcohol 120%也可以解决这个问题。 3/31/2008 Visual Studio 2005 开发WPF应用程序系列文章——什么是WPF 你也许听说过Avalon(现在被称为Windows Presentation Foundation,或WPF),也许看过相关的屏幕截图或demo,但是现在你可以亲手尝试了。让我们开始创建下一代Windows应用程序吧。 微软公司早在2003年洛杉矶的PDC上就公布了Avalon,他们将其视为下一代用户界面技术,并且得到了开发者和用户的一致赞同。 在2005年的PDC上,微软公司展示了比2003年更加完整的Avalon版本,并给它取了一个官方新名称:Windows Presentation Foundation(WPF)。在此之前,它已经完成了从演示软件到开始阶段alpha版本的API的转变。到了几个月之后的今天,它又成长成为更加先进的beta版本--你可以使用它来开发你的下一代用户界面程序了。 那么,WPF是什么,为什么它那么重要呢? 首先,它清晰而又有效的将用户界面和程序实现分开。它使得设计可视化的用户界面的设计者和编写内部核心代码的开发人员可以并行工作。这是非常重要的: ·将两者分开,软件开发公司可以使得设计者们集中精力将设计工作做得更好,同时让开发者支持他们。 ·随着软件外包和订购的逐渐风行,WPF使得一些商业的设计者们能够更好的从事界面设计工作,并集成一些简单的功能,而购买的核心代码能够独立的完成内部的一些关键逻辑而不干扰设计过程。 ·它更好的支持应用软件的国际化。不同的独立的界面可以使用不同的本地化方案,而内部的代码是通用的。 ·它支持软件的"空标签":可以为不同的用户采用定制的界面而保持核心的逻辑不变。开发者们创建程序逻辑,然后为不同的用户使用不同的界面并贴上他们的商标等。 WPF使用一种基于XML的语言来定义用户界面从而完成上述的工作。这种语言被称为XAML,XML应用程序标记语言。 其次,WPF使用一种基于向量而不是基于光栅的绘制引擎,这和曹其的Windows的绘制引擎是截然不同的。光栅绘制引擎通过在屏幕上绘制象素点来绘制表面。象素只是点;这样的话,如果屏幕分辨率(DPI,每英寸点)增加了,它的效果就会变差。随着现在屏幕都采用超高DPI的分辨率,字体必须使用成百上千个DPI来达到一定的浏览效果。比如微软Word里缺省的英文字体12号的Times New Roman,在现在的普通分辨率情况下效果还可以但是到了超高分辨率的显示器上效果就不行了。管理这些基于光栅的图像的点将会消耗大量的处理能力,同时也是很浪费的。而采用基于向量的方式来替代象素,在一个可扩展的坐标系里绘制字体和其他线型,使得它们可以独立于DPI。想想Windows Metafile(WMF)和位图文件(BMP)之间的差距你就明白了。同时,向量图也使得一些变换如3D,旋转和动画变得更加方便和易于操作。 好,下面开始我们的第一个基于WPF的应用程序之旅吧。 首先你需要安装一下一些软件: 1. 首先你需要安装.NET Framework 3.0。 2. 你需要安装WinFX runtime components。 3. 还需要安装VS2005 4. 最后你需要下载Visual Studio development tools(Orcas)来进行WinFX开发。它包含了VS里的"Cider"设计器来编辑XAML。 5. 最后你需要下载Expression Designer for XAML 作为程序员你可以使用Cider工具来在VS.NET里创建基本的XAML用户界面,这样的方式你会感到很熟悉,和在VS中进行一般的Windows 窗体设计差不多。但是,如果要是用一些XAML提供的高级特性,我建议你还是研究一下Expression Designer for XAML。 第一个WPF Windows Application: 如果所有的工具都安装正确,你就可以开发你的第一个WPF程序了。打开VS2005,选择文件->新建工程。你将会看到工程对话框,如图1所示。 在图1中,你可以看到一套新的工程类型,名为Windows Application,包括Windows Application(WPF),服务库,XAML Browser Application (WPF)浏览器程序和控件库。它们分别用来创建XAML客户端程序,Indigo服务,XAML浏览器(Web窗体)程序,和控件库。 这篇文章里,我主要讲解创建一个Windows windows应用程序的流程,所以我们选择和其对应的工程模板。 当你第一次创建这个程序的时候,你将会看到和标准的VS设计环境类似的界面,但是事实上它是一个VS的新的XAML设计器,代号"Cider"。如图2所示。 如果你仔细看图2,你会发现在设计面板的下部有一个新tab,名为"Xaml"。点击它,你会看到当前设计的XAML,这个XAML包含了一个button,一个textbox: 当你改变Cider可视化编辑器里的对话框的布局的时候,工具会自动更新XAML的内容。 对控件的基于设计者的事件添加机制还没有被Cider所支持,不过如果手工对XML进行一些修改就可以很容易的增加一些事件。比如,你可以手工为"Click"属性增加一个点击事件处理: <Button Margin="124,125,93,119" Name="btnClick" Click="ButtonClick" >I Click</Button> 你可以看到,这里做的就是为按钮增加了一个新的"Click"属性,并且给出了点击按键事件句柄的名称。如果你选择了"Source"那个tab,你可以为这个事件创建处理句柄。 Avalon使用一种被称为"Routed Events"的机制来绑定XAML和后端代码,如同其名--事件在运行时在独立的XAML UI和代码之间相互传递。 这样的话,你需要声明事件句柄来使用RoutedEventArgs参数: void ButtonClick(object sender, RoutedEventArgs e) { System.Windows.MessageBox.Show("Hello World to:" + textBox1.Text); } 如果你此时运行程序,你将看到WPF基于向量的引擎已经开始工作了,如图3所示。 这样你就完成了你的第一次Avalon的学习之旅,也许它没有想象中的激动人心,但是毕竟你已经开始掌握这一先进技术了。 Microsoft Expression是一个比基本的Cider工具更加强大的XAML设计工具,它包含在VS.NET的WinFX工具集中。有兴趣的朋友可以自己 使用Expression来设计XAML 这个应用程序。 在C#隐藏主窗口的几种方法写过一个程序,要求在程序启动的时候主窗口隐藏,只在系统托盘里显示一个图标。一直以来采用的方法都是设置窗口的ShowInTaskBar=false, WindowState=Minimized。但是偶然发现尽管这样的方法可以使主窗口隐藏不见,但是在用Alt+Tab的时候却可以看见这个程序的图标并把这个窗口显示出来。因此这种方法其实并不能满足要求。 经过研究,又找到两个方法。 方法一: 重写setVisibleCore方法 protected override void SetVisibleCore(bool value) { base.SetVisibleCore(false); } 这个方法比较简单,但是使用了这个方法后主窗口就再也不能被显示出来,而且在退出程序的时候也必须调用Application.Exit方法而不是Close方法。这样的话就要考虑一下,要把主窗口的很多功能放到其他的地方去。 方法二: 不创建主窗口,直接创建NotifyIcon和ContextMenu组件 static void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); System.Resources.ResourceManager resources = new System.Resources.ResourceManager("myResource", System.Reflection.Assembly.GetExecutingAssembly()); NotifyIcon ni = new NotifyIcon(); ni.BalloonTipIcon = System.Windows.Forms.ToolTipIcon.Warning; ni.BalloonTipText = "test!"; ni.BalloonTipTitle = "test."; //ni.ContextMenuStrip = contextMenu; ni.Icon = ((System.Drawing.Icon)(resources.GetObject("ni.Icon"))); ni.Text = "Test"; ni.Visible = true; ni.MouseClick += delegate(object sender, MouseEventArgs e) { ni.ShowBalloonTip(0); }; Application.Run(); } 如果需要的组件太多,这个方法就很繁琐,因此只是做为一种可行性研究。 方法三:前面两种方法都有一个问题,主窗口不能再显示出来。现在这种方法就没有这个问题了 private bool windowCreate=true; ... protected override void OnActivated(EventArgs e) { if (windowCreate) { base.Visible = false; windowCreate = false; } base.OnActivated(e); } private void notifyIcon1_DoubleClick(object sender, EventArgs e) { if (this.Visible == true) { this.Hide(); this.ShowInTaskbar = false; } else { this.Visible = true; this.ShowInTaskbar = true; this.WindowState = FormWindowState.Normal; //this.Show(); this.BringToFront(); } |
||||
|
|