引用 DLL
开发专题 · 项目引用、浏览托管程序集与非托管调用
本页说明如何在 .NET Framework 4.8 窗体(或控制台)项目中引用 DLL:同一解决方案内的项目引用、磁盘上的托管程序集,以及手写 DllImport / Declare 调用 C++ 非托管导出。操作文案以 LCode 中文界面为准;凡有代码均同时给出 C# 5.0 与 VB.NET。类库的新建与编译见 DLL 动态链接库开发入门。
添加项目引用
同一解决方案内既有「Windows 应用程序」又有「类库」时,优先用项目引用:改完类库再编译解决方案,窗体侧会用到最新输出,不必每次手动挑 bin\Debug 里的文件。
- 在项目浏览器中选中要添加引用的项目(通常是窗体应用),或展开其下的引用节点。
- 右键项目(或「引用」节点)→ 添加引用;也可菜单 项目 → 添加引用。打开标题为「添加引用」的对话框。
- 切换到 项目 页签。列表列标题为项目名称、项目目录。
- 选中目标类库项目,点 选择(E),确认右侧「选择引用」列表中出现该项,再点确定。
- 菜单 编译 → 编译解决方案(F8)。先保证类库无错误,再运行窗体项目。
| 界面文案 | 含义 |
|---|---|
| 添加引用 | 对话框标题;项目/引用节点右键与「项目」菜单中的命令名 |
| 项目 | 页签:列出当前解决方案内可互引的项目 |
| 选择(E) | 把当前页选中项加入下方「选择引用」列表 |
| 引用 | 项目树中的引用文件夹节点名 |
提示:项目引用默认会把被引用程序集本地复制到输出目录(属性面板中文名为「本地复制」,对应 MSBuild 的 Copy Local)。同一解决方案内一般保持为 True。多项目与启动项说明见 解决方案与项目。
浏览引用托管 DLL
类库不在当前解决方案内、或只拿到第三方 .dll 时,用文件浏览添加托管程序集引用(不要用于纯 C++ 非托管 DLL——那一类走下文的 DllImport / Declare)。
- 同样打开「添加引用」对话框。
- 切换到 .NET集合浏览器 页签(文案来自界面资源;作用是浏览磁盘上的程序集文件)。
- 点 浏览(B)...,在打开文件对话框中筛选「程序集文件」(
*.dll;*.exe),选中目标文件后确定。 - 确认下方「选择引用」列表出现该项(类型一般为 Assembly),再点对话框确定。
- 也可在 GAC 页签中从全局程序集缓存按引用名称 / 版本选择;需要精确版本时可「选择特定程序集的版本」。
| 页签 / 控件 | 用途 |
|---|---|
| .NET集合浏览器 | 浏览并添加磁盘上的托管 .dll / .exe |
| 浏览(B)... | 打开文件选择框;支持多选 |
| GAC | 从全局程序集缓存添加(如部分框架程序集) |
| COM | 添加 COM 组件引用(本页不展开) |
| 本地复制 | 选中引用节点后在属性面板中查看/修改;True 时把 DLL 复制到输出目录 |
| 特定版本 | 是否绑定某一精确程序集版本;版本对不上时易导致加载失败 |
建议:浏览添加后,引用会写入相对路径(HintPath)。把 DLL 放在解决方案内固定目录(例如
lib\)再引用,比指向另一台机器的绝对路径更稳妥。若只改了外部 DLL 却未重新复制到输出目录,运行时仍可能用旧文件——检查「本地复制」与输出目录内容。
C# / VB.NET 调用示例
假设已按 DLL 入门 在类库 DemoLib 中实现 Greeter.SayHello,并在窗体项目中完成项目引用(或浏览到对应托管 DLL)。在按钮单击中调用:
C#
using System;
using System.Windows.Forms;
using DemoLib;
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
}
private void btnHello_Click(object sender, EventArgs e)
{
Greeter.SayHello("LCode");
}
}
VB.NET
Imports System
Imports System.Windows.Forms
Imports DemoLib
Public Class MainForm
Inherits Form
Private Sub btnHello_Click(sender As Object, e As EventArgs) Handles btnHello.Click
Greeter.SayHello("LCode")
End Sub
End Class
命名空间以类库中实际声明为准。若编译提示找不到类型或命名空间:确认引用节点下已有 DemoLib(或程序集名),目标框架均为 v4.8,且类库已成功编译。
调用 C++ 非托管 DLL
纯本机(C/C++)DLL 没有 .NET 元数据,不能靠「添加引用」当托管程序集使用。应在代码中用平台调用声明导出函数:C# 用 [DllImport],VB.NET 用 Declare(或同样的 DllImport)。
下面以系统 user32.dll 的 MessageBeep 为例(无需自备 C++ 工程即可验证声明写法):
C#
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
public partial class MainForm : Form
{
[DllImport("user32.dll")]
private static extern bool MessageBeep(uint uType);
private void btnBeep_Click(object sender, EventArgs e)
{
// 0x00000040 = MB_ICONINFORMATION
MessageBeep(0x00000040);
}
}
VB.NET
Imports System
Imports System.Runtime.InteropServices
Imports System.Windows.Forms
Public Class MainForm
Inherits Form
<DllImport("user32.dll")>
Private Shared Function MessageBeep(uType As UInteger) As Boolean
End Function
' 等价写法:Declare Function MessageBeep Lib "user32.dll" (ByVal uType As UInteger) As Boolean
Private Sub btnBeep_Click(sender As Object, e As EventArgs) Handles btnBeep.Click
' &H40 = MB_ICONINFORMATION
MessageBeep(&H40UI)
End Sub
End Class
| 注意点 | 说明 |
|---|---|
| 平台位数 | 进程与本机 DLL 须同为 x86 或同为 x64。AnyCPU 在 64 位系统上常以 64 位运行,无法加载纯 32 位 DLL。请在项目选项中对齐平台目标,并把 DLL 放到可被加载的路径(输出目录或系统搜索路径)。 |
| 调用约定 / 字符集 | 按导出方约定设置 CallingConvention、CharSet、EntryPoint;名称或约定错误会在运行时抛出 EntryPointNotFoundException / DllNotFoundException。 |
| LCode 辅助 | 主产品界面暂不支持,待更新完善可视化「声明非托管导出」向导;请按文档手写 DllImport / Declare。仓库中的 PInvoke 示例插件不在默认交付路径,本手册不以之为前提。 |
常见错误
| 现象 | 常见原因 | 处理方向 |
|---|---|---|
| 找不到类型 / 命名空间 | 未添加引用,或引用的程序集未编译成功 | 打开「添加引用」确认项目或浏览项存在;先编译类库再编译窗体 |
| 找不到程序集(运行时) | 输出目录缺少 DLL;「本地复制」为 False;HintPath 失效 | 检查引用属性「本地复制」;确认 DLL 与 EXE 同目录或路径有效 |
| 版本 / 强名称冲突 | 「特定版本」过严,或绑定重定向与实际文件不一致 | 核对引用版本;浏览引用时优先使用与编译时一致的文件 |
| BadImageFormatException | 位数不匹配(32/64),或把非托管 DLL 当托管引用添加 | 对齐平台目标;非托管改用 DllImport / Declare |
| Copy Local / 本地复制未生效 | 属性被关掉,或手动删了输出目录中的依赖 | 选中引用 → 属性 →「本地复制」= True,重新编译 |
相关阅读
- DLL 动态链接库开发入门 — 新建类库、实现 API、编译并找到
.dll - 解决方案与项目 — 多项目、启动项与编译范围
- 运行与编译 — 配置、输出目录与目标框架
- C# / VB.NET 窗体应用入门 — 可引用 DLL 的窗体侧入门