C++ Struct to C# - Access Denied by setting property

-1

So, It's been two days since I am stuck with this function in the code of a project I was just assigned to. Basically, It's sending a Struct from Visual C++ to C#. But, it isn't as easy as it sounds (or at least it hasn't been easy for me :P)

C# Side:

using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace TCLDemoRunner
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Beginning Test");
            var test = new InfoCheck();
            test.Test();
            Console.WriteLine("Finished Running.");
        }
    }

    //Test Runner
    class InfoCheck
    {
        [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
        public delegate int PassCallback(InfoNative info);
        [DllImport("CPPCode", CallingConvention = CallingConvention.Cdecl)]
        internal static extern int GetResponse(IntPtr handle, PassCallback cb);
        private readonly PassCallback _callback;
        public InfoCheck()
        {
            _callback = new InfoCheck.PassCallback(PassCB);
        }
        static private int PassCB(InfoNative info)
        {
            Console.WriteLine(info);
            return 1;
        }

        public void Test()
        {
            var ret = GetResponse((IntPtr)3151228115280 /*A basically random number used for testing*/, _callback);
            Console.WriteLine(ret);
        }
    }

    //The C# Version of the Struct

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    public class InfoNative
    {

        public InfoNative()
        {
        }


        [MarshalAs(UnmanagedType.LPStr)]
        public string usercode;


        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4, ArraySubType = UnmanagedType.U4)]
        public uint[] version;

        [MarshalAs(UnmanagedType.U8)]
        public long loading_timestamp;

        // Token: 0x040000AD RID: 173
        [MarshalAs(UnmanagedType.U1)]
        public byte already_activated;

        // Token: 0x040000AE RID: 174
        [MarshalAs(UnmanagedType.U1)]
        public byte auto_renew;

        // Token: 0x040000AF RID: 175
        [MarshalAs(UnmanagedType.U2)]
        public ushort review_status;

        // Token: 0x040000B0 RID: 176
        [MarshalAs(UnmanagedType.LPWStr)]
        public string company_name;

        // Token: 0x040000B1 RID: 177
        [MarshalAs(UnmanagedType.LPWStr)]
        public string contact_name;

        // Token: 0x040000B2 RID: 178
        [MarshalAs(UnmanagedType.LPStr)]
        public string email;

        // Token: 0x040000B3 RID: 179
        [MarshalAs(UnmanagedType.LPStr)]
        public string telephone;

        // Token: 0x040000B4 RID: 180
        [MarshalAs(UnmanagedType.LPStr)]
        public string country_id;

        // Token: 0x040000B5 RID: 181
        [MarshalAs(UnmanagedType.LPStr)]
        public string country_name;

        // Token: 0x040000B6 RID: 182
        [MarshalAs(UnmanagedType.LPStr)]
        public string admin_email;

        // Token: 0x040000B7 RID: 183
        [MarshalAs(UnmanagedType.LPWStr)]
        public string reseller_name;

        // Token: 0x040000B8 RID: 184
        [MarshalAs(UnmanagedType.U8)]
        public long expiration_time;

        // Token: 0x040000B9 RID: 185
        [MarshalAs(UnmanagedType.I4)]
        public int max_connections;

        // Token: 0x040000BA RID: 186
        [MarshalAs(UnmanagedType.I4)]
        public int max_chan;

        // Token: 0x040000BB RID: 187
        [MarshalAs(UnmanagedType.U8)]
        public long maintenance_expiration_date;

        // Token: 0x040000BC RID: 188
        [MarshalAs(UnmanagedType.U8)]
        public long support_expiration_date;

        // Token: 0x040000BD RID: 189
        [MarshalAs(UnmanagedType.I4)]
        public int max_wm_connections;

        // Token: 0x040000BE RID: 190
        [MarshalAs(UnmanagedType.U8)]
        public long last_erp_check_date;
    }
}

C++ Code:


#include "stdafx.h"
#include <apiquery2.h>

