惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Recent Announcements
Recent Announcements
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Last Week in AI
Last Week in AI
Scott Helme
Scott Helme
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
L
LINUX DO - 最新话题
S
Security @ Cisco Blogs
Webroot Blog
Webroot Blog
S
Security Affairs
H
Hacker News: Front Page
TaoSecurity Blog
TaoSecurity Blog
W
WeLiveSecurity
G
GRAHAM CLULEY
T
Tenable Blog
Schneier on Security
Schneier on Security
S
Securelist
Cyberwarzone
Cyberwarzone
P
Privacy International News Feed
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
S
Schneier on Security
Hacker News - Newest:
Hacker News - Newest: "LLM"
Recent Commits to openclaw:main
Recent Commits to openclaw:main
O
OpenAI News
N
News and Events Feed by Topic
AWS News Blog
AWS News Blog
C
Cisco Blogs
T
Threat Research - Cisco Blogs
S
Secure Thoughts
大猫的无限游戏
大猫的无限游戏
C
Check Point Blog
The GitHub Blog
The GitHub Blog
G
Google Developers Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
美团技术团队
Martin Fowler
Martin Fowler
Microsoft Security Blog
Microsoft Security Blog
L
LangChain Blog
Apple Machine Learning Research
Apple Machine Learning Research
爱范儿
爱范儿
D
DataBreaches.Net
博客园_首页
MyScale Blog
MyScale Blog
博客园 - 叶小钗
博客园 - 三生石上(FineUI控件)
P
Proofpoint News Feed
J
Java Code Geeks
SecWiki News
SecWiki News
P
Palo Alto Networks Blog
Know Your Adversary
Know Your Adversary
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org

博客园 - zhaotianff

解决IIS服务器typecho上传附件后无法访问的问题 Jenkins快速入门教程 .NET是什么?为什么要选择.NET? 如何在WPF中实现类似DevOps的自动化流程 一文带你搞懂医疗器械设计开发全生命周期 Windows如何清除本机记录的git用户名和密码 HL7协议详解 医疗行业 GDT 数据格式详解 一文带你搞懂C# 异步编程(async/await)底层原理 如何在C#中使用Chromium headless(无头模式)浏览器 不同.NET版本中的WPF新增功能 如何在WPF中使用 Fluent 主题 Windows平台下的各种原生UI框架介绍 C#如何Hook托管函数 WinDbg 用户层调试进阶教程 Windows编程的一些基础理论 推荐一款优秀的Windows经典文件管理器项目-WinFile Windows如何阻止应用程序联网 如何在WPF中捕获窗口外的事件 如何查看Windows进程的启动来源 Visual Studio 2026新解决方案格式slnx详解 我的微软MVP申请通过了 WPF MVVM实战系列教程(八、Prism DialogService, 对话框服务) WPF MVVM实战系列教程(七、Prism模块化) WPF 性能优化实战指南 WPF MVVM实战系列教程(六、Prism区域导航) WPF MVVM实战系列教程(五、Prism中的MVVM) WPF MVVM实战系列教程(四、Prism中的依赖注入) 微软 IDE 新纪元:Visual Studio 2026 初体验 Windows 7无法安装VMWare Tools的解决办法 WPF MVVM实战系列教程(三、创建Bootstrapper/启动器) WPF MVVM实战系列教程(二、使用Visual Studio 创建Prism项目) WPF MVVM实战系列教程(一、Prism框架介绍)
Visual Studio编译过程中拷贝文件的一些实用小技巧
zhaotianff · 2026-07-03 · via 博客园 - zhaotianff

有时候我们在编译项目前可能会需要拷贝一些文件,或者在编译完成后,将生成的文件拷贝到固定的位置。

场景1

我有一个三方的sdk,这个sdk已经放在项目里了。

有时候我们需要集成一个C++的动态链接库,它内部是动态调用的(通过LoadLibrary)。

在C#层是通过P/Invoke进行调用,一般会提供一个接口层,运行时,还需要另外一个dll.

如果我们每次把文件都手动复制到输出目录,就略显麻烦。特别是换了电脑,换了输出路径的情况下。

这种场景实现比较简单,只要设置一下属性,将文件始终复制到输出目录即可。

image

image

这样我们编译后,就可以看到文件已经自动复制到输出路径了。

image

场景2

我需要将生成的文件拷贝到其它路径。

这种比较常见的就是使用了Prism,将模块进行了统一管理,并通过目录加载的形式进行加载。

例如这里我配置了通过Device目录加载模块

1 protected override IModuleCatalog CreateModuleCatalog()
2 {
3     return new DirectoryModuleCatalog() { ModulePath = @".\Device" };
4 }

我们现在有一个Device.Keyboard工程,需要在编译完成后,把这个dll复制到项目输出路径下的Device目录下。

