本文中只讲C++中获取U盘序列号信息的核心代码以及返回值,参数传递的问题,具体封装细节可以查看楼主的一篇其他帖子,里面有具体的封装过程,提供参考(如果使用我这种方法建议一定要看我下面的帖子,因为关于项目属性的问题):
使用C++生成C#调用的DLL
项目结构图和属性图
获取U盘/磁盘序列号相关代码:
C++中获取序列号代码(封装dll的代码)
- U3DTestDLL.cpp
#include"U3DTestDLL.h"
#include <iostream>
#include <windows.h>
#include <winioctl.h>
#include <stdio.h>
#include <initguid.h>
#include <setupapi.h>
#include <string.h>
#include <string>
using namespace std;
int Add(int a, int b) {
return a + b;
}
DWORD getUSBSerial(const char * RootPathName) {
//LPCSTR RootPathName = "G:";
//LPCSTR RootPathName = name.c_str();
char VolumeNameBuffer[MAX_PATH] = { 0 };
DWORD nVolumeNameSize = MAX_PATH;
DWORD VolumeSerialNumber;
DWORD MaximumComponentLength;
DWORD FileSystemFlags;
char FileSystemNameBuffer[MAX_PATH] = { 0 };
DWORD nFileSystemNameSize = MAX_PATH;
BOOL ret = GetVolumeInformationA(
RootPathName,
VolumeNameBuffer,
nVolumeNameSize,
&VolumeSerialNumber,
&MaximumComponentLength,
&FileSystemFlags,
FileSystemNameBuffer,
nFileSystemNameSize
);
if (0 == ret) {
std:cout << "GetVolumeInformationA error !" << std::endl;
}
return VolumeSerialNumber;
}
- U3DTestDLL.h
#if ndef_U3DTestDLL_H_
#define_U3DTestDLL_
#ifdefU3DDLL_EXPORTS
#defineEXPORTS_U3DDLL _declspec(dllexport)
#else
#define EXPORTS_U3DDLL _declspec(dllimport)
extern"C" EXPORTS_U3DDLL int Add(int a, int b);
extern"C" EXPORTS_U3DDLL unsigned long getUSBSerial(const char* rootPathName);
#endif
C#调用代码示例
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Runtime.InteropServices;
/**
* Unity调用C#封装Dll文件
* 2020/10/13 15:55:32
*/
public class TestUSBInfoDLL : MonoBehaviour
{
[DllImport("U3DDLL")]
private static extern int getUSBSerial(string rootPathName);
[DllImport("U3DDLL")]
private static extern int Add(int a, int b);
// Start is called before the first frame update
public void Start()
{
// 测试C++封装代码在Unity中的调用
//Debug.Log("调用方法getUSBSerial");
string a = "I:/ ";
Debug.Log(getUSBSerial(a));
Debug.Log("调用方法Add");
Debug.Log(Add(9,6));
}
// Update is called once per frame
void Update()
{
}
}
生成
代码搞定之后点击 生成 》重新生成解决方案(R) ,就可以在日志中打印生成的dll路径,直接使用即可
问题
1、方法返回值参数对应的问题
-
由于方法是使用C++的并且是需要导出的文件,所以要求源文件和头文件的方法相对应,这样就可以让其他语言调用了,这也是最让人头疼的问题。我的cpp文件中 const char *类型代表字符串
对应关系可参考下面的文章:
返回主页C# java C++ 开源通信 -
小技巧:前面楼主在.cpp文件和.h文件的方法对应上花了很多时间,后来发现一种比较简单的方式:先在 返回主页C# java C++ 开源通信 的帖子中找到C#中想要的返回值类型,然后对应上C++的返回值类型,在.h的头文件中声明你想要的函数(返回值+方法名+参数),如果源文件cpp中没有对应函数时会报错,这时候头文件中声明的方法会报错,只需要点击提示生成对应函数就可以了,然后把生成的函数返回值类型和参数类型复制到我们在源文件中实现的文件中就可以了
2、生成的序列号与实际序列号不符的问题
楼主在网上找了很多篇关于c++获取序列号的代码,我自认为我的是最简单最正确的。通过下载软件aida64或者其他方式可以查看U盘真正的序列号,通过楼主c++代码测试也是基本一样的,只是会省略掉序列号中间的横杠(如果需要可以自己加的),但是当c#中调用dll之后,返回的序列号就不会是这个样子的,会是一个int类型的数字。个人分析认为是不同语言之间的数据类型导致的,楼主返回的是 DWORD的数据类型,他是就是UNSIGN LONG的类型,占用四个字节,所以里面包含数字和中英文(序列号中存在英文),但是在C#中与DWORD类型对应的是int类型,所以转换会有错误。因为楼主获取序列号的原因呢是区别不同U盘,虽然调取dll后并没有成功的获取原来的序列号,但也相当于是唯一标识ID,作用已经可以实现了,故如果大家需要完全获取磁盘序列号的话,需要将C++中的代码修改:修改方法返回值类型为字符串或者char等类型,将DWORD类型转成对应类型后返回,然后C#中声明dll中方法时修改成对应的方法类型即可,至于如何转换楼主也尝试过,但没有成功,里里外外花了一个星期的时间弄这个实在是太累了,如果大家找到了可以在评论中贴出来分享给大家
3、如何提高效率,直接测试需要封装的代码正确性
修改项目的类型即可。选中项目后右键属性修改,如下图
4、由于c#中调用方法时需要传递参数,参数的类型为盘符信息,以下是获取盘符的代码,传入的盘符G:和G:/效果是一样的
DriveInfo[] s = DriveInfo.GetDrives();
foreach (DriveInfo drive in s)
{
if (drive.DriveType == DriveType.Removable)
{
Debug.Log(drive.Name);
Debug.Log(123);
break;
}
Debug.Log(drive.Name);
}
附赠一篇java获取U序列号的代码(开个玩笑,主要是记录一下)
/**
* Description:得到U盘序列号
* @author liuwei DateTime 2013-11-4 下午6:05:56
* @param drive
* @return
*/
public static String getSerialNumber(String drive) {
String result = "";
try {
File file = File.createTempFile("realhowto",".vbs");
file.deleteOnExit();
FileWriter fw = new java.io.FileWriter(file);
String vbs = "Set objFSO = CreateObject(\"Scripting.FileSystemObject\")\n"
+"Set colDrives = objFSO.Drives\n"
+"Set objDrive = colDrives.item(\"" + drive + "\")\n"
+"Wscript.Echo objDrive.SerialNumber"; // see note
fw.write(vbs);
fw.close();
Process p = Runtime.getRuntime().exec("cscript //NoLogo " + file.getPath());
BufferedReader input =
new BufferedReader
(new InputStreamReader(p.getInputStream()));
String line;
while ((line = input.readLine()) != null) {
result += line;
}
input.close();
}
catch(Exception e){
e.printStackTrace();
}
return result.trim();
}
结束语
呕心之作,创作不易,喜欢的加个关注,点个收藏,给个赞~