我正在使用http://www.soft.tahionic.com/download-hdd_id/index.html中的硬件ID提取程序库(用Delphi编写),目的是生成唯一的系统指纹。
图书馆非常好,不像我在市场上看到的任何其他东西,但它的主要问题是它在运行.NET应用程序时不稳定,这意味着它有时可以工作,有时它可以工作对于一些函数调用,然后主应用程序崩溃,或者大多数时候应用程序在调用dll函数时立即崩溃。
正如图书馆的开发人员指出的那样(在我收到的最后一封支持电子邮件中),错误是ntdll.dll,正如我自己看到的那样:
以下是我为了测试dll函数而创建的演示项目的链接(为了确保没有其他任何干扰,演示应用程序执行此操作,并且只调用dll函数)。 http://www.mediafire.com/download/1jws7zh9218v88a/HardwareIdExtractDllTest.zip 该存档包含带有源代码的Visual Studio 2013项目和一个编译的演示应用程序,如下所示:
dll包含的函数列表可以在这里找到: http://www.soft.tahionic.com/download-hdd_id/hardware%20id%20programming%20source%20code/exported%20functions%20for%20non-Delphi.html
如果有人知道并且愿意测试演示项目/应用程序以针对该问题进行测试或个人意见,然后与我分享可能的解决方案,我将不胜感激。
如果您认为可以采取任何措施,请告诉我是否可以采取任何措施来进一步协助解决此问题。
编辑:这就是我宣布dll功能的方式
[DllImport("HardwareIDExtractorC.dll")]
private static extern bool EnterKey(int key);
[DllImport("HardwareIDExtractorC.dll")]
private static extern bool IsCPUIDAvailable();
[DllImport("HardwareIDExtractorC.dll")]
private static extern int GetCPUCount();
[DllImport("HardwareIDExtractorC.dll")]
private static extern byte CoreNumber2CoreMask(byte cpuCore);
[DllImport("HardwareIDExtractorC.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi, EntryPoint = "GetCPUID")]
[return: MarshalAs(UnmanagedType.LPStr)]
private static extern string GetCPUID(byte cpuCore);
[DllImport("HardwareIDExtractorC.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi, EntryPoint = "GetCpuIdNow")]
[return: MarshalAs(UnmanagedType.LPStr)]
private static extern string GetCpuIdNow();
[DllImport("HardwareIDExtractorC.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi, EntryPoint = "GetIDESerialNumber")]
[return: MarshalAs(UnmanagedType.LPStr)]
private static extern string GetIDESerialNumber(byte driveNumber);
答案 0 :(得分:3)
失败的函数是返回string
的函数。这样的p / invoke将返回值编组为指向空终止字符数组的指针,然后对非托管代码返回的原始指针调用CoTaskMemFree
。
如果概率接近1,那么在COM堆上没有分配字符串,因此错误可能出现在C#p / invoke声明中。那么在ntdll中出现访问冲突是非常合理的。
因此,要取得进展,您需要修复p / invoke调用。我无法告诉你如何这样做,因为你没有显示非托管函数声明。或者,更重要的是,如何分配内存。
procedure ReleaseMemory (P: PAnsiChar); stdcall;
我认为这告诉我们DLL必须通过调用此函数来释放DLL返回的字符串。大概是因为它们是由DLL的堆分配器分配的。
因此,使用IntPtr
作为返回文本的函数的返回类型。调用Marshal.PtrToStringAnsi
转换为C#字符串。然后将指针传递给ReleaseMemory
。
例如:
[DllImport(DllPath, CallingConvention = CallingConvention.StdCall)]
private static extern IntPtr GetCPUID(ushort CoreMask);
[DllImport(DllPath, CallingConvention = CallingConvention.StdCall)]
private static extern void ReleaseMemory(IntPtr P);
....
IntPtr ptr = GetCPUID(CoreMask);
string cpuid = Marshal.PtrToStringAnsi(ptr);
ReleaseMemory(ptr);