VS 多工程之间管理与调用(超详细)

本文详细介绍如何在Visual Studio中配置一个多项目的解决方案,涵盖动态链接库、静态库及可执行文件的生成与调用。通过具体步骤指导读者实现清晰的工作目录结构。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

说明


本文是在前任的基础上总结完善而成的,中间走了不少弯路,希望后来人能够大树乘凉~~~

特别感谢以下两篇博文:

平台:Visual Studio 2013 , Windows 10 OS

功能:本文实现了 VS 在同一解决方案下动态库,静态库,可执行文件的生成与调用

项目下载:MultiProj项目

配置过程描述


我们最终希望的多工程目录是这样的:

这里写图片描述

用思维导图表示是这样的:

链接:MultiProj 思维导图

这里写图片描述

VS工程下是这样的

这里写图片描述

这样做的好处是:

  • 工作目录结构清晰
  • 制作安装包时我们只需将 MultiProj/Bin/Release/ 目录下的所有文件打包即可
  • 发布和转移源码的时候我们可以打包除 Temp 目录以外 MultiProj 下面的所有文件和目录(如果不需要执行档,也可不包括Bin)

详细步骤


1、打开 VS

这里写图片描述

2、新建一个空的解决方案

这里写图片描述

3、新建 4 个文件夹

这样做的好处是易于管理项目~~

这里写图片描述

4、分别建立各自文件架下的工程

这里写图片描述

5、书写源代码

MathFuncsDll 工程代码

stdafx.h (下文不再写此部分)

// stdafx.h : 标准系统包含文件的包含文件,
#pragma once
#include "targetver.h"

#define WIN32_LEAN_AND_MEAN   //  从 Windows 头文件中排除极少使用的信息
// Windows 头文件: 
#include <windows.h>

// TODO:  在此处引用程序需要的其他头文件

stdafx.cpp

// stdafx.cpp : 只包括标准包含文件的源文件
#include "stdafx.h"
// TODO:  在 STDAFX.H 中
// 引用任何所需的附加头文件,而不是在此文件中引用

targetver.h (下文不再写此部分)

#pragma once

// 包括 SDKDDKVer.h 将定义可用的最高版本的 Windows 平台。

// 如果要为以前的 Windows 平台生成应用程序,请包括 WinSDKVer.h,并将
// WIN32_WINNT 宏设置为要支持的平台,然后再包括 SDKDDKVer.h。

#include <SDKDDKVer.h>

dllmain.cpp (下文不再写此部分)

// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "stdafx.h"

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
					 )
{
	switch (ul_reason_for_call)
	{
	case DLL_PROCESS_ATTACH:
	case DLL_THREAD_ATTACH:
	case DLL_THREAD_DETACH:
	case DLL_PROCESS_DETACH:
		break;
	}
	return TRUE;
}

MathFuncsDll.h

// MathFuncsDll.h

#ifdef MATHFUNCSDLL_EXPORTS
#define MATHFUNCSDLL_API __declspec(dllexport) 
#else
#define MATHFUNCSDLL_API __declspec(dllimport) 
#endif

namespace MathFuncs
{
	// This class is exported from the MathFuncsDll.dll
	class MyMathFuncs
	{
	public:
		// Returns a + b
		static MATHFUNCSDLL_API double Add(double a, double b);

		// Returns a - b
		static MATHFUNCSDLL_API double Subtract(double a, double b);

		// Returns a * b
		static MATHFUNCSDLL_API double Multiply(double a, double b);

		// Returns a / b
		// Throws const std::invalid_argument& if b is 0
		static MATHFUNCSDLL_API double Divide(double a, double b);
	};
}

MathFuncsDll.cpp

// MathFuncsDll.cpp : Defines the exported functions for the DLL application.
//

#include "stdafx.h"
#include "MathFuncsDll.h"
#include <stdexcept>

using namespace std;

namespace MathFuncs
{
	double MyMathFuncs::Add(double a, double b)
	{
		return a + b;
	}

	double MyMathFuncs::Subtract(double a, double b)
	{
		return a - b;
	}

	double MyMathFuncs::Multiply(double a, double b)
	{
		return a * b;
	}

	double MyMathFuncs::Divide(double a, double b)
	{
		if (b == 0)
		{
			throw invalid_argument("b cannot be zero!");
		}

		return a / b;
	}
}
MathSquare 工程代码

square.cpp

#include <iostream>
using namespace std;

int main(){
	cout << "Pls enter two number : \n";
	int a, b;
	cin >> a >> b;
	cout << a + b << endl;
	return 0;
}
MathAverageLib 工程代码

MathOperator.h

#pragma once
class MathOperator
{
public:
	MathOperator();
	~MathOperator();

	int getAverage(int a, int b, int c);
};

MathOperator.cpp

#include "stdafx.h"
#include "MathOperator.h"


MathOperator::MathOperator()
{
}


MathOperator::~MathOperator()
{
}


int MathOperator::getAverage(int a, int b, int c){
	return ( a + b + c) / 3;
}

Main工程代码

main.cpp

#include <iostream>
#include <windows.h>

#include "MathOperator.h"
#include "MathFuncsDll.h"

using namespace std;

