MarshalAs SAFEARRAY in C# .Net Core

Ali Ghorbanian 1 Reputation point
2021-10-25T08:07:35.637+00:00

I have C++ Dll function:

__declspec(dllexport) int __stdcall GetData(SAFEARRAY** ppSafeArrayToModify) {

    IRecordInfoPtr pIRecInfs = NULL;
    SafeArrayGetRecordInfo(*ppSafeArrayToModify, &pIRecInfs);
    if (pIRecInfs == NULL)
    {
        return 2020;
    }
}

I want use that Dll in C# .Net Core with down syntax:

public static extern int GetData(
    [In]
    [Out]
    [MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_RECORD)] 
    ref db_anneal_stack_csharp[] myStructArr);

But when run this code,I see this error.

{"Operation is not supported. (0x80131515)"}.

When I run this syntax in C#, Do Not have any error. Please help me. good luck.

C#
C#
An object-oriented and type-safe programming language that has its roots in the C family of languages and includes support for component-oriented programming.
11,288 questions
C++
C++
A high-level, general-purpose programming language, created as an extension of the C programming language, that has object-oriented, generic, and functional features in addition to facilities for low-level memory manipulation.
3,851 questions
{count} votes

1 answer

Sort by: Most helpful
  1. Jack J Jun 24,641 Reputation points Microsoft Vendor
    2021-10-26T06:20:33.803+00:00

    @Ali Ghorbanian , based on my test, I can run the code successfully in a c# .net core(.net 5.0) console app.

    Please check if you have done the following steps.

    First, Please ensure that you set the C++/CLI properties like the following picture:

    143617-image.png

    Second, Please set the platform to x86 in your .net core console app.

    143678-image.png

    Third, Please make sure that you use the absolute path for the dll in the dllimport code.

     [DllImport(@"D:\projectname\Debug\NativeLibrary.dll", CallingConvention = CallingConvention.Cdecl)]  
     private static extern void GetResult([MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_I4)] ref int[] ar);  
    

    Finally, I provide a completed code example so that you can have a check.

    C++:

    #include "pch.h"  
    #include <comdef.h>  
      
    // When you are using pre-compiled headers, this source file is necessary for compilation to succeed.  
      
    extern "C" __declspec(dllexport) void GetResult(SAFEARRAY * &data)  
    {  
        if (data != NULL)  
        {  
            // Begin print content of SAFEARRAY  
            VARTYPE vt;  
            HRESULT hr = SafeArrayGetVartype(data, &vt);  
            if (SUCCEEDED(hr))  
            {  
                // To make this code simple, we print only  
                // SAFEARRAY(VT_I4)  
                if (vt == VT_I4)  
                {  
                    int* pVals;  
                    hr = SafeArrayAccessData(data, (void**)&pVals); // direct access to SA memory  
                    if (SUCCEEDED(hr))  
                    {  
                        long lowerBound, upperBound;  // get array bounds  
                        SafeArrayGetLBound(data, 1, &lowerBound);  
                        SafeArrayGetUBound(data, 1, &upperBound);  
                        long cnt_elements = upperBound - lowerBound + 1;  
                        for (int i = 0; i < cnt_elements; i++)  // iterate through returned values  
                        {  
                            int val = pVals[i];  
                            printf("C++: %d\n", val);  
                        }  
                        SafeArrayUnaccessData(data);  
                    }  
                    else  
                    {  
                        // Error  
                    }  
                }  
            }  
            else  
            {  
                // Error  
            }  
            // End print content of SAFEARRAY  
            // Delete the SAFEARRAY if already present  
            SafeArrayDestroy(data);  
            data = NULL;  
        }  
        {  
            // Creation of a new SAFEARRAY  
            SAFEARRAYBOUND bounds;  
            bounds.lLbound = 0;  
            bounds.cElements = 10;  
            data = SafeArrayCreate(VT_I4, 1, &bounds);  
            int* pVals;  
            HRESULT hr = SafeArrayAccessData(data, (void**)&pVals); // direct access to SA memory  
            if (SUCCEEDED(hr))  
            {  
                for (ULONG i = 0; i < bounds.cElements; i++)  
                {  
                    pVals[i] = i + 100;  
                }  
            }  
            else  
            {  
                // Error  
            }  
        }  
    }  
    

    C#:

    [DllImport(@"D:\ProjectName\Debug\NativeLibrary.dll", CallingConvention = CallingConvention.Cdecl)]  
            private static extern void GetResult([MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_I4)] ref int[] ar);  
            static void Main(string[] args)  
            {  
                var data = new int[] { 1, 2, 3, 4, 5 };  
                GetResult(ref data);  
                if (data != null)  
                {  
                    for (int i = 0; i < data.Length; i++)  
                    {  
                        Console.WriteLine("C#: {0}", data[i]);  
                    }  
                }  
                else  
                {  
                    Console.WriteLine("C#: data is null");  
                }  
                Console.ReadKey();  
            }  
    

    Tested result:

    143618-image.png


    If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".
    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.