Повреждена куча: при вызове неуправляемой функции - PullRequest
0 голосов
/ 21 мая 2019

Я вызываю неуправляемую и очень простую функцию C ++ (расположенную в JNIDiskInfoDll.dll) из управляемой C # следующим образом:

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 breakpoint и Unhandled 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 голосов
/ 22 мая 2019

Благодаря комментарию @PaulMcKnezie, сказавшему:

Не возвращайте указатели.Надежный способ заставить это работать - предоставить вызывающей стороне буфер, а функция копирует строку в буфер.

Так что я использовал ту же концепцию, что и тот же метод, упомянутый здесь , что составляет около

Возвращение строки с параметром 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;
            }
        }
    }
}
...