1

Here is c++ dll code:

#include<stdlib.h>
#include "pch.h"

extern "C" _declspec(dllexport) int Add(int a, int b)
{
    return a + b;
}

C# code, that i run in Visual Studio:

[DllImport(@"C:\Dll1.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern int Add(int port, int speed);

public static void Main()
{
    int res = Add(8, 11);
    Console.WriteLine(res);

}

No problems, output: 19

PowerShell code:

Add-Type -Name MyFunctions -Namespace Cpp @'
[DllImport(@"C:\Dll1.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern int Add(int port, int speed);
'@

[Cpp.MyFunctions]::Add(8, 11)

Output: An attempt was made to load a program with an incorrect format. (Exception from HRESULT: 0x8007000B)

But functions from user32.dll/kernel32.dll imports without any problems.

How to fix it?

Danny
  • 410
  • 2
  • 8

1 Answers1

2

Make sure that you are using 32 bit dll for 32 bit powershell process and 64 bit dll for 64 bit powershell process. The error looks like as if you trying to load 32 bit dll into 64 bit process. Please note that .net applications compiled as "Any CPU" will run in 32 bit mode by default even on 64-bit operating system.

Update

If you have a sources for your dll, then you should recompile it for 64 bit environment and then import this 64-bit build.

If you need to execute PS script in a both 32- and 64-bit powerShell environments, then you should deploy two versions of dll and select the right one in runtime. I do not know how this can be done for PS, but for C# solution you can use #ifdef-based solution as described here: Using a 32bit or 64bit dll in C# DllImport

If you do not have sources for your dll, then all become complicated and I do not know any direct solution here. You can try to wrap your DLL in the 32-bit in-process (or even out-of-process) COM server (with help of C# or C++) and then use this server with New-Object. As I know, the Windows have special shims which allow to utilize 32-bit COM objects from 64-bit process and vice versa, but I am unsure if this will work for PS or not.

For build-in DLLs Windows has automatic file paths redirection from System32 to SysWOW64. So, when you requesting user32 import, you will get different user32 libraries depending on your process bitness. You can read more about this here: 64bit PowerShell calls the 32bit DLL

Serg
  • 3,454
  • 2
  • 13
  • 17
  • Good, you right, this code works on PowerShell (x86). But user32.dll works in 32 and 64 bit PowerShell. How to make my dll works too on any Powershell (32 and 64)? – Danny Aug 03 '21 at 13:27
  • 1
    @Danny Compile a 32-bit version and a 64-bit version of your DLL, then import both and [hide them behind a common method that decides which one to call](https://stackoverflow.com/a/10852827/712649) based on the runtime bitness – Mathias R. Jessen Aug 03 '21 at 13:37
  • @Danny, I updated the answer to account possible solutions. – Serg Aug 03 '21 at 13:40