0

i am trying to make a c++ DLL project in VS2017 to use in a VB.NET VS2017 project.

the c++ code;

MyCudaLib.h

#ifndef DLL3_H
#define DLL3_H

#ifdef DLL3_EXPORTS
#define DLL3_API __declspec(dllexport)
#else
#pragma message("automatic link to MyCudaLib.LIB")
//#pragma comment(lib, "MyCudaLib.lib")
#define DLL3_API __declspec(dllimport)
#endif

int* __stdcall test_array();

#endif //DLL3_H

MyCudaLib.cpp

#include <stdio.h>
#include "MyCudaLib.h"
#include <Windows.h>
#include <stdexcept>
#include <sstream>
using namespace std;

#define DLL3_EXPORTS


BOOL APIENTRY DllMain(HANDLE /*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;
}
int* __stdcall test_array()
{
int arr[]{ 30,50,60,70 };

return  arr;
}

in VB part of the code

Private Declare Function test_array Lib "MyCudaLib.dll" () As Integer()

Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load

    Console.WriteLine(test_array(0))

End Sub

is my exporting part of code is wrong? c++ part compiled wtihout error but VB part of the code wont work gives error.

System.Runtime.InteropServices.MarshalDirectiveException: ''return value' cannot arranged.

Note: My point to make a proper working function in c++ is to write a CUDA code to program the GPU. I can write and compile code in CUDA in c++ without problem. But students in my class cannot program in c++ and i can't write more complex code with c++. So, i thought, if i can use the cuda function outside the c++ environment, we all can code it with vb or other languages.

  • Please provide code without additional decorations (line numbers, markers like the `>` you used, ...) such that it can just be copied/pasted without changes! – Aconcagua Jul 18 '18 at 12:58
  • Possible duplicate of [How to return local array in C++?](https://stackoverflow.com/questions/7769998/how-to-return-local-array-in-c) – Andrew Henle Jul 18 '18 at 14:43

1 Answers1

0

Sure your function compiles fine - it is defined as a function returning a single int and does so as well (return *arr; is equivalent to return arr[0];).

From MarshalDirectiveException

The exception that is thrown by the marshaler when it encounters a MarshalAsAttribute it does not support.

As you did not provide an English error message, I can only guess what's happening now, but there are only few options available:

  1. You have yet another error with your marshaling not visible here.
  2. The function is not recognised due to C++ name mangling (see below).
  3. Incompatibility between int returned in function and expected array is recognised.
  4. The int is interpreted as pointer – but pointer size does not match and the type cannot be marshaled at all.

If you want to return an array, you need to define your function as such:

int* getArray()
// ^
{
    static int a[] = {1, 2, 3};
//  ^^^^^^ we cannot return an array with local storage duration, so make it
//         static, global, or allocate one on heap (new int[]; but assure the
//         array to be delete[]d appropriately again to avoid memory leak)

    return a; // NOT dereferenced!
}

Be aware that you have C++ name mangling applied. You might possibly prefer a C-kompatible interface:

extern "C" int* getArray();

However, you cannot return C++ data types this way like std::vector – which in most cases even is preferrable, though, as those types usually are incompatible across different implementations (DLL compiled with MSVS, EXE with GCC/MinGW) anyway.

Finally be aware that via a pointer, you lose information about array size! You need to find other means to provide this information to the user of your library.

Aconcagua
  • 24,880
  • 4
  • 34
  • 59
  • Then have a look at [here](https://stackoverflow.com/questions/3776485/marshal-c-int-array-to-c-sharp) as well. – Aconcagua Jul 18 '18 at 14:10
  • is my call from VB true ? – tevfik oguz Jul 19 '18 at 10:50
  • *"true"* -- if you mean "correct", then *probably* not. According to the answer to referenced question, you'd need to marshal as `IntPtr`, not as integer array. I've been out of .NET for a while, though, and currently no environment available to do so myself, so need to leave verifying to you... – Aconcagua Jul 19 '18 at 11:41
  • hi, @Aconcagua,i wanna ask this, when we make the function as ' int* __stdcall test_array() ' , aren't we make it 'IntPtr' ?. And also i used this dll inside a c++ project and it worked. i changed the code to make random array but i dont know how to post it here new version so can't show you them. only i can change the first post. i tried answer my question to post it before but someone deleted it. anyway, it works in another c++ project but not in VB with this DLL calling lines. – tevfik oguz Jul 19 '18 at 12:16
  • @tevfikoguz You need to be aware that C and C++ have a different interpretation of what a (raw) array is than .NET has. .NET arrays ressemble more to `std::vector` than C++ arrays. If you do bad marshalling, you get a result comparable to creating a raw array, `reinterpret_cast`ing it to a `std::vector` and hoping you magically get a true vector from. Of course it works if you use the dll from another C++ project: then both DLL and EXE have the same understanding of what a pointer to int (`int*`) is. – Aconcagua Jul 19 '18 at 12:27
  • @tevfikoguz Yes, you make an `IntPtr` from your C++ code, but this is totally different from `Integer()`, which is what you tell the marshaller to expect as result... – Aconcagua Jul 19 '18 at 12:28
  • However: Your *edited* code now yields undefined behaviour: you are returning a pointer to an array with local storage duration, which is destructed immediately before the function is exited, thus the pointer is dangling. It is just pure accident that your code *appears* to work, it might well have resulted in crash as well... – Aconcagua Jul 19 '18 at 12:33
  • ,so you saying, even it works in c++ project the result could be eraseable if memory runs out or something even in coding another c++ project? and there is no way to make it out an array from c++ dll? with safe and sound. ? !!! c++ so much complicated !!! – tevfik oguz Jul 19 '18 at 13:29
  • when i call the function from VB just an integer output, it returns a negative number. it should be address of the array right?. how can i point this address with VB? and another thing, what is the way to make a result with a string? – tevfik oguz Jul 19 '18 at 14:07
  • You should have a look at [`IntPtr` documentation](https://msdn.microsoft.com/en-us/library/system.intptr%28v=vs.110%29.aspx), especially at `ToPointer`. Pretty sure you will have to use unsafe code (C#), looks as if, though, not supported by VB. As mentioned already, being out of .NET for a while and currently no system to test (and while doing .NET, C#, not VB). Strings: You'll be doomed to fail if you try to return a `std::string` object, you need to return a const character pointer. If I recall correctly, there is a standard marshaller for to get .NET strings from. – Aconcagua Jul 19 '18 at 15:38
  • what if i made a customise structure , how should i use this structure with a function in a DLL??? i see an example but don't fully understand it. ["theLink"](https://stackoverflow.com/questions/9632713/how-to-call-a-c-dll-file-from-visual-basic-2010) . The writings are way high from my level of c++. – tevfik oguz Jul 23 '18 at 13:48
  • According to the link provided, you should use cdecl calling convention (you use stdcall; calling conventions define how parameters are passed from caller to callee and who of both cleans them up again). Then you need a way to tell VB how that data type is to be marshaled (data converted from one realm to the other, i. e. how to map unmanaged types to managed ones and vice versa). There is a way to write custom marshalers in C#, completely unfamiliar with VB in this respect, though. In the past, I did marshaling manually in C++ CLI... – Aconcagua Jul 23 '18 at 15:02
  • first i defined an empty array with 10 elements in VB then call the function with the first element in the array. 'Private Declare Function test_array Lib "MyCudaLib.dll" (ByVal aktar As Integer) As Integer' then, in c++, try to modify the array with this code. '__declspec(dllexport) int __stdcall test_array(int * AKTAR) { for (int i = 0; i < 10; ++i) { AKTAR[i] = rand(); } return 0; }' but i get error in VB ' System.AccessViolationException: Attempted to read or write protect' when calling it like this 'Dim retrnn As Integer = test_array(aktarım(0))' What should i do – tevfik oguz Jul 24 '18 at 08:22
  • sorry i have to write here down all codes because someone coming and deleting my answers. – tevfik oguz Jul 24 '18 at 08:24
  • i finally found my answer with you guidance of course @ Aconcagua . the key is using _GCHandle.Alloc_ function to allocate memmory and get it's pointer address in VB. Then i send it to dll in c++ to change it. finally. !!!! thanks my friend! – tevfik oguz Jul 24 '18 at 10:17
  • @tevfikoguz Glad I could help you... Just a (*general*) note on answers: Only write one, if you really want to answer something. If you want to add additional code, edit your question instead. If the edit means a (minor) change of the character of the question, the edit should be clearly marked as such (answers given so far might get invalidated by your edit!), or better, ask a new question (in given case, I'd say editing is OK, if clearly visible). – Aconcagua Jul 24 '18 at 17:18