#include <windows.h>
#include <stdio.h>
#include <tchar.h>
#include <string>
#include <ctime>
#include <iostream>

struct InfoNative
{
    // Token: 0x06000025 RID: 37 RVA: 0x000021CC File Offset: 0x000003CC


    // Token: 0x040000AA RID: 170


    LPSTR usercode;

    // Token: 0x040000AB RID: 171
    //[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4, ArraySubType = UnmanagedType.U4)]
    unsigned int* version[4];


    unsigned long first_activation_ts;

    // Token: 0x040000AD RID: 173

    BYTE already_activated;



    // Token: 0x040000AE RID: 174
    BYTE auto_renew;

    // Token: 0x040000AF RID: 175
    //[MarshalAs(UnmanagedType.U2)]
    unsigned short review_status;

    // Token: 0x040000B0 RID: 176
    //[MarshalAs(UnmanagedType.LPWStr)]
    LPWSTR company_name;

    // Token: 0x040000B1 RID: 177
    //[MarshalAs(UnmanagedType.LPWStr)]
    LPWSTR contact_name;

    // Token: 0x040000B2 RID: 178
    //[MarshalAs(UnmanagedType.LPStr)]
    LPSTR email;

    // Token: 0x040000B3 RID: 179
    //[MarshalAs(UnmanagedType.LPStr)]
    LPSTR telephone;

    // Token: 0x040000B4 RID: 180
    //[MarshalAs(UnmanagedType.LPStr)]
    LPSTR country_id;

    // Token: 0x040000B5 RID: 181
    //[MarshalAs(UnmanagedType.LPStr)]
    LPSTR country_name;

    // Token: 0x040000B6 RID: 182
    //[MarshalAs(UnmanagedType.LPStr)]
    LPSTR admin_email;

    // Token: 0x040000B7 RID: 183
    //[MarshalAs(UnmanagedType.LPWStr)]
    LPWSTR reseller_name;

    // Token: 0x040000B8 RID: 184
    //[MarshalAs(UnmanagedType.U8)]
    unsigned long expiration_date_ts;

    // Token: 0x040000B9 RID: 185
    //[MarshalAs(UnmanagedType.I4)]
    int max_connections;

    // Token: 0x040000BA RID: 186
    //[MarshalAs(UnmanagedType.I4)]
    int max_chan;

    // Token: 0x040000BB RID: 187
    //[MarshalAs(UnmanagedType.U8)]
    unsigned long maintenance_expiration_date;

    // Token: 0x040000BC RID: 188
    //[MarshalAs(UnmanagedType.U8)]
    unsigned long support_expiration_date;

    // Token: 0x040000BD RID: 189
    //[MarshalAs(UnmanagedType.I4)]
    __int32 max_wm_connections;

    // Token: 0x040000BE RID: 190
    //[MarshalAs(UnmanagedType.U8)]
    unsigned long last_erp_check_date;
};

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}


//This version of the function works, because the properties are not set.

