Platform Invoke of TakeCmd.dll

I have the following function defined in my PowerShell profile;
Code:
function tcc
{
  & "c:\program files\jpsoft\tcmd25\tcc.exe" /I /Q /C $args

}
This allows me to call Take Command internal functions and commands from PowerShell.

Loading tcc.exe this way is fast, but I was looking for a way to make it faster.

The method I am testing now is using Platform Invoke to call the internal functions and commands from the unmanaged TakeCmd.dll file.

I am using the TakeCmd.h file from the plugin SDK as a guide.

First, I have created a TakeCmd.ps1 file containing C# code to define a command and a function that exist in the unmanaged TakeCmd.dll file;
Code:
Add-Type -TypeDefinition @'
using System;
using System.Runtime.InteropServices;

public static class TakeCmd
{
[DllImport("takecmd.dll", CharSet = CharSet.Auto)]
public static extern void honk();

[DllImport("takecmd.dll", CharSet = CharSet.Auto)]
public static extern int GetExeType( string pszFilename );
}
'@
I load this in PowerShell as;
Code:
PS E:\Utils> .\takecmd.ps1
I can see the class members;
Code:
PS E:\Utils> [takecmd] | get-member -static


   TypeName: TakeCmd

Name            MemberType Definition
----            ---------- ----------
Equals          Method     static bool Equals(System.Object objA, System.Object objB)
GetExeType      Method     static int GetExeType(string pszFilename)
honk            Method     static void honk()
ReferenceEquals Method     static bool ReferenceEquals(System.Object objA, System.Object objB)
I then change to the folder where the unmanaged TakeCmd.dll is located;
Code:
PS E:\Utils> [environment]::CurrentDirectory = 'c:\program files\jpsoft\tcmd25'
...and I can beep (honk);
Code:
PS E:\Utils> [TakeCmd]::honk()
When I invoke the GetExeType function;
Code:
PS E:\Utils> [TakeCmd]::GetExeType(".\WMIGen.exe")
-2
PS E:\Utils> [TakeCmd]::GetExeType("WMIGen.exe")
-2
...the return value is not correct.

Here is GetExeType from TakeCmd.h;
Code:
INT WINAPI GetExeType( LPCTSTR pszFilename );
/*
    Returns an integer specifying the type of executable:
    

        0    // Error, or not an EXE file
        1    // Just plain old MS-DOS
        2    // DOS app with a PIF file
        3    // Windows 3.x
        4    // Windows 3.x VxD
        5    // OS/2 2.x
        6    // Windows NT, 2000, XP, or 2003 GUI
        7    // Windows NT, 2000, XP, or 2003 console mode
        8    // Windows NT, 2000, XP, or 2003 Posix
        9    // Windows x64 GUI
        10    // Windows x64 console
        11    // EFI
        12    // EFI boot driver
        13    // EFI runtime driver
        14    // EFI ROM
        15    // XBox
        16    // Windows boot application
*/
For the example function I am testing, GetExeType, I would appreciate input from the PowerShell folks on how to properly define the DllImport, and how to properly get the return value from this example.

Joe
 
May 20, 2008
10,634
81
Syracuse, NY, USA
What is the "unmanaged takecmd.dll file"?

I wouldn't be surprised if little worked without TCC performing whatever initializations are needed.

Does Powershell know that strings are Unicode?
 
C++ is used to create TakeCmd.dll, which means that the .dll is unmanaged. This can be verified as follows;
Code:
c:\program files\jpsoft\tcmd25>corflags.exe takecmd.dll
Microsoft (R) .NET Framework CorFlags Conversion Tool.  Version  4.8.3928.0
Copyright (c) Microsoft Corporation.  All rights reserved.

corflags : error CF008 : The specified file does not have a valid managed header
I used C# to create jlcNETUtils.dll, which means that the .dll is managed. This can be verified as follows;
Code:
e:\utils>corflags.exe jlcNETUtils.dll
Microsoft (R) .NET Framework CorFlags Conversion Tool.  Version  4.8.3928.0
Copyright (c) Microsoft Corporation.  All rights reserved.

Version   : v4.0.30319
CLR Header: 2.5
PE        : PE32
CorFlags  : 0x1
ILONLY    : 1
32BITREQ  : 0
32BITPREF : 0
Signed    : 0
In the .NET PowerShell environment, the DllImport Attribute can be set to recognize Unicode.

So, in my previous post, the DllImport would become;
Code:
Add-Type -TypeDefinition @'
using System;
using System.Runtime.InteropServices;

public static class TakeCmd
{
[DllImport("takecmd.dll", CharSet = CharSet.Unicode)]
public static extern void honk();

[DllImport("takecmd.dll", CharSet = CharSet.Unicode)]
public static extern int GetExeType( string pszFilename );
}
'@
A good majority of the unmanaged Windows API has been translated to Platform Invoke format, so as to be called from managed code.

Joe