﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-huyi-随笔分类-dotNET</title><link>http://www.blogjava.net/huyi/category/102.html</link><description /><language>zh-cn</language><lastBuildDate>Thu, 01 Mar 2007 19:32:52 GMT</lastBuildDate><pubDate>Thu, 01 Mar 2007 19:32:52 GMT</pubDate><ttl>60</ttl><item><title>CodeDom：语言的界限在这里消失</title><link>http://www.blogjava.net/huyi/archive/2005/04/13/3207.html</link><dc:creator>HuYi's Blog</dc:creator><author>HuYi's Blog</author><pubDate>Wed, 13 Apr 2005 03:16:00 GMT</pubDate><guid>http://www.blogjava.net/huyi/archive/2005/04/13/3207.html</guid><wfw:comment>http://www.blogjava.net/huyi/comments/3207.html</wfw:comment><comments>http://www.blogjava.net/huyi/archive/2005/04/13/3207.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/huyi/comments/commentRss/3207.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/huyi/services/trackbacks/3207.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp; .NET推崇这样一种思想：相对于框架而言，语言处于从属、次要的地位。CodeDom名称空间中包含的类是这一思想的集中体现。我们可以用CodeDom构造一个树或图，用System.CodeDom名称空间的类填充它，完成后，用对应各种.NET语言的CodeProvider对象将树结构转换成该种语言的代码。要更换一种语言，简单到只需更换一下最后用到的CodeProvider对象。 <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;　　设想一下，利用这一技术，我们至少能够： <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;　　·查询存储过程的元数据，构造出一个负责参数绑定的类。 <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;　　·查询程序集的manifest，构造出一个对每个函数执行单元测试的类。 <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;　　·为开发组用到的每一种语言生成样板代码。 <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;　　·只需写一份范例代码，就可以让用户自由选择他们要查看哪一种语言的版本。 <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;　　·自定义模板语法，经解析后生成任意语言的代码。 <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;　　·如果要学习某种不熟悉的语言，可以生成该语言的代码，然后将它与熟悉的语言比较。 <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;　　一、基本操作 <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;　　System.CodeDom名称空间包含了许多以语言中立的形式描述常见程序结构的对象，每一种语言的细节则由与该种语言对应的CodeProvider对象负责处理。例如，CodeConditionStatement包含一个TrueStatements集合、一个FalseStatements集合和一个条件属性（Condition attribute），但不涉及条件语句块要用“end if”还是右花括号“}”结束，这部分细节由CodeProvider处理。有了这一层抽象，我们就可以描述待生成的代码结构，然后将它以任意语言的形式输出，却不必斤斤计较于各种与特定语言有关的细节问题。同时，这种抽象也为我们通过程序改变代码的结构带来了方便。例如，当我们发现某个方法需要增加一个参数时，就可以将参数加入到该方法的Parameters集合，根本无须改动已生成的代码逻辑。 <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;　　我们在本文中要用到的大部分对象来自System.CodeDom名称空间，其余对象主要来自各个与特定语言有关的名称空间，例如Microsoft.CSharp名称空间、Microsoft.VisualBasic名称空间、Microsoft.JScript名称空间和Microsoft.VJSharp名称空间。所有这些面向特定语言的名称空间都包含各自的CodeProvider对象。最后，System.CodeDom.Complier名称空间定义ICodeGenerator接口，后者用来把生成的代码输出到一个TextWriter对象。 <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;　　如果我们只要生成一些用于插件或宏的代码片断，可以利用CodeGenerator从Statement、Expression、Type等生成代码。反之，如果我们要生成的是一个完整的文件，则必须从CodeNameSpace对象入手。在本文的例子中，我们将从一个名称空间开始，示范如何加入import语句、声明类、声明方法、声明变量、实现一个循环结构、索引一个数组，最后，我们将这些技术结合起来，得到一个大家都熟悉的程序。 <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;　　1.1 初始化名称空间 <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;　　初始化名称空间的代码类似下面这种形式： <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;private CodeNameSpace InitializeNameSpace(string Name) <BR>&nbsp;&nbsp;{ <BR>&nbsp;&nbsp; // 初始化CodeNameSpace变量，指定名称空间的名称 <BR>&nbsp;&nbsp; CodeNameSpace CurrentNameSpace = new CodeNamespace (Name); <BR>&nbsp;&nbsp; // 将一些名称空间加入到要导入的名称空间集合。 <BR>&nbsp;&nbsp; // 各种语言如何导入名称空间的细节由每种语言对应 <BR>&nbsp;&nbsp; // 的CodeProvider分别处理。 <BR>&nbsp;&nbsp; CurrentNameSpace.Imports.Add (new CodeNamespaceImport("System")); <BR>&nbsp;&nbsp; CurrentNameSpace.Imports.Add (new CodeNamespaceImport("System.Text")); <BR>&nbsp;&nbsp; return CurrentNameSpace; <BR>&nbsp;&nbsp;} <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;　　这段代码定义了一个新的名称空间，并导入System和System.Text名称空间。 <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;　　1.2 创建类 <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;　　声明一个新类的代码类似下面这种形式： <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;private CodeTypeDeclaration CreateClass (string Name) <BR>&nbsp;&nbsp;{ <BR>&nbsp;&nbsp; // 新建一个CodeTypeDeclaration对象，指定要创建的类的名称 <BR>&nbsp;&nbsp; CodeTypeDeclaration ctd = new CodeTypeDeclaration (Name); <BR>&nbsp;&nbsp; // 指定这个CodeType是一个类，而不是一个枚举变量或struct <BR>&nbsp;&nbsp; ctd.IsClass = true; <BR>&nbsp;&nbsp; // 这个类的访问类型是public <BR>&nbsp;&nbsp; ctd.Attributes = MemberAttributes.Public; <BR>&nbsp;&nbsp; // 返回新创建的类 <BR>&nbsp;&nbsp; return ctd; <BR>&nbsp;&nbsp;} <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;　　CreateClass函数新建一个指定名称的类，做好为该类植入方法、属性、事件的准备。 <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;　　1.3 创建方法 <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;　　声明一个新函数的代码类似下面这种形式： <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;private CodeEntryPointMethod CreateMethod() <BR>&nbsp;&nbsp;{ <BR>&nbsp;&nbsp; // 创建一个方法 <BR>&nbsp;&nbsp; CodeEntryPointMethod method = new CodeEntryPointMethod(); <BR>&nbsp;&nbsp; // 指定该方法的修饰符：public，static <BR>&nbsp;&nbsp; method.Attributes = MemberAttributes.Public | <BR>&nbsp;&nbsp; MemberAttributes.Static; <BR>&nbsp;&nbsp; // 返回新创建的方法 <BR>&nbsp;&nbsp; return method; <BR>&nbsp;&nbsp;} <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;　　本例创建了一个CodeEntryPointMethod对象。CodeEntryPointMethod对象类似于CodeMemberMethod对象，两者的不同之处在于，CodeProvider会将CodeEntryPointMethod代表的方法作为类的入口点调用，例如作为Sub Main或void main等。对于CodeEntryPointMethod对象，方法的名称默认为Main；对于CodeMemberMethod，方法的名称必须显式指定。 <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;　　1.4 声明变量 <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;　　声明一个变量的代码类似下面这种形式： <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;private CodeVariableDeclarationStatement <BR>&nbsp;&nbsp; DeclareVariables(System.Type DataType, <BR>&nbsp;&nbsp; string Name) <BR>&nbsp;&nbsp;{ <BR>&nbsp;&nbsp; // 为将要创建的变量类型创建一个CodeTypeReference对象， <BR>&nbsp;&nbsp; // 这使得我们不必去关注该类数据在特定语言环境中的 <BR>&nbsp;&nbsp; // 与数据类型有关的细节问题。 <BR>&nbsp;&nbsp; CodeTypeReference tr = new CodeTypeReference (DataType ); <BR>&nbsp;&nbsp; // CodeVariableDeclarationStatement对象使得我们不必纠缠于 <BR>&nbsp;&nbsp; // 与特定语言有关的下列细节：在该语言的变量声明语句中， <BR>&nbsp;&nbsp; // 应该是数据类型在前，还是变量名称在前；声明变量时是 <BR>&nbsp;&nbsp; // 否要用到Dim之类的关键词. <BR>&nbsp;&nbsp; CodeVariableDeclarationStatement Declaration = <BR>&nbsp;&nbsp; new CodeVariableDeclarationStatement(tr, Name); <BR>&nbsp;&nbsp; // CodeObjectCreateExpression负责处理所有调用构造器的细节。 <BR>&nbsp;&nbsp; // 大多数情况下应该是new，但有时要使用New。但不管怎样， <BR>&nbsp;&nbsp; // 我们不必去关注这些由语言类型决定的细节. <BR>&nbsp;&nbsp; CodeObjectCreateExpression newStatement = new <BR>&nbsp;&nbsp; CodeObjectCreateExpression (); <BR>&nbsp;&nbsp; // 指定我们要调用其构造器的对象. <BR>&nbsp;&nbsp; newStatement.CreateType = tr; <BR>&nbsp;&nbsp; // 变量将通过调用其构造器的方式初始化. <BR>&nbsp;&nbsp; Declaration.InitExpression = newStatement; <BR>&nbsp;&nbsp; return Declaration; <BR>&nbsp;&nbsp;} <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;　　每一种.NET语言都有其特定的数据类型名称，所有这些数据类型都被映射到公共的.NET语言类型。例如，对于C#中称为int的数据类型，在VB.NET中是Integer，公共的.NET类型是System.Int32。CodeTypeReference对象直接使用.NET公共数据类型，以后由每种语言的CodeProvider将它转换成符合各自语言规范的类型名称。 <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;　　1.5 初始化数组 <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;　　初始化一个数组的代码类似下面这种形式： <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;private void InitializeArray (string Name, <BR>&nbsp;&nbsp; params char[] Characters ) <BR>&nbsp;&nbsp;{ <BR>&nbsp;&nbsp; // 从参数中传入的字符数组获得一个CodeTypeReference 对象， <BR>&nbsp;&nbsp; // 以便在生成的代码中复制该数据类型. <BR>&nbsp;&nbsp; CodeTypeReference tr = new CodeTypeReference (Characters.GetType()); <BR>&nbsp;&nbsp; // 声明一个匹配原始数组的数组 <BR>&nbsp;&nbsp; CodeVariableDeclarationStatement Declaration = <BR>&nbsp;&nbsp; new CodeVariableDeclarationStatement (tr, Name); <BR>&nbsp;&nbsp; // CodePrimitiveExpression代表“基本”或值数据类型， <BR>&nbsp;&nbsp; // 例如char、int、double等等。 <BR>&nbsp;&nbsp; // 我们将用这类基本数据类型构成的一个数组来 <BR>&nbsp;&nbsp; // 初始化我们正在声明的数组。 <BR>&nbsp;&nbsp; CodePrimitiveExpression[] cpe = new <BR>&nbsp;&nbsp; CodePrimitiveExpression[Characters.Length]; <BR>&nbsp;&nbsp; // 循环遍历原始字符数组， <BR>&nbsp;&nbsp; // 为CodePrimitiveExpression类型的数组创建对象。 <BR>&nbsp;&nbsp; for (int i = 0; i &lt; Name.Length ; i++) <BR>&nbsp;&nbsp; { <BR>&nbsp;&nbsp; // 每一个CodePrimitiveExpression将有一个字符的语言 <BR>&nbsp;&nbsp; // 中立的表示。 <BR>&nbsp;&nbsp; cpe[i] = new CodePrimitiveExpression (Characters[i]); <BR>&nbsp;&nbsp; } <BR>&nbsp;&nbsp; // CodeArrayCreateExpression负责调用数组中数据类型的 <BR>&nbsp;&nbsp; // 默认构造器。 <BR>&nbsp;&nbsp; // 由于我们还传入了一个CodePrimitiveExpression的数组， <BR>&nbsp;&nbsp; // 所以不必指定数组的大小，且数组中的每一个元素都将有 <BR>&nbsp;&nbsp; // 合适的初值。 <BR>&nbsp;&nbsp; CodeArrayCreateExpression array = new <BR>&nbsp;&nbsp; CodeArrayCreateExpression(tr, cpe); <BR>&nbsp;&nbsp; // 指定：该CodeArrayCreateExpression将初始化数组变量声明。 <BR>&nbsp;&nbsp; Declaration.InitExpression = array; <BR>&nbsp;&nbsp; return Declaration; <BR>&nbsp;&nbsp;} <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;　　1.6 定义循环结构 <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;　　声明一个循环结构的代码类似下面这种形式： <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;private CodeIterationStatement CreateLoop(string LoopControlVariableName) <BR>&nbsp;&nbsp;{ <BR>&nbsp;&nbsp; // 声明一个新的变量，该变量将作为 <BR>&nbsp;&nbsp; // 循环控制变量 <BR>&nbsp;&nbsp; CodeVariableDeclarationStatement Declaration; <BR>&nbsp;&nbsp; // 声明一个管理所有循环逻辑的CodeIterationStatement <BR>&nbsp;&nbsp; CodeIterationStatement forloop = new CodeIterationStatement(); <BR>&nbsp;&nbsp; // 为动态声明的变量指定数据类型的另一种方法： <BR>&nbsp;&nbsp; // 用typeof函数获得该数据类型的Type对象，不必 <BR>&nbsp;&nbsp; // 用到该类数据的变量 <BR>&nbsp;&nbsp; Declaration = new CodeVariableDeclarationStatement(typeof (int), <BR>&nbsp;&nbsp; LoopControlVariableName); <BR>&nbsp;&nbsp; // 指定一个简单的初始化表达式： <BR>&nbsp;&nbsp; // 将新变量设置为0 <BR>&nbsp;&nbsp; Declaration.InitExpression = new CodeSnippetExpression ("0"); <BR>&nbsp;&nbsp; // 这个新声明的变量将用来初始化循环 <BR>&nbsp;&nbsp; forloop.InitStatement = Declaration; <BR>&nbsp;&nbsp; // CodeAssignStatement用来处理赋值语句。 <BR>&nbsp;&nbsp; // 这里使用的构造器要求提供两个表达式，第一个位于 <BR>&nbsp;&nbsp; // 赋值语句的左边，第二个位于赋值语句的右边。 <BR>&nbsp;&nbsp; // 另一种办法是：调用默认的构造器，然后分别显式设置 <BR>&nbsp;&nbsp; // 左、右两个表达式。 <BR>&nbsp;&nbsp; CodeAssignStatement assignment = new CodeAssignStatement( <BR>&nbsp;&nbsp; new CodeVariableReferenceExpression(LoopControlVariableName), <BR>&nbsp;&nbsp; new CodeSnippetExpression (LoopControlVariableName + " + 1" )); <BR>&nbsp;&nbsp; // 在循环迭代中使用赋值语句。 <BR>&nbsp;&nbsp; forloop.IncrementStatement = assignment; <BR>&nbsp;&nbsp; // 当循环控制变量超出数组中的字符个数时， <BR>&nbsp;&nbsp; // 循环结束 <BR>&nbsp;&nbsp; forloop.TestExpression = new CodeSnippetExpression <BR>&nbsp;&nbsp; (LoopControlVariableName + " &lt; Characters.Length"); <BR>&nbsp;&nbsp; return forloop; <BR>&nbsp;&nbsp;} <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;　　注意，这里我们用typeof函数直接获得循环控制变量的数据类型的Type对象，而不是通过声明一个CodeTypeReference对象的方式。这是CodeVariableDeclartionStatement的又一个构造器，实际上其构造器的总数多达7种。 <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;　　1.7 索引数组 <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;　　索引一个数组的代码类似下面这种形式： <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;private CodeArrayIndexerExpression <BR>&nbsp;&nbsp; CreateArrayIndex(string ArrayName, string IndexValue ) <BR>&nbsp;&nbsp;{ <BR>&nbsp;&nbsp; // 新建一个CodeArrayIndexerExpression <BR>&nbsp;&nbsp; CodeArrayIndexerExpression index = new CodeArrayIndexerExpression (); <BR>&nbsp;&nbsp; // Indices属性是一个能够支持多维数组的集合。不过这里我们只需要 <BR>&nbsp;&nbsp; // 一个简单的一维数组。 <BR>&nbsp;&nbsp; index.Indices.Add ( new CodeVariableReferenceExpression (IndexValue)); <BR>&nbsp;&nbsp; // TargetObject指定了要索引的数组的名称。 <BR>&nbsp;&nbsp; index.TargetObject = new CodeSnippetExpression (ArrayName); <BR>&nbsp;&nbsp; return index; <BR>&nbsp;&nbsp;} <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;　　CodeArrayIndexerExpression对象处理数组索引方式的种种差异。例如，在C#中数组以ArrayName[IndexValue]的方式索引；但在VB.NET中，数组以ArrayName(IndexValue)的方式索引。CodeArrayIndexerExpression允许我们忽略这种差异，将注意力集中到其他更重要的问题，例如要索引哪一个数组、要访问第几个数组元素。 <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;　　二、装配出树结构 <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;　　我们可以把前面定义的所有函数加入到一个类，通过构造器初始化，例如： <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;public CodeDomProvider() <BR>&nbsp;&nbsp;{ <BR>&nbsp;&nbsp; CurrentNameSpace = InitializeNameSpace("TestSpace"); <BR>&nbsp;&nbsp; CodeTypeDeclaration ctd = CreateClass ("HelloWorld"); <BR>&nbsp;&nbsp; // 把类加入到名称空间 <BR>&nbsp;&nbsp; CurrentNameSpace.Types.Add (ctd); <BR>&nbsp;&nbsp; CodeEntryPointMethod mtd = CreateMethod(); <BR>&nbsp;&nbsp; // 把方法加入到类 <BR>&nbsp;&nbsp; ctd.Members.Add (mtd); <BR>&nbsp;&nbsp; CodeVariableDeclarationStatement VariableDeclaration = <BR>&nbsp;&nbsp; DeclareVariables (typeof (StringBuilder), "sbMessage"); <BR>&nbsp;&nbsp; // 把变量声明加入到方法 <BR>&nbsp;&nbsp; mtd.Statements.Add (VariableDeclaration); <BR>&nbsp;&nbsp; CodeVariableDeclarationStatement array = InitializeArray <BR>&nbsp;&nbsp; ("Characters", 'H', 'E', 'L', 'L', 'O', ' ', <BR>&nbsp;&nbsp; 'W', 'O', 'R', 'L', 'D'); <BR>&nbsp;&nbsp; // 把数组加入到方法 <BR>&nbsp;&nbsp; mtd.Statements.Add (array); <BR>&nbsp;&nbsp; CodeIterationStatement loop = CreateLoop("intCharacterIndex"); <BR>&nbsp;&nbsp; // 把循环加入到方法 <BR>&nbsp;&nbsp; mtd.Statements.Add (loop); <BR>&nbsp;&nbsp; // 数组索引 <BR>&nbsp;&nbsp; CodeArrayIndexerExpression index = CreateArrayIndex("Characters", <BR>&nbsp;&nbsp; "intCharacterIndex"); <BR>&nbsp;&nbsp; // 加入一个语句，它将调用sbMessage对象的“Append”方法 <BR>&nbsp;&nbsp; loop.Statements.Add (new CodeMethodInvokeExpression ( <BR>&nbsp;&nbsp; new CodeSnippetExpression ("sbMessage"),"Append", <BR>&nbsp;&nbsp; index)); <BR>&nbsp;&nbsp; // 循环结束后，输出所有字符追加到sbMessage对象 <BR>&nbsp;&nbsp; // 后得到的结果 <BR>&nbsp;&nbsp; mtd.Statements.Add (new CodeSnippetExpression <BR>&nbsp;&nbsp; ("Console.WriteLine (sbMessage.ToString())")); <BR>&nbsp;&nbsp;} <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;　　构造器的运行结果是一个完整的CodeDom树结构。可以看到，至此为止我们的所有操作都独立于目标语言。最后生成的代码将以属性的形式导出。 <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;　　三、输出生成结果 <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;　　构造好CodeDom树之后，我们就可以较为方便地将代码以任意.NET语言的形式输出。每一种.NET语言都有相应的CodeProvider对象，CodeProvider对象的CreateGenerator方法能够返回一个实现了ICodeGenerator接口的对象。ICodeGenerator接口定义了用来生成代码的所有方法，而且允许我们定义一个用来简化属性输出的辅助方法。下面的辅助方法GenerateCode负责设置好合适的TextWriter以供输出代码，以字符串的形式返回结果文本。 <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;private string GenerateCode (ICodeGenerator CodeGenerator) <BR>&nbsp;&nbsp;{ <BR>&nbsp;&nbsp; // CodeGeneratorOptions允许我们指定各种供代码生成器 <BR>&nbsp;&nbsp; // 使用的格式化选项 <BR>&nbsp;&nbsp; CodeGeneratorOptions cop = new CodeGeneratorOptions(); <BR>&nbsp;&nbsp; // 指定格式：花括号的位置 <BR>&nbsp;&nbsp; cop.BracingStyle = "C"; <BR>&nbsp;&nbsp; // 指定格式：代码块的缩进方式 <BR>&nbsp;&nbsp; cop.IndentString = " "; <BR>&nbsp;&nbsp; // GenerateCodeFromNamespace要求传入一个TextWriter以 <BR>&nbsp;&nbsp; // 容纳即将生成的代码。这个TextWriter可以是一个StreamWriter、 <BR>&nbsp;&nbsp; // 一个StringWriter或一个IndentedTextWriter。 <BR>&nbsp;&nbsp; // StreamWriter可用来将代码输出到文件。 <BR>&nbsp;&nbsp; // StringWriter可绑定到StringBuilder，后者可作为一个变量引用。 <BR>&nbsp;&nbsp; // 在这里，我们把一个StringWriter绑定到StringBuilder sbCode。 <BR>&nbsp;&nbsp; StringBuilder sbCode = new StringBuilder(); <BR>&nbsp;&nbsp; StringWriter sw = new StringWriter(sbCode); <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp; // 生成代码！ <BR>&nbsp;&nbsp; CodeGenerator.GenerateCodeFromNamespace(CurrentNameSpace, sw,cop); <BR>&nbsp;&nbsp; return sbCode.ToString(); <BR>&nbsp;&nbsp;} <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;　　有了这个辅助函数，要获取各种语言的代码就相当简单了： <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;public string VBCode <BR>&nbsp;&nbsp;{ <BR>&nbsp;&nbsp; get <BR>&nbsp;&nbsp; { <BR>&nbsp;&nbsp; VBCodeProvider provider = new VBCodeProvider (); <BR>&nbsp;&nbsp; ICodeGenerator codeGen = provider.CreateGenerator (); <BR>&nbsp;&nbsp; return GenerateCode (codeGen); <BR>&nbsp;&nbsp; } <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;} <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;public string JScriptCode <BR>&nbsp;&nbsp;{ <BR>&nbsp;&nbsp; get <BR>&nbsp;&nbsp; { <BR>&nbsp;&nbsp; JScriptCodeProvider provider = new JScriptCodeProvider (); <BR>&nbsp;&nbsp; ICodeGenerator codeGen = provider.CreateGenerator (); <BR>&nbsp;&nbsp; return GenerateCode(codeGen); <BR>&nbsp;&nbsp; } <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;} <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;public string JSharpCode <BR>&nbsp;&nbsp;{ <BR>&nbsp;&nbsp; get <BR>&nbsp;&nbsp; { <BR>&nbsp;&nbsp; VJSharpCodeProvider provider = new VJSharpCodeProvider (); <BR>&nbsp;&nbsp; ICodeGenerator codeGen = provider.CreateGenerator (); <BR>&nbsp;&nbsp; return GenerateCode (codeGen); <BR>&nbsp;&nbsp; } <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;} <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;public string CSharpCode <BR>&nbsp;&nbsp;{ <BR>&nbsp;&nbsp; get <BR>&nbsp;&nbsp; { <BR>&nbsp;&nbsp; CSharpCodeProvider provider = new CSharpCodeProvider(); <BR>&nbsp;&nbsp; ICodeGenerator codeGen = provider.CreateGenerator (); <BR>&nbsp;&nbsp; return GeneratorCode (codeGen); <BR>&nbsp;&nbsp; } <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;} <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;　　四、显示出生成的代码 <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;　　为输出代码，我们要用到一个简单的.aspx文件，它有四个标签，分别对应一种.NET语言： <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;&lt;table width="800" border="1"&gt; <BR>&nbsp;&nbsp; &lt;tr&gt; <BR>&nbsp;&nbsp; &lt;th&gt;VB.NET代码&lt;/th&gt; <BR>&nbsp;&nbsp; &lt;/tr&gt; <BR>&nbsp;&nbsp; &lt;tr &gt; <BR>&nbsp;&nbsp; &lt;td&gt; <BR>&nbsp;&nbsp; &lt;asp:Label ID="vbCode" Runat="server" CssClass="code"&gt; <BR>&nbsp;&nbsp; &lt;/asp:Label&gt; <BR>&nbsp;&nbsp; &lt;/td&gt; <BR>&nbsp;&nbsp; &lt;/tr&gt; <BR>&nbsp;&nbsp; &lt;tr&gt; <BR>&nbsp;&nbsp; &lt;th&gt; <BR>&nbsp;&nbsp; C#代码&lt;/th&gt;&lt;/tr&gt; <BR>&nbsp;&nbsp; &lt;tr&gt; <BR>&nbsp;&nbsp; &lt;td&gt;&lt;asp:Label ID="csharpcode" Runat="server" CssClass="code"&gt; <BR>&nbsp;&nbsp; &lt;/asp:Label&gt;&lt;/td&gt; <BR>&nbsp;&nbsp; &lt;/tr&gt; <BR>&nbsp;&nbsp; &lt;tr&gt; <BR>&nbsp;&nbsp; &lt;th&gt;J#代码&lt;/th&gt;&lt;/tr&gt; <BR>&nbsp;&nbsp; &lt;tr &gt; <BR>&nbsp;&nbsp; &lt;td&gt; <BR>&nbsp;&nbsp; &lt;asp:Label ID="JSharpCode" Runat="server" CssClass="code"&gt; <BR>&nbsp;&nbsp; &lt;/asp:Label&gt; <BR>&nbsp;&nbsp; &lt;/td&gt; <BR>&nbsp;&nbsp; &lt;/tr&gt; <BR>&nbsp;&nbsp; &lt;tr&gt; <BR>&nbsp;&nbsp; &lt;th&gt;JScript.NET代码&lt;/th&gt; <BR>&nbsp;&nbsp; &lt;/tr&gt; <BR>&nbsp;&nbsp; &lt;tr&gt; <BR>&nbsp;&nbsp; &lt;td&gt;&lt;asp:Label ID="JScriptCode" Runat="server" CssClass="code"&gt; <BR>&nbsp;&nbsp; &lt;/asp:Label&gt;&lt;/td&gt; <BR>&nbsp;&nbsp; &lt;/tr&gt; <BR>&nbsp;&nbsp;&lt;/table&gt; <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;　　在后台执行的代码中，我们实例化一个前面创建的CodeDomProvider类的实例，把它生成的代码赋值给.aspx页面的相应标签的Text属性。为了使Web页面中显示的代码整齐美观，有必要做一些简单的格式化，替换换行符号、空格等，如下所示： <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;private string FormatCode (string CodeToFormat) <BR>&nbsp;&nbsp;{ <BR>&nbsp;&nbsp; string FormattedCode = Regex.Replace (CodeToFormat, "\n", "&lt;br&gt;"); <BR>&nbsp;&nbsp; FormattedCode = Regex.Replace (FormattedCode, " " , "&nbsp;"); <BR>&nbsp;&nbsp; FormattedCode = Regex.Replace (FormattedCode, ",", ", "); <BR>&nbsp;&nbsp; return FormattedCode; <BR>&nbsp;&nbsp;} <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;　　下面把生成的代码显示到Web页面： <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;private void Page_Load(object sender, System.EventArgs e) <BR>&nbsp;&nbsp;{ <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp; HelloWorld.CodeDomProvider codegen = new HelloWorld.CodeDomProvider (); <BR>&nbsp;&nbsp; vbCode.Text = FormatCode (codegen.VBCode); <BR>&nbsp;&nbsp; csharpcode.Text = FormatCode (codegen.CSharpCode); <BR>&nbsp;&nbsp; JScriptCode.Text = FormatCode (codegen.JScriptCode); <BR>&nbsp;&nbsp; JSharpCode.Text = FormatCode (codegen.JSharpCode); <BR>&nbsp;&nbsp; Page.EnableViewState = false; <BR>&nbsp;&nbsp;} <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;　　输出结果如下： <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;VB.NET代码 <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;Imports System <BR>&nbsp;&nbsp;Imports System.Text <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;Namespace HelloWorld <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp; Public Class Hello_World <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp; Public Shared Sub Main() <BR>&nbsp;&nbsp; Dim sbMessage As System.Text.StringBuilder = _ <BR>&nbsp;&nbsp; New System.Text.StringBuilder <BR>&nbsp;&nbsp; Dim Characters() As Char = New Char() {_ <BR>&nbsp;&nbsp; Microsoft.VisualBasic.ChrW(72), _ <BR>&nbsp;&nbsp; Microsoft.VisualBasic.ChrW(69), _ <BR>&nbsp;&nbsp; Microsoft.VisualBasic.ChrW(76), _ <BR>&nbsp;&nbsp; Microsoft.VisualBasic.ChrW(76), _ <BR>&nbsp;&nbsp; Microsoft.VisualBasic.ChrW(79), _ <BR>&nbsp;&nbsp; Microsoft.VisualBasic.ChrW(32), _ <BR>&nbsp;&nbsp; Microsoft.VisualBasic.ChrW(87), _ <BR>&nbsp;&nbsp; Microsoft.VisualBasic.ChrW(79), _ <BR>&nbsp;&nbsp; Microsoft.VisualBasic.ChrW(82), _ <BR>&nbsp;&nbsp; Microsoft.VisualBasic.ChrW(76), _ <BR>&nbsp;&nbsp; Microsoft.VisualBasic.ChrW(68)} <BR>&nbsp;&nbsp; Dim intCharacterIndex As Integer = 0 <BR>&nbsp;&nbsp; Do While intCharacterIndex &lt; Characters.Length <BR>&nbsp;&nbsp; sbMessage.Append(Characters(intCharacterIndex)) <BR>&nbsp;&nbsp; intCharacterIndex = intCharacterIndex + 1 <BR>&nbsp;&nbsp; Loop <BR>&nbsp;&nbsp; Console.WriteLine (sbMessage.ToString()) <BR>&nbsp;&nbsp; End Sub <BR>&nbsp;&nbsp; End Class <BR>&nbsp;&nbsp;End Namespace <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;C#代码 <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;namespace HelloWorld <BR>&nbsp;&nbsp;{ <BR>&nbsp;&nbsp; using System; <BR>&nbsp;&nbsp; using System.Text; <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp; public class Hello_World <BR>&nbsp;&nbsp; { <BR>&nbsp;&nbsp; public static void Main() <BR>&nbsp;&nbsp; { <BR>&nbsp;&nbsp; System.Text.StringBuilder sbMessage = new <BR>&nbsp;&nbsp; System.Text.StringBuilder(); <BR>&nbsp;&nbsp; char[] Characters = new char[] { <BR>&nbsp;&nbsp; 'H', <BR>&nbsp;&nbsp; 'E', <BR>&nbsp;&nbsp; 'L', <BR>&nbsp;&nbsp; 'L', <BR>&nbsp;&nbsp; 'O', <BR>&nbsp;&nbsp; ' ', <BR>&nbsp;&nbsp; 'W', <BR>&nbsp;&nbsp; 'O', <BR>&nbsp;&nbsp; 'R', <BR>&nbsp;&nbsp; 'L', <BR>&nbsp;&nbsp; 'D'}; <BR>&nbsp;&nbsp; for (int intCharacterIndex = 0; <BR>&nbsp;&nbsp; intCharacterIndex &lt; Characters.Length; <BR>&nbsp;&nbsp; intCharacterIndex = intCharacterIndex + 1) <BR>&nbsp;&nbsp; { <BR>&nbsp;&nbsp; sbMessage.Append(Characters[intCharacterIndex]); <BR>&nbsp;&nbsp; } <BR>&nbsp;&nbsp; Console.WriteLine (sbMessage.ToString()); <BR>&nbsp;&nbsp; } <BR>&nbsp;&nbsp; } <BR>&nbsp;&nbsp;} <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;J#代码 <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;package HelloWorld; <BR>&nbsp;&nbsp;import System.*; <BR>&nbsp;&nbsp;import System.Text.*; <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;public class Hello_World <BR>&nbsp;&nbsp;{ <BR>&nbsp;&nbsp; public static void main(String[] args) <BR>&nbsp;&nbsp; { <BR>&nbsp;&nbsp; System.Text.StringBuilder sbMessage = new <BR>&nbsp;&nbsp; System.Text.StringBuilder(); <BR>&nbsp;&nbsp; char[] Characters = new char[] <BR>&nbsp;&nbsp; { <BR>&nbsp;&nbsp; 'H', <BR>&nbsp;&nbsp; 'E', <BR>&nbsp;&nbsp; 'L', <BR>&nbsp;&nbsp; 'L', <BR>&nbsp;&nbsp; 'O', <BR>&nbsp;&nbsp; ' ', <BR>&nbsp;&nbsp; 'W', <BR>&nbsp;&nbsp; 'O', <BR>&nbsp;&nbsp; 'R', <BR>&nbsp;&nbsp; 'L', <BR>&nbsp;&nbsp; 'D'} <BR>&nbsp;&nbsp; ; <BR>&nbsp;&nbsp; for (int intCharacterIndex = 0; <BR>&nbsp;&nbsp; intCharacterIndex &lt; Characters.Length; <BR>&nbsp;&nbsp; intCharacterIndex = intCharacterIndex + 1) <BR>&nbsp;&nbsp; { <BR>&nbsp;&nbsp; sbMessage.Append(Characters[intCharacterIndex]); <BR>&nbsp;&nbsp; } <BR>&nbsp;&nbsp; Console.WriteLine (sbMessage.ToString()); <BR>&nbsp;&nbsp; } <BR>&nbsp;&nbsp;} <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;JScript.NET代码 <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;//@cc_on <BR>&nbsp;&nbsp;//@set @debug(off) <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;import System; <BR>&nbsp;&nbsp;import System.Text; <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;package HelloWorld <BR>&nbsp;&nbsp;{ <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp; public class Hello_World <BR>&nbsp;&nbsp; { <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp; public static function Main() <BR>&nbsp;&nbsp; { <BR>&nbsp;&nbsp; var sbMessage : System.Text.StringBuilder = <BR>&nbsp;&nbsp; new System.Text.StringBuilder(); <BR>&nbsp;&nbsp; var Characters : char[] = <BR>&nbsp;&nbsp; ['H', 'E', 'L', 'L', 'O', ' ', 'W', 'O', 'R', 'L', 'D']; <BR>&nbsp;&nbsp; for (var intCharacterIndex : int = 0; <BR>&nbsp;&nbsp; ; intCharacterIndex &lt; Characters.Length; <BR>&nbsp;&nbsp; intCharacterIndex = intCharacterIndex + 1) <BR>&nbsp;&nbsp; { <BR>&nbsp;&nbsp; sbMessage.Append(Characters[intCharacterIndex]); <BR>&nbsp;&nbsp; } <BR>&nbsp;&nbsp; Console.WriteLine (sbMessage.ToString()); <BR>&nbsp;&nbsp; } <BR>&nbsp;&nbsp; } <BR>&nbsp;&nbsp;} <BR>&nbsp;&nbsp;HelloWorld.Hello_World.Main(); <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;　　总结：CodeDom体现了.NET中语言的重要性不如框架的思想。本文示范了如何运用一些常用的CodeDom类，几乎每一个使用CodeDom技术的应用都要用到这些类。作为一种结构化的代码生成技术，CodeDom有着无限的潜能，唯一的约束恐怕在于人们的想象力。 <img src ="http://www.blogjava.net/huyi/aggbug/3207.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/huyi/" target="_blank">HuYi's Blog</a> 2005-04-13 11:16 <a href="http://www.blogjava.net/huyi/archive/2005/04/13/3207.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>在 C# 中加载自己编写的动态链接库</title><link>http://www.blogjava.net/huyi/archive/2005/04/13/3206.html</link><dc:creator>HuYi's Blog</dc:creator><author>HuYi's Blog</author><pubDate>Wed, 13 Apr 2005 03:13:00 GMT</pubDate><guid>http://www.blogjava.net/huyi/archive/2005/04/13/3206.html</guid><wfw:comment>http://www.blogjava.net/huyi/comments/3206.html</wfw:comment><comments>http://www.blogjava.net/huyi/archive/2005/04/13/3206.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/huyi/comments/commentRss/3206.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/huyi/services/trackbacks/3206.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 一、发生的背景 <BR>&nbsp;&nbsp;　　在开发新项目中使用了新的语言开发 C# 和新的技术方案 WEB Service，但是在新项目中，一些旧的模块需要继续使用，一般是采用 C 或 C++ 或 Delphi 编写的，如何利用旧模块对于开发人员来说，有三种可用方法供选择：第一、将 C 或 C++ 函数用 C# 彻底改写一遍，这样整个项目代码比较统一，维护也方便一些。但是尽管微软以及某些书籍说，C# 和 C++ 如何接近，但是改写起来还是很痛苦的事情，特别是 C++ 里的指针和内存操作；第二、将 C 或 C++ 函数封装成 COM，在 C# 中调用COM 比较方便，只是在封装时需要处理 C 或 C++ 类型和 COM 类型之间的转换，也有一些麻烦，另外COM 还需要注册，注册次数多了又可能导致混乱；第三、将 C 或 C++ 函数封装成动态链接库，封装的过程简单，工作量不大。因此我决定采用加载动态链接库的方法实现，于是产生了在 C# 中如何调用自定义的动态链接库问题，我在网上搜索相关主题，发现一篇调用系统 API 的文章，但是没有说明如何解决此问题，在 MSDN 上也没有相关详细说明。基于此，我决定自己从简单出发，逐步试验，看看能否达到自己的目标。 <BR>&nbsp;&nbsp;　　（说明一点：我这里改写为什么很怕麻烦，我改写的代码是变长加密算法函数，代码有600多行，对算法本身不熟悉，算法中指针和内存操作太多，要想保证算法正确，最可行的方法就是少动代码，否则只要有一点点差错，就不能肯定算法与以前兼容） <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;二、技术实现 <BR>&nbsp;&nbsp;　　下面看看如何逐步实现动态库的加载，类型的匹配，动态链接库函数导出的定义，这个不需要多说，大家参考下面宏定义即可： <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;#define LIBEXPORT_API extern "C" __declspec(dllexport) <BR>&nbsp;&nbsp;第一步，我先从简单的调用出发，定义了一个简单的函数，该函数仅仅实现一个整数加法求和： <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;LIBEXPORT_API int mySum(int a,int b){ return a+b;} <BR>&nbsp;&nbsp;C# 导入定义： <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;public class RefComm <BR>&nbsp;&nbsp;{ <BR>&nbsp;&nbsp;[DllImport("LibEncrypt.dll", <BR>&nbsp;&nbsp;　　　　EntryPoint=" mySum ", <BR>&nbsp;&nbsp;　　　　CharSet=CharSet.Auto,CallingConvention=CallingConvention.StdCall)] <BR>&nbsp;&nbsp;　　　　public static extern int mySum (int a,int b); <BR>&nbsp;&nbsp;} <BR>&nbsp;&nbsp;在C#中调用测试： <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;int iSum = RefComm.mySum(2,3); <BR>&nbsp;&nbsp;运行查看结果iSum为5，调用正确。第一步试验完成，说明在C#中能够调用自定义的动态链接库函数。 <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;第二步，我定义了字符串操作的函数（简单起见，还是采用前面的函数名），返回结果为字符串： <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;LIBEXPORT_API char *mySum(char *a,char *b){sprintf(b,"%s",a); return a;} <BR>&nbsp;&nbsp;C# 导入定义： <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;public class RefComm <BR>&nbsp;&nbsp;{ <BR>&nbsp;&nbsp;[DllImport("LibEncrypt.dll", <BR>&nbsp;&nbsp;　　　　　EntryPoint=" mySum ", <BR>&nbsp;&nbsp;　　　　　CharSet=CharSet.Auto, <BR>&nbsp;&nbsp;　　　　　CallingConvention=CallingConvention.StdCall)] <BR>&nbsp;&nbsp;　　　　　public static extern string mySum (string a, string b); <BR>&nbsp;&nbsp;} <BR>&nbsp;&nbsp;在C#中调用测试： <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;string strDest=""; <BR>&nbsp;&nbsp;string strTmp= RefComm.mySum("12345", strDest); <BR>&nbsp;&nbsp;运行查看结果 strTmp 为"12345"，但是strDest为空。我修改动态链接库实现，返回结果为串b： <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;LIBEXPORT_API char *mySum(char *a,char *b){sprintf(b,"%s",a) return b;} <BR>&nbsp;&nbsp;修改 C# 导入定义，将串b修改为ref方式： <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;public class RefComm <BR>&nbsp;&nbsp;{ <BR>&nbsp;&nbsp;[DllImport("LibEncrypt.dll", <BR>&nbsp;&nbsp;　　　　　EntryPoint=" mySum ", <BR>&nbsp;&nbsp;　　　　　CharSet=CharSet.Auto,CallingConvention=CallingConvention.StdCall)] <BR>&nbsp;&nbsp;　　　　　public static extern string mySum (string a, ref string b); <BR>&nbsp;&nbsp;} <BR>&nbsp;&nbsp;在C#中再调用测试： <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;string strDest=""; <BR>&nbsp;&nbsp;string strTmp= RefComm.mySum("12345", ref strDest); <BR>&nbsp;&nbsp;　　运行查看结果 strTmp 和 strDest 均不对，含不可见字符。再修改 C# 导入定义，将CharSet从Auto修改为Ansi： <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;public class RefComm <BR>&nbsp;&nbsp;{ <BR>&nbsp;&nbsp;[DllImport("LibEncrypt.dll", <BR>&nbsp;&nbsp;　　　　　EntryPoint=" mySum ", <BR>&nbsp;&nbsp;　　　　　CharSet=CharSet.Ansi,CallingConvention=CallingConvention.StdCall)] <BR>&nbsp;&nbsp;　　　　　public static extern string mySum (string a, string b); <BR>&nbsp;&nbsp;} <BR>&nbsp;&nbsp;在C#中再调用测试： <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;string strDest=""; <BR>&nbsp;&nbsp;string strTmp= RefComm. mySum("12345", ref strDest); <BR>&nbsp;&nbsp;　　运行查看结果 strTmp 为"12345"，但是串 strDest 没有赋值。第二步实现函数返回串，但是在函数出口参数中没能进行输出。再次修改 C# 导入定义，将串b修改为引用（ref）： <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;public class RefComm <BR>&nbsp;&nbsp;{ <BR>&nbsp;&nbsp;[DllImport("LibEncrypt.dll", <BR>&nbsp;&nbsp;　　　　　EntryPoint=" mySum ", <BR>&nbsp;&nbsp;　　　　　CharSet=CharSet.Ansi,CallingConvention=CallingConvention.StdCall)] <BR>&nbsp;&nbsp;　　　　　public static extern string mySum (string a, ref string b); <BR>&nbsp;&nbsp;} <BR>&nbsp;&nbsp;运行时调用失败，不能继续执行。 <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;第三步，修改动态链接库实现，将b修改为双重指针： <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;LIBEXPORT_API char *mySum(char *a,char **b){sprintf((*b),"%s",a); return *b;} <BR>&nbsp;&nbsp;C#导入定义： <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;public class RefComm <BR>&nbsp;&nbsp;{ <BR>&nbsp;&nbsp;[DllImport("LibEncrypt.dll", <BR>&nbsp;&nbsp;　　　　　EntryPoint=" mySum ", <BR>&nbsp;&nbsp;　　　　　CharSet=CharSet.Ansi,CallingConvention=CallingConvention.StdCall)] <BR>&nbsp;&nbsp;　　　　　public static extern string mySum (string a, ref string b); <BR>&nbsp;&nbsp;} <BR>&nbsp;&nbsp;在C#中调用测试： <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;string strDest=""; <BR>&nbsp;&nbsp;string strTmp= RefComm. mySum("12345", ref strDest); <BR>&nbsp;&nbsp;　　运行查看结果 strTmp 和 strDest 均为"12345"，调用正确。第三步实现了函数出口参数正确输出结果。 <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;第四步，修改动态链接库实现，实现整数参数的输出： <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;LIBEXPORT_API int mySum(int a,int b,int *c){ *c=a+b; return *c;} <BR>&nbsp;&nbsp;C#导入的定义： <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;public class RefComm <BR>&nbsp;&nbsp;{ <BR>&nbsp;&nbsp;[DllImport("LibEncrypt.dll", <BR>&nbsp;&nbsp;　　　　　EntryPoint=" mySum ", <BR>&nbsp;&nbsp;　　　　　CharSet=CharSet.Ansi,CallingConvention=CallingConvention.StdCall)] <BR>&nbsp;&nbsp;　　　　　public static extern int mySum (int a, int b,ref int c); <BR>&nbsp;&nbsp;} <BR>&nbsp;&nbsp;在C#中调用测试： <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;int c=0; <BR>&nbsp;&nbsp;int iSum= RefComm. mySum(2,3, ref c); <BR>&nbsp;&nbsp;运行查看结果iSum 和c均为5，调用正确。 <BR>&nbsp;&nbsp;　　经过以上几个步骤的试验，基本掌握了如何定义动态库函数以及如何在 C# 定义导入，有此基础，很快我实现了变长加密函数在 C# 中的调用，至此目标实现。 <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;三、结论 <BR>&nbsp;&nbsp;　　在 C# 中调用 C++ 编写的动态链接库函数，如果需要出口参数输出，则需要使用指针，对于字符串，则需要使用双重指针，对于 C# 的导入定义，则需要使用引用（ref）定义。 <BR>&nbsp;&nbsp;　　对于函数返回值，C# 导入定义和 C++ 动态库函数声明定义需要保持一致，否则会出现函数调用失败。定义导入时，一定注意 CharSet 和 CallingConvention 参数，否则导致调用失败或结果异常。运行时，动态链接库放在 C# 程序的目录下即可，我这里是一个 C# 的动态链接库，两个动态链接库就在同一个目录下运行。 <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp;原文出处：：http://windend.blogchina.com <BR><img src ="http://www.blogjava.net/huyi/aggbug/3206.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/huyi/" target="_blank">HuYi's Blog</a> 2005-04-13 11:13 <a href="http://www.blogjava.net/huyi/archive/2005/04/13/3206.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C# Tip: Monitoring Clipboard Activity in C#</title><link>http://www.blogjava.net/huyi/archive/2005/03/25/2448.html</link><dc:creator>HuYi's Blog</dc:creator><author>HuYi's Blog</author><pubDate>Fri, 25 Mar 2005 11:26:00 GMT</pubDate><guid>http://www.blogjava.net/huyi/archive/2005/03/25/2448.html</guid><wfw:comment>http://www.blogjava.net/huyi/comments/2448.html</wfw:comment><comments>http://www.blogjava.net/huyi/archive/2005/03/25/2448.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/huyi/comments/commentRss/2448.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/huyi/services/trackbacks/2448.html</trackback:ping><description><![CDATA[<A href="http://www.developer.com/net/csharp/article.php/3359891">http://www.developer.com/net/csharp/article.php/3359891</A><img src ="http://www.blogjava.net/huyi/aggbug/2448.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/huyi/" target="_blank">HuYi's Blog</a> 2005-03-25 19:26 <a href="http://www.blogjava.net/huyi/archive/2005/03/25/2448.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>.NET工具介绍</title><link>http://www.blogjava.net/huyi/archive/2005/01/26/715.html</link><dc:creator>HuYi's Blog</dc:creator><author>HuYi's Blog</author><pubDate>Wed, 26 Jan 2005 00:43:00 GMT</pubDate><guid>http://www.blogjava.net/huyi/archive/2005/01/26/715.html</guid><wfw:comment>http://www.blogjava.net/huyi/comments/715.html</wfw:comment><comments>http://www.blogjava.net/huyi/archive/2005/01/26/715.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/huyi/comments/commentRss/715.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/huyi/services/trackbacks/715.html</trackback:ping><description><![CDATA[<P>对常用的工具有个比较详细的介绍。</P>
<P><A href="http://www.cnblogs.com/William_Fire/archive/2005/01/13/91035.html">http://www.cnblogs.com/William_Fire/archive/2005/01/13/91035.html</A></P><img src ="http://www.blogjava.net/huyi/aggbug/715.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/huyi/" target="_blank">HuYi's Blog</a> 2005-01-26 08:43 <a href="http://www.blogjava.net/huyi/archive/2005/01/26/715.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>