C语言的结构体中怎么包含枚举类型?

C语言的结构体中怎么包含枚举类型?,第1张

#include <stdio.h>

enum types

{

    TYPE_1,

    TYPE_2,

    type_3

}

struct aaa

{

    int a

    enum types b    

}

int main(int argc, char *argv[])

{

    struct aaa A

    

    A.a = TYPE_1

    A.b = TYPE_2

    

    return 0

}

结构体中aaa中的a和b都可以表示枚举类型

一、最小化窗口

点击“X”或“Alt F4”时,最小化窗口,如:

protected override void WndProc(ref Message m)

{

const int

WM_SYSCOMMAND = 0x0112

const int SC_CLOSE = 0xF060

if (m.Msg ==

WM_SYSCOMMAND &&(int) m.WParam == SC_CLOSE)

{

// User clicked

close button

this.WindowState =

FormWindowState.Minimized

return

}

base.WndProc(ref m)

}

二、如何让Foreach 循环运行的更快

foreach是一个对集合中的元素进行简单的枚举及处理的现成语句,用法如下例所示:

using System

using System.Collections

namespace

LoopTest

{

class Class1

{

static void Main(string[] args)

{

//

create an ArrayList of strings

ArrayList array = new

ArrayList()

array.Add("Marty")

array.Add("Bill")

array.Add("George")

//

print the value of every item

foreach (string item in

array)

{

Console.WriteLine(item)

}

}

}

你可以将foreach语句用在每个实现了Ienumerable接口的集合里。如果想了解更多foreach的用法,你可以查看.NET Framework

SDK文档中的C# Language Specification。

在编译的时候,C#编辑器会对每一个foreach 区域进行转换。

IEnumerator enumerator = array.GetEnumerator()

try

{

string

item

while (enumerator.MoveNext())

{

item = (string)

enumerator.Current

Console.WriteLine(item)

}

}

finally

{

IDisposable d = enumerator as IDisposable

if (d != null)

d.Dispose()

}

这说明在后台,foreach的管理会给你的程序带来一些增加系统开销的额外代码。

三、将图片保存到一个XML文件

WinForm的资源文件中,将PictureBox的Image属性等非文字内容都转变成文本保存,这是通过序列化(Serialization)实现的,

例子://

using System.Runtime.Serialization.Formatters.Soap

Stream stream = new

FileStream("E://Image.xml",FileMode.Create,FileAccess.Write,FileShare.None)

SoapFormatter

f = new SoapFormatter()

Image img =

Image.FromFile("E://Image.bmp")

f.Serialize(stream,img)

stream.Close()

四、屏蔽CTRL-V

在WinForm中的TextBox控件没有办法屏蔽CTRL-V的剪贴板粘贴动作,如果需要一个输入框,但是不希望用户粘贴剪贴板的内容,可以改用RichTextBox控件,并且在KeyDown中屏蔽掉CTRL-V键,例子:

private void richTextBox1_KeyDown(object sender,

System.Windows.Forms.KeyEventArgs e)

{

if(e.Control &&

e.KeyCode==Keys.V)

e.Handled = true

}

ps: 网上摘抄,看了以后感觉不错,以后碰见好的再陆续发布

Tags: dotnet技术 , c#开发技术

ASP.NET 2.0中使用webpart系列控件

Dot-Net技术 | 阅读(144) | 评论(0)

Oct

29

2005

[此文来源于互联网,牛C网只负责收集整理]

在现在的网站设计中,更强调的是用户的个性化设置,让用户可以自由的设置符合自己喜好的页面成为网站开发人员的头号难题,不过现在看来这个难题微软帮我们解决了。在asp.net

2.0中新增加了一系列webpart控件,可以让用户很方便地对网页的各区域布局进行调整。在一些web应用程序中,如果用户想自定义页面布局,比如一个新闻发布系统,想让左,中,右三栏的位置进行调换的话,就可以使用webpart控件。

下面,我们来看下asp.net 2.0中webpart系列控件的一些基本用法。

首先,在vs.net 2005 中的工具箱中,可以找到如下图所示的webpart系列控件,有很多个,限于篇幅,本文介绍其中的一些重要的控件:

 

在webpart系列控件中,其中的webpartmanager控件用于统一管理各webpart控件。而webpartzone控件,则是提供了各区域划分,在这些区域中,用户可以往里面放置各式各样的控件,而当运行的时候,用户可以移动的就是这些webpartzone控件所在的区域。

为增强认识,我们先做个简单的例子。

1、首先使用vs.net 2005 beta 2(或者RC1)新建一个web站点,

2、往窗体中拖拉一个webpartmanager控件,再建一个3列1行的表格,分别往每个单元格里拖拉一个webpartzone控件,如下图:

 

3、往webpartzone1中拖拉放一个日历控件,并为这个日历控件选择一个合适的样式

4、切换到代码视图状态,将日历控件的title属性改为:today’s

date。注意的是,日历控件本身没有title属性,但当一个控件加入到webpartzone区域中去后,则该控件被自动包装为GenericWebPart类型控件,这些类型的控件有title属性。

5、这时,我们可以按F5来运行该程序,运行如下图所示,可以看到,区域的右上角有最小化和关闭,恢复的按钮。

接下来,我们介绍如何在webpart系列控件中,使用用户自定义的控件。

1、首先,我们为工程项目增加一个"google.ascx"的控件,并且在images目录下,添加google那张著名的logo图片。

接着,往窗体中添加一个2*2行的表格,再往其中的一个单元格添加一个image图象控件,指定其图象为google.gif,再添加一个文本框,一个按钮,如下图所示,其中,括号内的是该控件的名称: 

3、在btnsearch按钮的click事件中写入如下代码:

 Response.Write(Page.IsValid)

 Dim queryStr As String =

HttpUtility.UrlEncode(txtSearch.Text)

 Response.Redirect("http://www.google.com/search?q=" &

queryStr)

End Sub

4、这时,将写好的google.ascx控件,整个拖拉到我们刚才建立好的表格中的中间那个单元格,如下图所示:

我们并且修改代码如下,修改其名称为google serach:

<uc1:Google title="Google Search" runat="server" ID="Google1" />

接下来,F5运行,可以看到,可以在googlesearch所在的webpart里进行google搜索了。

同时,如果觉得webpart的那些关闭,恢复,最小化的按钮不大好看,还可以自定义按钮,比如在images目录下,添加下面的图片:

然后,在webpartzone1的属性中,指定如下的属性就可以了。 

CloseVerb.ImageUrl="Images/CloseVerb.gif"

EditVerb.ImageUrl="Images/EditVerb.gif"

MinimizeVerb.ImageUrl="Images/MinimizeVerb.gif"

RestoreVerb.ImageUrl="Images/RestoreVerb.gif"

使webpart动起来

上面设计的webpart还没能动起来,要让webpart动起来的话,必须要将webpar设置为design display

模式。先为webpart添加下面的radiobutton选择框

<asp:RadioButtonList ID="rblMode" runat="server"

AutoPostBack="True">

 <asp:ListItem>Browse Display

Mode</asp:ListItem>

 <asp:ListItem>Design Display

Mode</asp:ListItem>

</asp:RadioButtonList>

并且在code-behind的代码中,写入如下代码:

Protected Sub RadioButtonList1_SelectedIndexChanged(ByVal sender As

Object, _ ByVal e As System.EventArgs) _ Handles

rblMode.SelectedIndexChanged

 Select Case rblMode.SelectedIndex

Case 0 :

WebPartManager1.DisplayMode =WebPartManager.BrowseDisplayMode

Case 1 :

WebPartManager1.DisplayMode = WebPartManager.DesignDisplayMode

 End

Select

End Sub 

运行上面代码,选择design display mode,则可以象下图那样,自由拖动webpart,

要注意的是,当移动各webpart的位置后,即使关掉浏览器,下次重新打开时,依然可以看到各个控件保持原来的位置。其实,asp.net

2.0是使用在aspnetdb.mdf中的一个叫aspnet_PersonalizationPerUser的表来保存数据的,表的结构如下所示:

 

Field

Value

Id 928e121a-4042-4fb4-9520-21210b9b37c1

PathId

7c3b5dc0-04d0-48a2-bbb2-2b70286f22fe

UserId

9bff14df-024f-4bda-9a0a-b4a19ab9e387

PageSettings <Binary data>

LastUpdatedDate 10/06/2005 4:44:05 AM

如果想恢复各控件的原来位置,只需要将该数据表中相应的行删除掉就可以了。但有个问题是,如果使用每一个webpart的关闭按钮,则很难再将其恢复(当然删除数据表中的行,但十分麻烦)。在asp.net

2.0中,提供了另一种webpart,叫做catlogzone控件,下面介绍其用法:

1、往窗体中拖拉一个catlogzone控件,如下图所视。

2、往该catlogzone控件区域中,再拖放三个webpart系列的控件,分别是DeclarativeCatalogPart,

PageCatalogPart, and

ImportCatalogPart,如下图所示。其中,DeclarativeCatalogPart控件的作用是,显示目前页面上有哪些可以用的webpart控件;PageCatalogPart的作用是,可以让用户通过勾选的方式,选定将哪些控件添加转移到其他webpart区域中去。ImportCatalogPart则可以通过外部磁盘文件的方式,加载其他做好了的webpart部件。

3、在radiobutton区域中,修改以下代码,增添一个catalog display的显示模式:

<asp:RadioButtonList ID="rblMode" runat="server"

AutoPostBack="True">

<asp:ListItem>Browse Display

Mode</asp:ListItem>

<asp:ListItem>Design Display

Mode</asp:ListItem>

<asp:ListItem>Catalog Display

Mode</asp:ListItem>

</asp:RadioButtonList>

然后,在code-behind的代码中,将代码修改为如下:

Protected Sub rblMode_SelectedIndexChanged( _

 ByVal sender As Object,

_

 ByVal e As System.EventArgs) _

 Handles

rblMode.SelectedIndexChanged

Select Case rblMode.SelectedIndex

 Case 0

: WebPartManager1.DisplayMode = WebPartManager.BrowseDisplayMode

 Case 1 :

WebPartManager1.DisplayMode = WebPartManager.DesignDisplayMode

 Case 2 :

WebPartManager1.DisplayMode = WebPartManager.CatalogDisplayMode

End

Select

End Sub

4、在DeclarativeCatalogPart任务菜单上,点击右上角的智能感知按钮,然后选"edit

templates"的链接,进入模版编辑状态,如下图:

再往其中的webpartstemplate区域中拖拉一个google.ascx控件,如下图,这将允许用户在运行时,可以自由地往页面增加这样的google搜索控件。

5、然后修改代码如下:

<ZoneTemplate>

<asp:DeclarativeCatalogPart

ID="DeclarativeCatalogPart1"

runat="server">

 <WebPartsTemplate>

<uc1:Google title="Google Search"

ID="Google2" runat="server"

/>

 </WebPartsTemplate>

</asp:DeclarativeCatalogPart>

6、运行程序,可以看到,当选择catalog display mode时,会显示如下图所示的catalog

zone,其中列出了当前可用的有哪些webpart控件,我们可以把这个google的控件加到其他的webpart区域,也可以尝试将已经存在的webpart控件关闭,然后在catalog

zone区域中的控件列表中,把它们再加回到页面中去。

此外,在运行期间,还可以动态地修改webpart控件的外观等属性,如下:

1) 往窗体中添加一个editor