InfoNative* generate_response_info_native()
{
    long expiration = 1765416838;
    InfoNative *response = new InfoNative();

    response->usercode = (char*)&"NCDAXA";

    response->admin_email = (char*)&"(REDACTED)";

    //response->already_activated =  1; ---TROUBLE!

    //response->auto_renew =  1; ---TROUBLE!
    *response->version = new unsigned int[4]{ 17, 1, 953, 0 };
    response->company_name = (LPWSTR)"(REDACTED)";
    response->contact_name = (LPWSTR)"(REDACTED)";
    response->country_id = (LPSTR)"(REDACTED)";
    response->country_name = (LPSTR)"(REDACTED)";
    response->email = (LPSTR)"(REDACTED)";
    response->expiration_date_ts = expiration;
    //response->first_activation_ts = 1544492038;  ---TROUBLE!
    std::time_t result = std::time(nullptr);
    long int now = static_cast<long int> (result);
    response->last_erp_check_date = now;
    //response->review_status = 1; ---TROUBLE!
    response->telephone = (LPSTR)"(REDACTED)";
    response->reseller_name = (LPWSTR)"";
    response->max_connections = 16; //16
    response->max_chan = 8; //8
    response->maintenance_expiration_date = expiration;

    response->support_expiration_date = 0;
    response->max_wm_connections = 16;

    return response;
}
//This function is the same as above, but with the troublesome lines uncommented, so you don't have to do that.
InfoNative* generate_response_info_native_with_trouble()
{

    long expiration = 1765416838;
    InfoNative *response = new InfoNative();

    response->usercode = (char*)&"NCDAXA";

    response->admin_email = (char*)&"(REDACTED)";

    response->already_activated =  1; //TROUBLE!

    response->auto_renew =  1; //TROUBLE!
    *response->version = new unsigned int[4]{ 17, 1, 953, 0 };
    response->company_name = (LPWSTR)"(REDACTED)";
    response->contact_name = (LPWSTR)"(REDACTED)";
    response->country_id = (LPSTR)"(REDACTED)";
    response->country_name = (LPSTR)"(REDACTED)";
    response->email = (LPSTR)"(REDACTED)";
    response->expiration_date_ts = expiration;
    response->first_activation_ts = 1544492038;  //TROUBLE!
    std::time_t result = std::time(nullptr);
    long int now = static_cast<long int> (result);
    response->last_erp_check_date = now;
    response->review_status = 1; //TROUBLE!
    response->telephone = (LPSTR)"(REDACTED)";
    response->reseller_name = (LPWSTR)"";
    response->max_connections = 16; //16
    response->max_chan = 8; //8
    response->maintenance_expiration_date = expiration;

    response->support_expiration_date = 0;
    response->max_wm_connections = 16;

    return response;
}
typedef struct
{
    //[MarshalAs(UnmanagedType.LPStr)]
    LPSTR product_code;
    //[MarshalAs(UnmanagedType.U8)]
    long first_activation_ts;
} InfoNativeTeste;

typedef int(*Callback)(InfoNative *);
InfoNativeTeste test;
InfoNative* responseOut;
InfoNative* finalResponse = new InfoNative();
extern "C" __declspec(dllexport) long GetResponse(__int64 a1, Callback a2)
{





    MessageBox(NULL, _T("Beginning Test from CPP!"), _T("Hi"), NULL);
    responseOut = generate_response_info_native_with_trouble(); //TODO: Content is troublesome

    int resp = a2(responseOut);



    MessageBox(NULL, _T("Data Sent to .NET!"), _T("Hi"), NULL);
    return  1i64;
}

(also available at this (small) GitHub Repo, with a prebuilt copy on the Releases Section)

Problem is:

Everytime I set one of the properties which are commented out and tagged with ---TROUBLE! (at dllmain.cpp), I get the following error:

Assistente para Depuração Gerenciada 'FatalExecutionEngineError' : 'O tempo de execução encontrou um erro fatal. O endereço do erro é 0x3517b97e, no thread 0xea4. O código do erro é 0xc0000005. Esse erro pode ser um bug no CLR ou nas partes não segura ou não verificável do código do usuário. Origens comuns desse bug incluem erros de marshaling de usuário para COM-interop ou PInvoke, o que pode danificar a pilha.'

Which, in english, is basically:

Managed Debugging 'FatalExecutionEngineError': 'The runtime encountered a fatal error. The error address is 0x3517b97e, on thread 0xea4. The error code is 0xc0000005. This error could be a bug in the CLR or in the unsafe or unverifiable portions of user code. Common sources of this bug include user marshaling errors for COM-interop or PInvoke, which can damage the stack. '

The error happens at the callback call (a2(responseOut) at dllmain.cpp)

Any help would be appreciated.

Yours Faithfully, Gabriel.

c#
c++
interop
marshalling
c#-native-library
asked on Stack Overflow Oct 15, 2019 by GabrielTK • edited Oct 15, 2019 by GabrielTK

0 Answers

Nobody has answered this question yet.


User contributions licensed under CC BY-SA 3.0