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

A heap has been corrupted: When calling unmanaged function

我正在从一个 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";)之前使用它,但错误仍然存​​在。

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

感谢@PaulMcKnezie 的评论说:

Don't return pointers. The sure way to get this to work is for the caller to provide the buffer, and the function copies the string to the buffer.

所以我使用了与提到的相同方法相同的概念 here 大约

Returning a String With a BSTR * Parameter.

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

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;
            }
        }
    }
}