A heap has been corrupted: When calling unmanaged function

0

I am calling an un-managed and very simple C++ function (located in JNIDiskInfoDll.dll) from a C# managed one as follows:

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

My problem is that after running the application I get two successive errors saying projectName.exe has triggered a breakpoint and Unhandled exception at 0x77110E23 (ntdll.dll) in projectName.exe: 0xC0000374: A heap has been corrupted (parameters: 0x7712E930).. Knowing that although I'm getting these errors, the function is still returning the desired output.

Please note that the getSerial C function has the LPTSTR inCStrIn parameter since I was using it before I did remove the whole code (keeping only return "abcdefg";) where the error persists.

I don't know what could be the problem here. I tried to change the Charset in the DllImport into Unidcode, but still getting same errors. Any help please?

c#
c++
unmanaged
cdecl
asked on Stack Overflow May 21, 2019 by peter bence • edited May 21, 2019 by 1201ProgramAlarm

1 Answer

0

Thanks to the comment of @PaulMcKnezie saying:

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.

So I used the same concept as the same method mentioned here that is about

Returning a String With a BSTR * Parameter.

Finally, below is the final working version of my code:

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;
            }
        }
    }
}
answered on Stack Overflow May 22, 2019 by peter bence

User contributions licensed under CC BY-SA 3.0