zone的区域控件,往其中再拖放一个appearanceEdiotrPart控件,该控件可以在运行时,让用户动态改变各webpart控件的属性。

2) 我们再修改radiobutton选择框的代码如下,则加一个编辑模式:

<asp:RadioButtonList ID="rblMode" runat="server"

AutoPostBack="True">

<asp:ListItem>Browse Display

Mode</asp:ListItem>

<asp:ListItem>Design Display

Mode</asp:ListItem>

<asp:ListItem>Catalog Display

Mode</asp:ListItem>

<asp:ListItem>Edit Display

Mode</asp:ListItem>

</asp:RadioButtonList>

3) 修改code-behind代码如下:

Protected Sub rblMode_SelectedIndexChanged(ByVal sender As Object, ByVal

e As System.EventArgs) _

Handles rblMode.SelectedIndexChanged

 Select Case

rblMode.SelectedIndex

Case 0 : WebPartManager1.DisplayMode =

WebPartManager.BrowseDisplayMode

Case 1 : WebPartManager1.DisplayMode =

WebPartManager.DesignDisplayMode

Case 2 : WebPartManager1.DisplayMode =

WebPartManager.CatalogDisplayMode

Case 3 : WebPartManager1.DisplayMode =

WebPartManager.EditDisplayMode

 End Select

