www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - extern export (Pascal) does not works correctly under Windows platform

reply "Andrey" <vangelisforever yandex.ru> writes:
I've been created C# console app by MS VS2008 and shared library 
mydll.dll by D dmd tool.

mydll consist of: dll.d, mydll.d, mydll.def.
compiled by command: dmd -ofmydll.dll mydll.d dll.d mydll.def

------- dll.d code here:

module WWWW;
version(Windows)
{
	import std.c.windows.windows;
	import core.sys.windows.dll;

	__gshared HINSTANCE g_hInst;

	extern (Windows)
	BOOL DllMain(HINSTANCE hInstance, ULONG ulReason, LPVOID 
pvReserved)
	{
		switch (ulReason)
		{
			case DLL_PROCESS_ATTACH:
				g_hInst = hInstance;
				dll_process_attach( hInstance, true );
				break;

			case DLL_PROCESS_DETACH:
				dll_process_detach( hInstance, true );
				break;

			case DLL_THREAD_ATTACH:
				dll_thread_attach( true, true );
				break;

			case DLL_THREAD_DETACH:
				dll_thread_detach( true, true );
				break;
			default:
				break;
		}
		return true;
	}

}

-------- mydll.d code here:

module mydll;

import std.stdio;
import WWWW;

// pascal model is the same that stdcall
export extern(Pascal) // full analog of STDCALL
{
void dllprint() // works correctly everytime
{
	writeln("Hello!!!");
}

void dllprint_vec(byte* pBytes, uint len) // the second parameter 
always wrong!!!
{
	writefln("lengths=%d", len);
	writeln("Bytes are:");
	for(int i=0; i<len; i++)
		writefln("%d", pBytes[i]);
}

void printlength(uint len, double d) // the second parameter 
always wrong!!!
{
      writefln("sizeof(uint)=%d, printlength=%d, d = %.2f \n", 
typeof(len).sizeof, len, d);
}

}

---------mydll.def
LIBRARY "mydll.dll"
EXETYPE NT
SUBSYSTEM WINDOWS
CODE PRELOAD DISCARDABLE
DATA PRELOAD SINGLE
EXPORTS

---------------------------

main C# console code that calls mydll.dll exported functions:

namespace Test_D_DLL
{

     public partial class Form1 : Form
     {
		[DllImport("mydll.dll", CallingConvention = 
CallingConvention.StdCall)]
         public static unsafe extern void DLLPRINT();

		[DllImport("mydll.dll", CallingConvention = 
CallingConvention.StdCall)]
		public static unsafe extern void DLLPRINT_VEC(byte[] pB, uint 
len);

		[DllImport("mydll.dll", CallingConvention = 
CallingConvention.StdCall)]
		public static unsafe extern void PRINTLENGTH(uint len, double 
d);
		

         unsafe public Form1()
         {
             InitializeComponent();

             dllprint(); // is OK, prints "Hello!"


	     uint d = 89898989;
      	     printlength(d, 0.7612); // WRONG!!! the second 
argument prints always 0.0, but expects 0.7612 !!!!

             byte[] b = new byte[5];
             b[0] = 123;
             b[1] = 10;
             b[2] = 20;
             b[3] = 30;
             b[4] = 88;

    	    Console.WriteLine(sizeof(uint));

	    d = 5;
	    fixed (byte* pB = &(b[0]))
             {
	       DLLPRINT_VEC(pB, d); // FATAL EXCEPTION!!! the second 
parameter more bigger than 5!!!
	    }
         }
     }
}

You can find this DMD bug in 2.58 version, 2.59, 2.60, 2.61. 
Why??? And how can we solve this problem???
Feb 15 2013
parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 2/15/13, Andrey <vangelisforever yandex.ru> wrote:
 // pascal model is the same that stdcall
 export extern(Pascal) // full analog of STDCALL

No it's not, pascal parameters are pushed left-to-right, stdcall does it the other way around. Try using extern(Windows) here and see if that works. See http://en.wikipedia.org/wiki/X86_calling_conventions#pascal and http://en.wikipedia.org/wiki/X86_calling_conventions#stdcall . Also see Agner's detailed calling convention PDF: www.agner.org/optimize/calling_conventions.pdf
Feb 15 2013