Tag Archives: DllImport

Always Use Plain Type(e.g. char*) As Parameter For P/Invoke

Background:

Recently, a customer encountered a strange issue. He created a C++ class library with I/O operation:

Source File:

#include "stdafx.h"
#include
#include

#include "DynamicDLLToCall.h"
using namespace std;

void zlog(string fstr)
{
	FILE * debug;
	debug = fopen("zlog.txt", "a");
	ifstream iFile(fstr);
	fprintf(debug, "fsadfsdfsdfsdfdsfsdf");
	fclose(debug);
}

Header File:

using namespace System;
using namespace std;

extern "C" __declspec(dllexport) void zlog(string fstr);

Now, he want to call zlog() method in a .NET project:

[DllImport("D:/ClassLibrary1.dll")]
public static extern void zlog(string fstr);//imported func

private void Button_Click(object sender, RoutedEventArgs e)
{
            zlog("asdas");
}

Issue:
This app crashed when the zlog() function is called and the zlog.txt file was successfully created.

Troubleshoot:

At first, I tried to comment some code snippets in the zlog(string fstr) function, but this issue still existed, so I think it should be more related to the declaration of this function.

With the help from C++ expert, it may be caused by this reason: C++ doesn’t support(or fully support) ABI(Application Binary Interface) which is required to help clean the stack of the object.

What is ABI? Please refer to these references:

ABIs cover details such as:

–the sizes, layout, and alignment of data types

–the calling convention, which controls how functions’ arguments are passed and return values retrieved; for example, whether all parameters are passed on the stack or some are passed in registers, which registers are used for which function parameters, and whether the first function parameter passed on the stack is pushed first or last onto the stack

–how an application should make system calls to the operating system and, if the ABI specifies direct system calls rather than procedure calls to system call stubs, the system call numbers

–and in the case of a complete operating system ABI, the binary format of object files, program libraries and so on.

A complete ABI, such as the Intel Binary Compatibility Standard (iBCS),[1] allows a program from one operating system supporting that ABI to run without modifications on any other such system, provided that necessary shared libraries are present, and similar prerequisites are fulfilled.

——–

So always use plain type(e.g. char*) as parameter for P/invoke instead of using type within the std namespace as parameter.

The following code worked well now:

C++ declaration:

extern "C" __declspec(dllexport) void zlog(char* fstr);
1

C++ function:
1
void zlog(char* fstr)
{
 //...your code
}

In .NET application code behind:

[DllImport("DynamicDLLToCall", CallingConvention = CallingConvention.Cdecl)]
public static extern void zlog(string fstr);