End Sub

4) 运行程序,选择edit display

mode模式,这时,会发现每个控件的右上角,会多了一个"edit"的按钮,点该按钮,d出如下图的窗体,用户可以修改每个控件的外观等属性。

最后,我们看下,webpart控件之间还可以进行相互之间的通信,下面的例子中,要实现的是,在一个日历控件中点选某一个日期,会在已经做好的googlesearch的webpart控件的文本框中显示其日期,达到通信的目的,下面介绍其实现步骤:

1、为了使两个webpart控件之间进行通信,必须先声明一个公共的接口。往工程项目里增加一个叫ISelectedDate.vb的类文件,放在app_code目录下,写入如下代码:

Imports Microsoft.VisualBasic

 Public Interface

ISelectedDate

 ReadOnly Property SelectedDate( ) As Date

End Interface

这里,我们返回一个只读的日期属性selectedDate.

2、再创建一个日历控件CalendarUC.ascx,其中拖拉一个普通的日历控件即可。然后写入如下代码:

Partial Class CalendarUC_ascx

Inherits

System.Web.UI.UserControl

Implements ISelectedDate

Public ReadOnly Property SelectedDate( ) As Date Implements

ISelectedDate.SelectedDate

 Get

Return

Calendar1.SelectedDate.Date

 End Get

