I am working on a project and currently have the following structure:
- C# WPF project containing the User Interface as well as calls to external methods.
- C DLL project containing an algorithm.
- ASM DLL project containing an algorithm.
For simplicity, let's assume the algorithm simply takes no parameters and returns the sum of two, predefined numbers.
Here's the function signature and implementation in the C (second) project:
int Add(int x, int y)
{
return x y;
}
extern "C" __declspec(dllexport) int RunCpp()
{
int x = 1, y = 2;
int z = Add(x, y);
return z;
}
And here's how I call the function in C#:
[DllImport("Algorithm.Cpp.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int RunCpp();
This works just fine - calling the function in C# returns the value 3, everything is working proplerly, no exceptions thrown.
However, I am now struggling to call the ASM procedure in C# code. I have seen (and tested myself to an extent) that it's impossible to call a MASM DLL directly in C# code. However, I've heard that it's possible to call ASM in C and call that function in C#.
1. My first question is - is calling ASM code actually possible directly in C#? When I try that, I get an exception that basically says the binary code is incompatible.
2. I have tried to use C to indirectly call the ASM DLL, and while I get no exception, the returned value is "random", as in, it feels like a remainder left in memory, for example: -7514271. Is this something I'm doing wrong, or is there another way to achieve this?
Here's the code for calling ASM in C :
typedef int(__stdcall* f_MyProc1)(DWORD, DWORD);
extern "C" __declspec(dllexport) int RunAsm()
{
HINSTANCE hGetProcIDDLL = LoadLibrary(L"Algorithm.Asm.dll");
if (hGetProcIDDLL == NULL)
{
return 0;
}
f_MyProc1 MyProc1 = (f_MyProc1)GetProcAddress(hGetProcIDDLL, "MyProc1");
if (!MyProc1)
{
return 0;
}
int x = 1, y = 2;
int z = MyProc1(x, y);
FreeLibrary(hGetProcIDDLL);
return z;
}
Here, the code for calling C in C#:
[DllImport("Algorithm.Cpp.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int RunAsm();
And here's the ASM code of MyProc1
, if needed:
Main.asm:
MyProc1 proc x: DWORD, y: DWORD
mov EAX, x
mov ECX, y
add EAX, ECX
ret
MyProc1 endp
Main.def:
LIBRARY Main
EXPORTS MyProc1
CodePudding user response:
is calling ASM code actually possible directly in C#?
Example of this with two projects, C# and assembly based DLL. Looks like you already know how to get a C based DLL working. The project names are the same as the directory names, xcs for C# and xcadll for the dll. I started with empty directories and created empty projects, then moved source files into the directories and then added existing items to each project.
xcadll properties:
Configuration Type: Dynamic Library (.dll)
Linker | Input: xcadll.def
xcadll\xcadll.def:
LIBRARY xcadll
EXPORTS DllMain
EXPORTS Example
xcadll\xa.asm properties (for release build, /Zi is not needed):
General | Excluded From Build: No
General | Item Type: Custom Build Tool
Custom Build Tool | General | Command Line: ml64 /c /Zi /Fo$(OutDir)\xa.obj xa.asm
Custom Build Tool | General | Outputs: $(OutDir)\xa.obj
xcadll\xa.asm:
includelib msvcrtd
includelib oldnames ;optional
.data
.data?
.code
public DllMain
public Example
DllMain proc ;return true
mov rax, 1
ret 0
DllMain endp
Example proc ;[rcx] = 0123456789abcdefh
mov rax, 0123456789abcdefh
mov [rcx],rax
ret 0
Example endp
end
xcs\Program.cs:
using System;
using System.Runtime.InteropServices;
namespace xcadll
{
class Program
{
[DllImport("c:\\xcadll\\x64\\release\\xcadll.dll")]
static extern void Example(ulong[] data);
static void Main(string[] args)
{
ulong[] data = new ulong[4] {0,0,0,0};
Console.WriteLine("{0:X16}", data[0]);
Example(data);
Console.WriteLine("{0:X16}", data[0]);
return;
}
}
}
For debug, use
[DllImport("c:\\xcadll\\x64\\debug\\xcadll.dll")]
xcs properties | debug | enable native mode debugging (check the box)