int main()
{
	///test dll
	double a = 7.4;
	int b = 99;

	cout << "a + b = " <<
		MathFuncs::MyMathFuncs::Add(a, b) << endl;
	cout << "a - b = " <<
		MathFuncs::MyMathFuncs::Subtract(a, b) << endl;
	cout << "a * b = " <<
		MathFuncs::MyMathFuncs::Multiply(a, b) << endl;
	cout << "a / b = " <<
		MathFuncs::MyMathFuncs::Divide(a, b) << endl;

	try
	{
		cout << "a / 0 = " <<
			MathFuncs::MyMathFuncs::Divide(a, 0) << endl;
	}
	catch (const invalid_argument &e)
	{
		cout << "Caught exception: " << e.what() << endl;
	}

	/// test lib 
	MathOperator mo;
	std::cout << "The average of 2, 4, 6 is: " << mo.getAverage(2, 4, 6) << std::endl;

	///test exe
	WinExec("\"MathSquare.exe\"", 1);

	system("pause");
	return 0;
}

部分代码讲解

这里写图片描述
这里写图片描述
这里写图片描述

6、更改各种文件的生成路径

首先看一下项目设置中可以使用的宏,常用的有:

宏名称含义
$(ConfigurationName)Debug或者Release
$(IntDir)编译器使用的中间目录,产出obj二进制文件
$(OutDir)链接器使用的输出目录
$(ProjectDir)项目目录
$(ProjectName)项目名字
$(SolutionDir)解决方案目录
$(TargetDir)目标输出文件所在的目录
$(TargetExt)目标输出的扩展名
$(TargetFileName)目标输出文件名,包括扩展名
$(TargetName)目标输出名,不包括扩展名
$(TargetPath)目标输出文件的全路径名

上面建立的 4 个工程要分别单独设置,每个工程又要分 Debug 和 Release 两种情况,所以要注意!!!

MathFuncsDll 属性设置

这里写图片描述

全局配置

  • 配置属性 - 常规 - 输出目录:
$(SolutionDir)\Temp\Link\$(ProjectName)\$(ConfigurationName)
  • 配置属性 - 常规 - 中间目录:
$(SolutionDir)\Temp\Compile\$(ProjectName)\$(ConfigurationName)

Release 模式

  • 配置属性 - 生成事件 - 后期生成事件 - 命令行:
copy $(TargetPath)    $(SolutionDir)\Bin\$(ConfigurationName)\;
copy $(TargetDir)$(TargetName).lib    $(SolutionDir)\Lib\;

Debug 模式

  • 配置属性 - 链接器 - 高级 - 导入库:
$(TargetDir)$(TargetName)_d.lib
  • 配置属性 - 生成事件 - 后期生成事件 - 命令行:
copy $(TargetPath)    $(SolutionDir)\Bin\$(ConfigurationName)\;
copy $(TargetDir)$(TargetName)_d.lib    $(SolutionDir)\Lib\;

看不清楚的话看这里:
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

MathSquare 属性设置

这里写图片描述

全局配置

  • 配置属性 - 常规 - 输出目录(同上)
  • 配置属性 - 常规 - 中间目录(同上)
  • 配置属性 - 生成事件 - 后期生成事件 - 命令行:
copy  $(TargetDir)$(TargetName).exe    $(SolutionDir)\Bin\$(ConfigurationName);
MathAverageLib 属性设置

这里写图片描述

全局配置

  • 配置属性 - 常规 - 输出目录(同上)
  • 配置属性 - 常规 - 中间目录(同上)
  • 配置属性 - 生成事件 - 后期生成事件 - 命令行:
copy $(TargetDir)$(TargetName).lib $(SolutionDir)\Lib\;
Main 属性设置

全局配置

  • 配置属性 - 常规 - 输出目录(同上)
  • 配置属性 - 常规 - 中间目录(同上)
  • 配置属性 - 生成事件 - 后期生成事件 - 命令行:
copy $(TargetPath)    $(SolutionDir)\Bin\$(ConfigurationName);

7、添加引用

这里写图片描述

大功告成!!! Ctrl + F5 运行即可~~

失败总结


  • 是否正确建立工程
  • 时否正确配置相关属性
  • 是否模糊了 release 和 debug 下的配置
  • 是否写正确后处理事件
  • 源代码是都书写正确

快速复制

// 输出目录
$(SolutionDir)\Temp\Link\$(ProjectName)\$(ConfigurationName)
// 中间目录
$(SolutionDir)\Temp\Compile\$(ProjectName)\$(ConfigurationName)

// DLL Release 命令
copy $(TargetPath)    $(SolutionDir)\Bin\$(ConfigurationName)\;
copy $(TargetDir)$(TargetName).lib    $(SolutionDir)\Lib\;

// DLL Debug 命令
copy $(TargetPath)    $(SolutionDir)\Bin\$(ConfigurationName)\;
copy $(TargetDir)$(TargetName)_d.lib    $(SolutionDir)\Lib\;

$(TargetDir)$(TargetName)_d.lib

// EXE 命令
copy  $(TargetDir)$(TargetName).exe    $(SolutionDir)\Bin\$(ConfigurationName);

// LIB 命令
copy $(TargetDir)$(TargetName).lib $(SolutionDir)\Lib\;

// MAIN 命令
copy $(TargetPath)    $(SolutionDir)\Bin\$(ConfigurationName);
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值