End Property

<ConnectionProvider("SelectedDate", "SelectedDate")> _

Public Function

GetSelectedDate( ) As ISelectedDate

 Return Me

End Function

End

Class

上面的代码,首先实现了已经声明了的IselectedDate接口,要留意的是<ConnectionProvider("SelectedDate",

"SelectedDate")>中的写法。由于在这个例子中,日历控件要为其他的控件提供信息,因此,该日历控件是一个provider(提供者),而另外的接收信息的控件,是consumer(消费者)。而两者为了要通信,必须要提供一个通信接入点,就象一个电插头,要找到合适的电插板一样。因此,<ConnectionProvider("SelectedDate",

"SelectedDate")>中的第一个参数,定义了两者的接口点,第二个参数,则是要传递给consumer的参数,本例是selectedDate。

3、接下来,我们在已经做好的google.ascx控件的代码中,编写如下代码:

Private _selectedDate As ISelectedDate

<ConnectionConsumer("SelectedDate", "SelectedDate")> _

Sub

setSearchText(ByVal SearchText As ISelectedDate)

 Me._selectedDate =

SearchText

End Sub

Protected Sub Page_PreRender(ByVal sender As Object, ByVal e As

System.EventArgs) Handles Me.PreRender

 If _selectedDate IsNot Nothing

Then

txtSearch.Text = _selectedDate.SelectedDate.ToShortDateString

 End

If

End Sub

可以看到 <ConnectionConsumer("SelectedDate",

"SelectedDate")>的定义必须和provider中的定义一样。

4、再修改如下代码,将两个控件的命名变得通俗易懂

<ZoneTemplate>

 <uc1:Google title="Google Search" runat="server"

ID="Google1" />

 <uc3:CalendarUC title="Calendar Web Part" runat="server"

ID="CalendarUC1" />

</ZoneTemplate>

5、最后,为了使两者能互相通信,必须在default.aspx页中修改如下代码:

<asp:WebPartManager ID="WebPartManager1"

runat="server">

<StaticConnections>

<asp:WebPartConnection ID="Connection"

ProviderID="CalendarUC1"

ProviderConnectionPointID="SelectedDate"

ConsumerID="Google1"

ConsumerConnectionPointID="SelectedDate"

/>

</StaticConnections>

</asp:WebPartManager>

6、在页面代码中,增加一个radiobutton,用作显示connection模式,并写入如下代码:

Case 4 : WebPartManager1.DisplayMode =

WebPartManager.ConnectDisplayMode

7、运行程序,选择connect displaymode模式。再选择GOOGLE

SEARCH的那个webpart控件,点右上角的"conenct"按钮,此时,会显示如下图所示,提示你要选择从那个控件中得到信息,这里选择日历控件,按确定。那么,当点选日历控件的某个日期值的时候,GOOGLE

SEARCH的那个文本框里,就会显示相应的日期了。

首先,应该在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调用DLLd出提示框”,并将按钮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 d出的提示框哦! "," 挑战杯 ",0x30)

6. 按“F5”运行该程序,并点击按钮B1,便d出如下提示框:

(二) 动态装载、调用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,便d出如下三个提示框:

第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

}


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/bake/11841919.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-19
下一篇 2023-05-19

发表评论

登录后才能评论

评论列表(0条)

保存