2024年1月19日发(作者:)
DLL与LIB文件的区别
共有两种库:
一种是LIB包含了函数所在的DLL文件和文件中函数位置的信息(入口),代码由运行时加载在进程空间中的DLL提供,称为动态链接库dynamic link library。
一种是LIB包含函数代码本身,在编译时直接将代码加入程序当中,称为静态链接库static link library。
共有两种链接方式:
动态链接使用动态链接库,允许可执行模块(.dll文件或.exe文件)仅包含在运行时定位DLL函数的可执行代码所需的信息。
静态链接使用静态链接库,链接器从静态链接库LIB获取所有被引用函数,并将库同代码一起放到可执行文件中。
关于lib和dll的区别如下:
(1)lib是编译时用到的,dll是运行时用到的。如果要完成源代码的编译,只需要 lib;如果要使动态链接的程序运行起来,只需要dll。
(2)如果有dll文件,那么lib一般是一些索引信息,记录了dll中函数的入口和位置,dll中是函数的具体内容;如果只有lib文件,那么这个lib文件是静态编译出来的,索引和实现都在其中。使用静态编译的lib文件,在运行程序时不需要再挂动态库,缺点是导致应用程序比较大,而且失去了动态库的灵活性,发布新版本时要发布新的应用程序才行。
(3)动态链接的情况下,有两个文件:一个是LIB文件,一个是DLL文件。LIB包含被DLL导出的函数名称和位置,DLL包含实际的函数和数据,应用程序使用LIB文件链接到DLL 文件。在应用程序的可执行文件中,存放的不是被调用的函数代码,而是DLL中相应函数代码的地址,从而节省了内存资源。DLL和LIB文件必须随应用程序一起发行,否则应用程序会产生错误。如果不想用lib文件或者没有lib文件,可以用WIN32 API函数LoadLibrary、GetProcAddress装载。
使用lib需注意两个文件:
(1).h头文件,包含 lib中说明输出的类或符号原型或数据结构。应用程序调用lib时,需要将该文件包含入应用程序的源文件中。
(2).LIB文件,略。
使用dll需注意三个文件:
(1).h头文件,包含dll中说明输出的类或符号原型或数据结构的.h文件。应用程序调用dll时,需要将该文件包含入应用程序的源文件中。
(2).LIB文件,是dll在编译、链接成功之后生成的文件,作用是当其他应用程序调用dll时,需要将该文件引入应用程序,否则产生错误。若是不想用lib文件或没有lib文件,能够用WIN32 API函数LoadLibrary、GetProcAddress装载。
(3).dll文件,真正的可执行文件,开发成功后的应用程序在发布时,只需要有.exe文件和.dll文件,并非需要.lib文件和.h头文件。
DLL与Lib的区别:
1. DLL是一个编译好的程序,调历时能够直接挪用其中的函数,不参加工程的编译
是一个程序集,只是把相应的函数总结在一路,若是挪用Lib的函数在工程编译时,这些函数也参加编译
dll和lib文件
(1)lib是编译时需要的,dll是运行时需要的。
若是要完成源代码的编译,有lib就够了。
若是也使动态连接的程序运行起来,有dll就够了。
在开发和调试时期,固然最好都有。
(2) 一样的动态库程序有lib文件和dll文件。lib文件是必需在编译期就连接到应用程序中的,而dll文件是运行期才会被挪用的。若是有dll文件,那么对应的lib文件一样是一些索引信息,具体的实此刻dll文件中。若是只有lib文件,那么那个lib文件是静态编译出来的,索引和实现都在其中。静态编译的lib文件有益处:给用户安装时就不需要再挂动态库了。但也有缺点,确实是致使应用程序比较大,而且失去了动态库的灵活性,在版本升级时,同时要发布新的应用程序才行。
(3)在动态库的情形下,有两个文件,一个是引入库(.LIB)文件,一个是DLL文件,引入库文件包括被DLL导出的函数的名称和位置,DLL包括实际的函数和数据,应用程序利用LIB文件链接到所需要利用的DLL文件,库中的函数和数据并非复制到可执行文件中,因此在应用程序的可执行文件中,寄存的不是被挪用的函数代码,而是DLL中所要挪用的函数的内存地址,如此当一个或多个应用程序运行是再把程序代码和被挪用的函数代码链接起来,从而节省了内存资源。从上面的说明能够看出,DLL和.LIB文件必需随应用程序一路发行,不然应用程序将会产生错误。
(4).dll是在你的程序运行的时候才连接的文件,因此它是一种比较小的可执行文件格式,.dll还有其他的文件格式如.ocx等,所有的.dll文件都是可执行。 .lib是在你的程序编译连接的时候就连接的文件,因此你必需告知编译器连接的lib文件在那里。一样来讲,与动态连接文件相对照,lib文件也被称为是静态连接库。当你把代码编译成这几种格式的文件时,在以后他们就不可能再被更改。若是你想利用lib文件,就必需:
1 包括一个对应的头文件告知编译器lib文件里面的具体内容
2 设置lib文件许诺编译器去查找已经编译好的二进制代码
若是你想从你的代码分离一个dll文件出来代替静态连接库,仍然需要一个lib文件。那个lib文件将被连接到程序告知操作系统在运行的时候你想用到什么 dll文件,一样情形下,lib文件里有相应的dll文件的名字和一个指明dll输出函数入口的顺序表。若是不想用lib文件或是没有lib文件,能够用WIN32 API
函数LoadLibrary、GetProcAddress。事实上,咱们能够在Visual C++ IDE中以二进制形式打开lib文件,大多情形下会看到ASCII码格式的C++函数或一些重载操作的函数名字。
一样咱们最要紧的关于lib文件的麻烦确实是显现unresolved symble 这种错误,这确实是lib文件连接错误或没有包括.c、.cpp文件到工程里,关键是若是在C++工程里用了C语言写的lib文件,就必需要如此包括:
extern "C"
{
#include ""
}
这是因为C语言写的lib文件没有C++所必需的名字破坏,C函数不能被重载,因此连接器会犯错。
在vs2020中编写dll如何生成lib文件
vs2020默许生成dll,但不生成Lib文件,方式是:在所建工程上单击鼠标右键,在弹出的右键菜单当选择“添加-->新建项....---->模块概念文件”,在该模块概念文件中写导出函数表,单击确信。然后在所建工程上单击鼠标右键,选择“属性”菜单,在弹出的属性对话框中“链接器-->输入-->模块概念文件”中填写适才概念的def文件,然后再从头编译即可生成LIB文件。
一 VS2020生成dll文件的方式
有两种方式:
1:傻瓜式操作
打开VS2020,依次点击:菜单->文件->新建项目->项目类型visual C#(那个地址假设为该项目所取的名字是DllBuild)->类库(注意必需是类库),即新建一个由纯.cs类库文件组成的程序集,写好代码以后(例如写了一个名为的类,该类的namespace取名为DllTestNS), 再依次点击:菜单->生成->生成DllBuild,如此你的DllBuild/DllBuild/bin/Debug文件夹或 DllBuild/DllBuild/obj/Debug文件夹里便会自动生成dll文件啦,该文件名称与项目名称一致,即为。
2:利用VS命令行
依次点击:开始->运行,输入cmd,在打开的命令行窗口中输入:cd ,按回车,输入下面一行命令:
cd c:Program FilesMicrosoft Visual Studio 8SDK>csc /target:library /out:d: d:
按回车,如此,便将d: 文件编译为dll文件并保留为d:。
在那个地址有可能会报错,缘故是文件找不到。现在只需打开资源阅读器explorer,在“我的电脑”中搜索“”文件即可,比如我的文件即是在:
C:WINDOWSFramework。为了不至于每次编译dll时都要输入如此长的VS命令行途径,咱们能够将该途径添加到系统环境变量中。具体的添加方式请见: 。当添加完环境变量后,此刻要将.cs文件编译为dll文件便十分方便:
点击“开始”->“运行”,输入: csc /target:library /out:d: d:
如此便直接进行编译。
二 dll文件的引用及动态加载
引用dll文件
c++文件必需有头文件和lib文件方能编译通过,在运行时还必需挪用相应的dll文件;而c#那么直接将头文件和lib文件都封装进dll文件中,因此,c#编程无需再引入这两个文件,可是在运行时或编译时很多时候都需要引用dll文件。
在上一步,咱们生成(Build)了名为DllBuild的项目,并生成了文件,此刻咱们从头新建一个模板类型为Console Application(操纵台应用程序)的项目,名为DllInvoke, 新建好项目以后,从资源阅读器中打开该项目,依次打开DllInvokeDllInvokebinDebug,将适才生成的 文件复制到Debug目录下,同时打开DllInvokeDllInvoke文件(右击, 用记事本打开),打开后内容如下:
可 以看到,该文件要紧描述了改项目的一些系统配置和属性,例如项目名称和根命名空间名称、调试方式等等。由于要引用dll文件,因此咱们需要在该xml格式 的文件中添加关于该dll文件的描述信息,添加到
反编译C#生成的DLL文件--学习源代码的好软件Reflector利用手记
打开Reflector工具而且下载了一个FileDisassembler插件,FileDisassembler插件用于输出程序 集的反编译结果到文件中。打开Reflector工具,并导入FileDisassembler插件。导入好
后加载程序集将反编译结果输出到指定的文件夹 中;
Reflector下载地址: 下载时必须输入用户名和Email地址,用户名中必须有空格;
FileDisassembler插件的下载地址:
使用新建一个项目,根据文件夹结构新建相应的文件夹,导入所有的源文件和资源文件。使用FileDisassembler导出的资源文件为全 名称,在实际的项目中必须根据namespace更改资源文件名且必须将“生成操作”更改为“嵌入的资源”,可以使用ILDASM查看metadata来 决定资源文件名及所在的文件夹,编译并更改一些错误;
当编译好后,找到所有与COM有关的内容将其注释掉(因为以前使用过CCW/RCW技术),并做相应的更改,每更改一个class后,编译一次,直到去掉其相关引用为止;
更改完成后,需要对其进行重构,主要重构以下方面:
rename,因为Reflector工具反编译时其变量名会根据类型来命名,如text1,text2,num1等;
去掉goto语句,如果代码中有swtich语句时,Reflector工具会使用goto语句,严重影响程序逻辑其可读性;
Extract Method,将过于长的method执行分解操作;
当重构完成后,应用到项目中,并更改相应的Register语句,test,run,结果是successful,从而也在最短的时间内完成了项目经理所交给我的任务。
先行说明:在reflect时,请遵守ESRI公司的End User Licenses。
cs编译成DLL文件cs文件如何生成exe,dll文件
cs编译成DLL文件cs文件如何生成exe,dll文件
以下是本人的制作过程:
盘下有一个 文件。
2.开始-》程序-》Microsoft Visual Studio 2005-》Visual Studio Tools-》Visual Studio
2005 命令提示
3.命令提示符山输入:csc /target:library /out:E: E:
即可在E盘生成一个名为MyTestDLL的dll文件,该dll的主题是
备注:
我在生成自己的DLL时出现这种错误:
e:(8,29): error CS0234:
命名空间“”中不存在类型或命名空间名称“CompilerServices”(是缺少程序集引用吗?)
因为我这个类中第八行有着样的引用“using ;然而vs2005c#程序不能引用到VB中的类库。所以报错。
我的解决办法是:
找到我自己电脑上该VB类库的路径,引入编译。
/reference:C:WINDOWSFrameworkv2
.
完整的语句这样:
csc /target:library /out:E: E: /reference:C:WINDOWSFramework祝大家解决问题!以下是摘录:
1、打开 Microsoft .NET Framework SDK --> SDK Command Prompt
2、指定cs文件所在的目录(如 E:)
3、运行命令 csc /? 查看所有的命令以及各自的参数
4、csc /target:exe *.cs (生成exe文件)----/t:exe *.cs (Short form)
5、csc /target:library *.cs (生成dll文件)-- /t:library *.cs (Short form)
在网上搜索到的,一般不详细,这个比较详细,果然实验成功。
现在的问题,这个DLL如何调用?
似乎的很好调用,ASP能调用吗?
其他语言能调用吗?
通过在命令行上键入 C# 编译器可执行文件的名称 ,可以在命令行调用 C# 编译器。如果希望
从计算机上的任何子目录调用 ,可能需要调整路径。
命令行语法规则
当解释操作系统命令行上给出的参数时,C# 编译器代码使用下面的规则:
参数用空白分隔,空白可以是一个空格或制表符。
^ 字符 (^) 未被识别为转义符或者分隔符。该字符在被传递给程序中的 argv 数组前,完全由操作系统的命令行分析器进行处理。
无论其中有无空白,包含在双引号 ("string") 中的字符串均被解释为单个参数。带引号的字符串可以嵌入在参数内。
前面有反斜杠的双引号 (") 被解释为原义双引号字符 (")。
反斜杠按其原义解释,除非它们紧位于双引号之前。
如果偶数个反斜杠后跟双引号,则每对反斜杠中的一个反斜杠放置在 argv 数组中,并且双引号被解释为字符串分隔符。
如果奇数个反斜杠后跟双引号,则每对反斜杠中的一个反斜杠放置在 argv 数组中,双引号由其余的反斜杠“转义”,使原义双引号 (") 被放置在 argv 数组中。
命令行示例
编译 以产生 :
csc
编译 以产生 :
csc /target:library
编译 并创建 :
csc /out:
通过使用优化和定义 DEBUG 符号,编译当前目录中所有的 C# 文件。输出为 :
csc /define:DEBUG /optimize /out: *.cs
编译当前目录中所有的 C# 文件,以产生 的调试版本。不显示任何徽标和警告:
csc /target:library /out: /warn:0 /nologo /debug *.cs
将当前目录中所有的 C# 文件编译为 (一个 DLL):
csc /target:library /out: *.cs
VC2020编写Dll文件[转载]
1、 打开VS2010【Flie / New / Project / Visual
C++ / Win32 / Win32 Console Application】在下面输入一个名称,比如mydll,然后【OK / Next】,然后在Application Type里选择Dll,在Additional
Options里选择Exports Symbols,最后点击Finish。
2、在里面已经有相关的例子模板了。可以照着他的写法写自己的函数。但是注意,对于有参数传递的函数,编写格式如下:
MYDLL_API int _stdcall MaxNumber(int x,int y)
{
if (x>y)
return x;
return y;
}
即多了个_stdcall ,这个是需要注意的,函数写好后,还要在里进行申明。它里面也有相应函数的申明格式,对于上面那个函数,申明也要加_stdcall 。即应该申明为MYDLL_API int
_stdcall MaxNumber(int x,int y)。
3、现在写一个.def的模块文件。文件内容编写格式如下
LIBRARY "mydll"
EXPORTS
MaxNumber
函数名2
函数名3
……
上面的myll就是你的dll名称,MaxNumber就是我们要导出的函数,函数名2,函数名3也是我们要导出的函数的名称,要导出多个函数,则在下面依次写上要导出的函数名称即可。
假如我们编写的def文件命名为,注意把放在编译的文件夹下。然后我们在工程里打开Properties窗口【选中mydll,然后右键Properties】,然后【Configuration Properties / Linker / Input】在右边的Module
Definition File里填入我们的模块名称,然后点击确定.
4、现在就可以直接点击运行按钮进行dll文件编译了。
需要说明的是,上面编译后的dll文件只能在装了VC2010运行库的操作系统上才能运行。如果要在没有装VC2010运行库的操作系统也能使用那个dll文件,则在执行第4步之前先进行如下操作:在工程里打开Properties窗口【选中mydll,然后右键Properties】,然后【Configuration
Properties / General 】在右边的Use of MFC里选择Use MFC in a Static
Library,然后点击确定。不过这样编译出来的dll文件比原来的dll文件大很
多。
C#生成DLL文件
使用csc命令将.cs文件编译成.dll的过程
很多时候,我们需要将.cs文件单独编译成.dll文件, 操作如下:
打开命令窗口->输入cmd到控制台->cd C:WINDOWSFramework转到安装的该目录下->执行csc命令csc /target:library >在该目录下产生一个对应名字的.dll文件(前提:把.cs文件放到C:WINDOWSFramework目录下)
csc命令的方式很多,请参考以下
译 以产生
csc 编译 以产生
csc /target:library 编译 并创建
csc /out: 通过使用优化和定义 DEBUG 符号,编译当前目录中所有的 C# 文件。输出为
csc /define:DEBUG /optimize /out: *.cs 编译当前目录中所有的 C# 文件,以产生 的调试版本。不显示任何徽标和警告
csc /target:library /out: /warn:0 /nologo /debug *.cs 将当前目录中所有的 C# 文件编译为 (一个 DLL)
csc /target:library /out: *.cs 编译 以产生
csc /target:library 这个就是我们使用最多的一个命令,其实可以简单的写成csc /t:library ,另外的一个写法是 csc /out: /t:library ,这个可以自己指定输出的文件名。
csc /out: /t:library ,这个的作用是把两个cs文件装到一个.dll文件里
csc不是内部或外部命令,也不是可运行的程序解决方法
针对VisualStudio2005
1:右键点击"我的电脑"--"属性"--"高级"--"环境变量"--"系统变量"
将PATH中加上路径:C:WINDOWSFramework
2:直接在dos环境的cs相应文件夹目录执行
Path=C:WINDOWSFramework
3:VisualStudio2005命令提示
开始--》程序---》Microsoft Visual Studio2005---->Visual Studio
Tools--->VisualStudio2005命令提示
把cs文件copy到C:Program FilesMicrosoft Visual Studio 8VC
4:C:
加入:C:WINDOWSFramework
vs2008 下
C:WINDOWSFramework 里的 是版本
编译的.cs文件如果带using ;编译通不过,如果不用LINQ语法删除using ;即可,否则 调用C:WINDOWSFramework里的
同一SLN下 里面 class 直接访问类库。
封装到DLL。 导入DLL 添加using namespace 工有才能访问。
一、 动态链接库
什么是动态链接库?DLL三个字母对于你来说一定很熟悉吧,它是Dynamic Link
Library 的缩写形式,动态链接库 (DLL) 是作为共享函数库的可执行文件。动态链接提供了一种方法,使进程可以调用不属于其可执行代码的函数。函数的可执行代码位于一个 DLL 中,该
DLL 包含一个或多个已被编译、链接并与使用它们的进程分开存储的函数。DLL 还有助于共享数据和资源。多个应用程序可同时访问内存中单个 DLL 副本的内容。
和大多数程序员一样,你一定很使用过DLL吧。也曾感受到它的带给你程序设计和编码上的好错吧今天我想和大家探讨一个主题:如何在C#创建和调用DLL(动态链接库), 其实在很大意义上而讲,DLL让我更灵活的组织编写我们的应用程序,作为软件设计者,可一个根据它来达到很高的代码重用效果。下面我来介绍一下在C#中如何创建和调用DLL。
二、准备工作
我们需要对我们接下来要做的事情做个简单的介绍,在本文我们将利用C#语言创建一个名为 的动态链接库,在这个动态链接库文件中我们将提供两个功能一个是对两个参数交换他们的值,另一个功能是求两个参数的最大公约数。然后创建一个应用程序使用这个DLL。运行并输出结果。
三、创建DLL
让我们创建以下三个C#代码文件:
1、
view plaincopy to clipboardprint?
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;
}
}
}
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、
view plaincopy to clipboardprint?
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;
}
}
}
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 或者其他的文本编辑器,就算是记事本也可以。这两个文件虽然不在同一个文件里面,但是他们是属于同一个namespace(名称空间)这对以后我们使用这两个方法提供了方便。当然他们也可以属于不同的名称空间,这是完全可以的,但只是在我们应用他们的时候就需要引用两个不同的名称空间,所以作者建议还是写在一个名称空间下面比较好。
接下来的任务是把这两个cs文件变成我们需要的DLL文件。方法是这样的:在安装了
Framework的操作系统上,我们可以在Windows所在目录下找到目录。在这个目录下面提供了C#的编译器,运行:csc /target:library /out: ,完成后可在本目录下面找到我们刚才生成的文件/target:library 编译器选项通知编译器输出 DLL 文件而不是 EXE 文件。后跟文件名的 /out 编译器选项用于指定 DLL 文件名。如果/out后面不跟文件名编译器使用第一个文件 作为 DLL 文件名。生成的文件为文件。
OK!我们创建动态链接库文件的任务完成了,现在是我们享受劳动成果的时候了,下面我将介绍如何使用我们所创建的动态链接库文件。 四、使用DLL 我们简单写一个小程序来测试一下我们刚才写的两个方法是否正确,好吧,跟我来:
view plaincopy to clipboardprint?
using System;
using MyMethods; //这里我们引用刚才定义的名称空间,如果刚才的两个文件我们写在两个不同的名称空间
class MyClient
{
public static void Main(string[] args)
{
if != 2)
{
("Usage: MyClient
return;
}
long num1 = (args[0]);
long num2 = (args[1]);
(ref num1,ref num2);
// 请注意,文件开头的 using 指令使您得以在编译时使用未限定的类名来引用 DLL 方法
("The result of swap is num1 = {0} and num2 ={1}",num1, num2);
long maxcd = (num1,num2);
("The MaxCD of {0} and {1} is {2}",num1, num2, maxcd);
}
}
using System;
using MyMethods; //这里我们引用刚才定义的名称空间,如果刚才的两个文件我们写在两个不同的名称空间
class MyClient
{
public static void Main(string[] args)
{
if != 2)
{
("Usage: MyClient
return;
}
long num1 = (args[0]);
long num2 = (args[1]);
(ref num1,ref num2);
// 请注意,文件开头的 using 指令使您得以在编译时使用未限定的类名来引用 DLL 方法
("The result of swap is num1 = {0} and num2 ={1}",num1, num2);
long maxcd = (num1,num2);
("The MaxCD of {0} and {1} is {2}",num1, num2, maxcd);
}
}
若要生成可执行文件 ,请使用以下命令行:
csc /out: /reference:
/out 编译器选项通知编译器输出 EXE 文件并且指定输出文件名 。/reference 编译器选项指定该程序所引用的 DLL 文件。
五、执行
若要运行程序,请输入 EXE 文件的名称,文件名的后面跟两个数字,例如:MyClient 123 456
六、输出
The result of swap is num1 = 456 and num2 = 123
The MaxCD of 456 and 123 is 3
七、小结
动态链接具有下列优点:
1、节省内存和减少交换操作。很多进程可以同时使用一个 DLL,在内存中共享该 DLL 的一个副本。相反,对于每个用静态链接库生成的应用程序,Windows 必须在内存中加载库代码的一个副本。
2、节省磁盘空间。许多应用程序可在磁盘上共享 DLL 的一个副本。相反,每个用静态链接库生成的应用程序均具有作为单独的副本链接到其可执行图像中的库代码。 3、升级到 DLL 更为容易。DLL 中的函数更改时,只要函数的参数和返回值没有更改,就不需重新编译或重新链接使用它们的应用程序。相反,静态链接的对象代码要求在函数更改时重新链接应用程序。
4、提供售后支持。例如,可修改显示器驱动程序 DLL 以支持当初交付应用程序时不可用的显示器。
5、支持多语言程序。只要程序遵循函数的调用约定,用不同编程语言编写的程序就可以调用相同的 DLL 函数。程序与 DLL 函数在下列方面必须是兼容的:函数期望其参数被推送到堆栈上的顺序,是函数还是应用程序负责清理堆栈,以及寄存器中是否传递了任何参数。
6、提供了扩展 MFC 库类的机制。可以从现有 MFC 类派生类,并将它们放到 MFC 扩展 DLL 中供 MFC 应用程序使用。
7、使国际版本的创建轻松完成。通过将资源放到 DLL 中,创建应用程序的国际版本变得容易得多。可将用于应用程序的每个语言版本的字符串放到单独的 DLL 资源文件中,并使不同的语言版本加载合适的资源。
使用 DLL 的一个潜在缺点是应用程序不是独立的;它取决于是否存在单独的 DLL 模块


发布评论