堆已损坏:调用非托管函数时

时间:2019-05-21 15:50:52

标签: c# c++ unmanaged cdecl

我正在从C#受管函数调用一个非托管且非常简单的C ++函数(位于JNIDiskInfoDll.dll中),如下所示:

C ++:

#include "stdafx.h"
#include "AtaSmart.h"

#include <iostream>
#include <string.h>

extern "C" __declspec(dllexport) char* __cdecl getSerial(LPTSTR inCStrIn)
{
    return "abcdefg";
}

C#:

using System;
using System.Runtime.InteropServices;

namespace HardInfoRetriever
{
    class DiskInfoRetreiver
    {

        [DllImport("C:\\Users\\User1\\Documents\\Visual Studio 2017\\Projects\\HardInfoRetriever\\Debug\\JNIDiskInfoDll.dll",
            EntryPoint = "getSerial", CallingConvention = CallingConvention.Cdecl,
            BestFitMapping = false, ThrowOnUnmappableChar = true, CharSet = CharSet.Ansi)]

        public static extern String getSerial([MarshalAs(UnmanagedType.LPTStr)]String _driveletter_);
        public static String getSerialNumber(String driveletter)
        {
            try
            {
                return getSerial(driveletter);
            }
            catch (Exception e)
            {
                throw e;
            }
        }
    }
}

我的问题是,运行应用程序后,我得到两个连续的错误,分别为projectName.exe has triggered a breakpointUnhandled exception at 0x77110E23 (ntdll.dll) in projectName.exe: 0xC0000374: A heap has been corrupted (parameters: 0x7712E930).。知道尽管我遇到了这些错误,但该函数仍在返回所需的输出。

请注意,getSerial C函数具有LPTSTR inCStrIn参数,因为我在删除仍然存在错误的整个代码(仅保留return "abcdefg";)之前就已经使用了它。

我不知道这里可能是什么问题。我试图将Charset中的DllImport更改为Unidcode,但是仍然遇到相同的错误。有什么帮助吗?

1 个答案:

答案 0 :(得分:0)

感谢@PaulMcKnezie的评论:

  

不返回指针。确保此功能正常运行的肯定方法是   调用方提供缓冲区,该函数将字符串复制到   缓冲区。

因此,我使用了与提到的here相同的方法相同的概念

  

使用BSTR *参数返回字符串。

最后,下面是我的代码的最终工作版本:

C ++:

extern "C" __declspec(dllexport) HRESULT __cdecl getSerial(LPTSTR inCStrIn, BSTR* inCStrOut)
{
    *inCStrOut= SysAllocString(L"abcdefg"); 
    return S_OK;
}

C#:

using System;
using System.Runtime.InteropServices;

namespace HardInfoRetriever
{
    class DiskInfoRetreiver
    {

        [DllImport("C:\\Users\\User1\\Documents\\Visual Studio 2017\\Projects\\HardInfoRetriever\\Debug\\JNIDiskInfoDll.dll",
            EntryPoint = "getSerial", CallingConvention = CallingConvention.Cdecl,
            BestFitMapping = false, ThrowOnUnmappableChar = true, CharSet = CharSet.Ansi)]
        //[return: MarshalAs(UnmanagedType.LPTStr)]
        public static extern int getSerial([MarshalAs(UnmanagedType.LPTStr)] string _driveletter_, [MarshalAs(UnmanagedType.BStr)] out string serial);
        public static String getSerialNumber(string letter)
        {
            try
            {
                string serial;
                int result =  getSerial(letter, out serial);
                if (result == 0)
                {
                    return serial;
                }
                return null;
            }
            catch (Exception e)
            {
                throw e;
            }
        }
    }
}