这个时候我们可以编辑生成后事件,使用xcopy命令来进行拷贝(关于xcopy命令的详细使用参考:https://learn.microsoft.com/zh-cn/windows-server/administration/windows-commands/xcopy

image

Visual Studio中.NET Core/.NET工程的配置界面

image

 Visual Studio 中.NET Framework工程的配置界面

输入以下指令

1 xcopy /Y /R "$(TargetPath)" "$(OutDir)Device\"

就可以在编译成功时自动将当前的项目的输出文件拷贝到输出路径下的Device文件夹

image

 这里我们使用了一些预生成宏,常见的宏定义如下:

说明
$(Configuration) 当前项目配置的名称,例如,“调试”。
$(DevEnvDir) Visual Studio 的安装目录(定义为驱动器 + 路径);包括尾随反斜杠 (\)。
$(FrameworkDir) 在其中安装了 .NET Framework 的目录。
$(FrameworkSDKDir) 在其中安装了 .NET Framework 的目录。 .NET Framework 可能已作为 Visual Studio 的一部分安装或已单独安装。
$(FrameworkVersion) Visual Studio 使用的.NET framework 版本。 结合 $(FrameworkDir),就是 Visual Studio 使用的 .NET Framework 版本的完整路径。
$(FxCopDir) fxcop.cmd 文件的路径。 fxcop.cmd 文件并未在所有 Visual Studio 版本中安装。
$(IntDir) 为中间文件指定的目录路径。 如果这是一个相对路径,中间文件将转到已追加到项目目录的这一路径。 此路径应包含尾随斜杠 (\)。 它解析为“中间目录”属性的值。 请勿使用 $(OutDir) 来定义此属性。
$(OutDir) 输出文件目录的路径。 如果这是一个相对路径,输出文件将转到已追加到项目目录中的这一路径。 此路径应包含尾随斜杠 (\)。 它解析为“输出目录”属性的值。 请勿使用 $(IntDir) 来定义此属性。
$(Platform) 当前项目平台的名称(例如“Win32”)。
$(PlatformShortName) 当前体系结构的短名称,例如“x86”或“x64”。
$(ProjectDir) 项目的目录(定义为驱动器 + 路径);包括尾随反斜杠 (\)。
$(ProjectExt) 项目的文件扩展名。 文件扩展名之前包括“.”。
$(ProjectFileName) 项目的文件名称(定义为基名称 + 文件扩展名)。
$(ProjectName) 项目的基名称。
$(ProjectPath) 项目的绝对路径名称(定义为驱动器 + 路径 + 基名称 + 文件扩展名)。
$(PublishDir) 发布目标的输出位置;包括尾随反斜杠 (\)。 默认为 $(OutDir)app.publish\ 文件夹。
$(RemoteMachine) 设置为“调试”属性页上 Remote Machine 属性的值。 有关详细信息,请参阅更改 C/C++ 调试配置的项目设置
$(RootNameSpace) 包含应用程序的命名空间(如果存在)。
$(SolutionDir) 解决方案的目录(定义为驱动器 + 路径);包括尾随反斜杠 (\)。 仅当在 IDE 中生成解决方案时定义。
$(SolutionExt) 解决方案的文件扩展名。 文件扩展名之前包括“.”。 仅当在 IDE 中生成解决方案时定义。
$(SolutionFileName) 解决方案的文件名称(定义为基名称 + 文件扩展名)。 仅当在 IDE 中生成解决方案时定义。
$(SolutionName) 解决方案的基名称。 仅当在 IDE 中生成解决方案时定义。
$(SolutionPath) 解决方案的绝对路径名称(定义为驱动器 + 路径 + 基名称 + 文件扩展名)。 仅当在 IDE 中生成解决方案时定义。
$(TargetDir) 生成的主输出文件的目录(定义为驱动器 + 路径);包括尾随反斜杠 (\)。
$(TargetExt) 生成的主输出文件的文件扩展名。 文件扩展名之前包括“.”。
$(TargetFileName) 生成的主输出文件的文件名称(定义为基名称 + 文件扩展名)。
$(TargetName) 生成的主输出文件的基名称。
$(TargetPath) 生成的主输出文件的绝对路径名称(定义为驱动器 + 路径 + 基名称 + 文件扩展名)。
$(VCInstallDir) 包含 Visual Studio 安装的 C++ 内容的目录。 此属性包含目标 Microsoft C++ (MSVC) 工具集的版本,它可能与主机 Visual Studio 不同。 例如,当使用 $(PlatformToolset) = v140 进行生成时,$(VCInstallDir) 包含 Visual Studio 2015 安装路径。
$(VSInstallDir) 在其中安装了 Visual Studio 的目录。 此属性包含目标 Visual Studio 工具集的版本,它可能与主机 Visual Studio 不同。 例如,当使用 $(PlatformToolset) = v110 进行生成时,$(VSInstallDir) 包含 Visual Studio 2012 安装路径。
$(WebDeployPath) 从 Web 部署根到项目输出位置的相对路径。
$(WebDeployRoot) <localhost> 位置的绝对路径。 例如 c:\inetpub\wwwroot

 详见:https://www.cnblogs.com/zhaotianff/p/19117283

场景3

我需要将生成的文件压缩 

这里我们还是使用生成后事件,并使用tar命令进行压缩 

以下指令的功能是将输出目录下的全部文件压缩到D:\Compressed.zip文件

1 tar -caf D:\Compressed.zip -C $(OutDir) *

场景4

我需要在生成完成后生成安装包

这里我们可以借助Inno Setup或NSIS等支持命令行 / 脚本批量打包的安装包制作工具。

在生成后事件里,使用对应的命令执行打包,例如

2 ISCC /d"Version=1.1.0" build_script.iss

关于Inno SetupNSIS等工具的使用可以参考以下文档,这里不做详细介绍。

Inno Setup

https://jrsoftware.org/ishelp/

NSIS

https://nsis.sourceforge.io/Docs/