[EDIT] I changed the source as suggested by Stephen Martin (in bold). And added the C ++ source code.
I would like to call an unmanaged function in a self-signed C ++ dll. This library reads the general computer memory for information on the status of third-party software. Since there are several values, I would like to return the values in a struct. However, inside the structure there is char [] (fixed-size char arrays). Now I am trying to get this structure from a dll, for example:
[StructLayout(LayoutKind.Sequential)] public struct SYSTEM_OUTPUT { UInt16 ReadyForConnect; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] String VersionStr; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1024)] String NameOfFile; // actually more of those } public partial class Form1 : Form { public SYSTEM_OUTPUT output; [DllImport("testeshm.dll", EntryPoint="getStatus")] public extern static int getStatus(out SYSTEM_OUTPUT output); public Form1() { InitializeComponent(); } private void ReadSharedMem_Click(object sender, EventArgs e) { try { label1.Text = getStatus(out output).ToString(); } catch (AccessViolationException ave) { label1.Text = ave.Message; } } }
I will also send the code from the C ++ dll, I am sure there is more to track. The original STATUS_DATA structure has an array of four instances of struct SYSTEM_CHARACTERISTICS , and inside this structure there are char[] s that are not populated (yet), which leads to a bad pointer. This is why I am trying to extract a subset of the first SYSTEM_CHARACTERISTICS element in STATUS_DATA .
#include <windows.h> #include <stdio.h> #include <conio.h> #include <tchar.h> #include <iostream> #if defined(_MSC_VER) #include <windows.h> #define DLL extern "C" __declspec(dllexport) #else #define DLL #endif using namespace std; enum { SYSID_LEN = 1024, VERS_LEN = 128, SCENE_LEN = 1024 }; enum { MAX_ENGINES = 4 }; struct SYSTEM_CHARACTERISTICS { unsigned short ReadyForConnect; char VizVersionStr[VERS_LEN]; char NameOfFile[SCENE_LEN]; char Unimplemented[SCENE_LEN]; // not implemented yet, resulting to bad pointer, which I want to exclude (reason to have SYSTEM_OUTPUT) }; struct SYSTEM_OUTPUT { unsigned short ReadyForConnect; char VizVersionStr[VERS_LEN]; char NameOfFile[SCENE_LEN]; }; struct STATUS_DATA { SYSTEM_CHARACTERISTICS engine[MAX_ENGINES]; }; TCHAR szName[]=TEXT("E_STATUS"); DLL int getStatus(SYSTEM_OUTPUT* output) { HANDLE hMapFile; STATUS_DATA* pBuf; hMapFile = OpenFileMapping( FILE_MAP_READ, // read access FALSE, // do not inherit the name szName); // name of mapping object if (hMapFile == NULL) { _tprintf(TEXT("Could not open file mapping object (%d).\n"), GetLastError()); return -2; } pBuf = (STATUS_DATA*) MapViewOfFile(hMapFile, FILE_MAP_READ, 0, 0, 0); if (pBuf == NULL) { _tprintf(TEXT("Could not map view of file (%d).\n"), GetLastError()); CloseHandle(hMapFile); return -1; } output->ReadyForConnect = pBuf->engine[0].ReadyForConnect; memcpy(output->VizVersionStr, pBuf->engine[0].VizVersionStr, sizeof(pBuf->engine[0].VizVersionStr)); memcpy(output->NameOfFile, pBuf->engine[0].NameOfFile, sizeof(pBuf->engine[0].NameOfFile)); CloseHandle(hMapFile); UnmapViewOfFile(pBuf); return 0; }
Now I get an empty output structure, and the return value is not 0, as intended. It is rather a change in a seven-digit number, which leaves me puzzled ... Am I messed up in a dll? If I make unmanaged code executable and debug it, I see that output populated with the appropriate values.
c ++ c # marshalling pinvoke ipc
rdoubleui
source share