by Hanman at 2013-03-09 05:32:00
I’m a noob to powershellby MattG at 2013-03-09 06:39:44
Would like to be able to write a powershell script to control a DMX Controller USB connected Hardware using its supplied DLL
The controller works fine with applications written in C++ or VB.
In +CC I can use the following to opening the interface
int interfaceOpen;
int numberOfInterface;
unsigned char dmxBlock[512];
DasUsbCommand(DHC_INIT,0, NULL);
interfaceOpen = DasUsbCommand(DHC_OPEN,0,0);
To send a signal
if (interface_open>0){
DasUsbCommand(DHC_DMXOUT, 512, dmxblock);
}
To Close the Interface
if (interface_open>0)
DasUsbCommand(DHC_CLOSE,0,0);
DasUsbCommand(DHC_EXIT,0, NULL);
Is this possible? I searched a lot on how to call a DLL function in powershell without sucess?
Thanks for the help
You absolutely can call unmanaged DLL functions in PowerShell although it’s not extremely straightforward. What I’m about to describe is an advanced technique. Although, since you’re already familiar with C/C++, the concepts should translate easily. The gist of it is that you need to compile C# code which declares the function signature and applies a DllImport attribute to the DLL you’re interested in. As an example, say I want to call the user32.dll MessageBox function. This is accomplished with the following C#/PowerShell code:by Hanman at 2013-03-09 22:47:47$Code = @'In your case where you are trying to import DasUsbCommand, you will need to provide the path to the DLL that exports the function as well as the function signature. Since you’re using enum values in the signature (or possibly symbolic constants), you would also need to define an enum in the C# code block or you could just opt to provide the raw values to the function. As an example, based on my the documentation I’ve read on your dll, I would probably implement the code you provided with the following script:
using System;
using System.Runtime.InteropServices;
public class Win32
{
[DllImport("C:\Windows\System32\user32.dll", CharSet = CharSet.Unicode)]
public static extern int MessageBox(IntPtr hWnd, String text, String caption, uint type);
}
'@
Add-Type -TypeDefinition $Code
[Win32]]::Zero, 'What is your choice?', 'Test Message', 3)$Code = @'
using System;
using System.Runtime.InteropServices;
public class YourDll
{
[DllImport("C:\PathToDLL\DasHard2006.dll", CharSet = CharSet.Auto)]
public static extern int DasUsbCommand(uint command, uint param, Char bloc);
}
'@
Add-Type -TypeDefinition $Code
$numberOfInterface = 0
$dmxBlock = New-Object Char(512)
[YourDll]::DasUsbCommand($DHC_INIT,0, $null)
$interfaceOpen = [YourDll]::DasUsbCommand($DHC_OPEN,0,0)
if ($interfaceOpen -gt 0)
{
[YourDll]::DasUsbCommand($DHC_DMXOUT, 512, $dmxBlock)
}
if ($interfaceOpen -gt 0)
{
[YourDll]::DasUsbCommand($DHC_CLOSE,0,0)
[YourDll]::DasUsbCommand($DHC_EXIT,0, $null)
}
Your mileage may vary with the code I provided since I had no way of testing it. But if it works out for you, great!
In summary, you need to perform the following steps in order to interface with exported functions from unmanaged DLLs:
1) Define the equivalent function signature in C# for your function. Note: Sometimes, you won’t get the parameters to the function right the first time and you may need to tweak them to get the working - e.g. char vs. string, uint vs. int, etc.
2) Apply the appropriate parameters to the DllImport attribute.
3) Call the Add-Type cmdlet to compile the code.
4) Hopefully, you’re off and running. If you run into issues, MSDN is your friend.
I hope this helps!
Thanks Matt for the detailed responce. I beleive I understand what you have done in terms of defining the function structure.by MattG at 2013-03-10 06:24:14
I tried your suggested scrpit , However It would not compile… It seems the problem starts with calling with the Add-Type… See bellow
The code I tried is the same as your suggestion , I merely changed the Dllname to MyDll
I do not underatsnd how to debug the code based on the bellow. It seems the problem lies with location of the dll or is it the parameters we defined
Add-Type : c:\Users\Hani Hamad\AppData\Local\Temp\sdr3kj1l.0.cs(6) : Unrecognized escape sequence
c:\Users\Hani Hamad\AppData\Local\Temp\sdr3kj1l.0.cs(5) : {
c:\Users\Hani Hamad\AppData\Local\Temp\sdr3kj1l.0.cs(6) : >>> [DllImport("C:\siudi\siudiUsb_developerkit\src\DasHard2006.dll", CharSet = CharSet.Auto)]
c:\Users\Hani Hamad\AppData\Local\Temp\sdr3kj1l.0.cs(7) : public static extern int DasUsbCommand(uint command, uint param, Char bloc);
At C:\Users\Hani Hamad\Desktop\dmxtest.ps1:12 char:1
+ Add-Type -TypeDefinition $Code
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidData: (c:\Users\Hani H…escape sequence:CompilerError) [Add-Type], Exception
+ FullyQualifiedErrorId : SOURCE_CODE_ERROR,Microsoft.PowerShell.Commands.AddTypeCommand
Add-Type : c:\Users\Hani Hamad\AppData\Local\Temp\sdr3kj1l.0.cs(6) : Unrecognized escape sequence
c:\Users\Hani Hamad\AppData\Local\Temp\sdr3kj1l.0.cs(5) : {
c:\Users\Hani Hamad\AppData\Local\Temp\sdr3kj1l.0.cs(6) : >>> [DllImport("C:\siudi\siudiUsb_developerkit\src\DasHard2006.dll", CharSet = CharSet.Auto)]
c:\Users\Hani Hamad\AppData\Local\Temp\sdr3kj1l.0.cs(7) : public static extern int DasUsbCommand(uint command, uint param, Char bloc);
At C:\Users\Hani Hamad\Desktop\dmxtest.ps1:12 char:1
+ Add-Type -TypeDefinition $Code
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidData: (c:\Users\Hani H…escape sequence:CompilerError) [Add-Type], Exception
+ FullyQualifiedErrorId : SOURCE_CODE_ERROR,Microsoft.PowerShell.Commands.AddTypeCommand
Add-Type : c:\Users\Hani Hamad\AppData\Local\Temp\sdr3kj1l.0.cs(6) : Unrecognized escape sequence
c:\Users\Hani Hamad\AppData\Local\Temp\sdr3kj1l.0.cs(5) : {
c:\Users\Hani Hamad\AppData\Local\Temp\sdr3kj1l.0.cs(6) : >>> [DllImport("C:\siudi\siudiUsb_developerkit\src\DasHard2006.dll", CharSet = CharSet.Auto)]
c:\Users\Hani Hamad\AppData\Local\Temp\sdr3kj1l.0.cs(7) : public static extern int DasUsbCommand(uint command, uint param, Char bloc);
At C:\Users\Hani Hamad\Desktop\dmxtest.ps1:12 char:1
+ Add-Type -TypeDefinition $Code
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidData: (c:\Users\Hani H…escape sequence:CompilerError) [Add-Type], Exception
+ FullyQualifiedErrorId : SOURCE_CODE_ERROR,Microsoft.PowerShell.Commands.AddTypeCommand
Add-Type : c:\Users\Hani Hamad\AppData\Local\Temp\sdr3kj1l.0.cs(6) : Unrecognized escape sequence
c:\Users\Hani Hamad\AppData\Local\Temp\sdr3kj1l.0.cs(5) : {
c:\Users\Hani Hamad\AppData\Local\Temp\sdr3kj1l.0.cs(6) : >>> [DllImport("C:\siudi\siudiUsb_developerkit\src\DasHard2006.dll", CharSet = CharSet.Auto)]
c:\Users\Hani Hamad\AppData\Local\Temp\sdr3kj1l.0.cs(7) : public static extern int DasUsbCommand(uint command, uint param, Char bloc);
At C:\Users\Hani Hamad\Desktop\dmxtest.ps1:12 char:1
+ Add-Type -TypeDefinition $Code
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidData: (c:\Users\Hani H…escape sequence:CompilerError) [Add-Type], Exception
+ FullyQualifiedErrorId : SOURCE_CODE_ERROR,Microsoft.PowerShell.Commands.AddTypeCommand
Add-Type : Cannot add type. There were compilation errors.
At C:\Users\Hani Hamad\Desktop\dmxtest.ps1:12 char:1
+ Add-Type -TypeDefinition $Code
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidData: ([Add-Type], InvalidOperationException
+ FullyQualifiedErrorId : COMPILER_ERRORS,Microsoft.PowerShell.Commands.AddTypeCommand
Unable to find type [MyDll]: make sure that the assembly containing this type is loaded.
At C:\Users\Hani Hamad\Desktop\dmxtest.ps1:16 char:1
+ [MyDll]::DasUsbCommand($DHC_INIT,0,$null)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (MyDll:TypeName) , RuntimeException
+ FullyQualifiedErrorId : TypeNotFound
Unable to find type [MyDll]: make sure that the assembly containing this type is loaded.
At C:\Users\Hani Hamad\Desktop\dmxtest.ps1:17 char:1
+ $interfaceOpen = [MyDll]::DasUsbCommand($DHC_OPEN,0,0)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (MyDll:TypeName) , RuntimeException
+ FullyQualifiedErrorId : TypeNotFound
Thanks again for your help
You need to escape the backslashes in the path to the dll. This should work for you:by Hanman at 2013-04-24 05:11:39$Code = @'
using System;
using System.Runtime.InteropServices;
public class YourDll
{
[DllImport("C:\siudi\siudiUsb_developerkit\src\DasHard2006.dll", CharSet = CharSet.Auto)]
public static extern int DasUsbCommand(uint command, uint param, Char bloc);
}
'@
Add-Type -TypeDefinition $Code
$numberOfInterface = 0
$dmxBlock = New-Object Char(512)
[YourDll]::DasUsbCommand($DHC_INIT,0, $null)
$interfaceOpen = [YourDll]::DasUsbCommand($DHC_OPEN,0,0)
if ($interfaceOpen -gt 0)
{
[YourDll]::DasUsbCommand($DHC_DMXOUT, 512, $dmxBlock)
}
if ($interfaceOpen -gt 0)
{
[YourDll]::DasUsbCommand($DHC_CLOSE,0,0)
[YourDll]::DasUsbCommand($DHC_EXIT,0, $null)
}
I finally got the code to work (80%)by MattG at 2013-04-24 07:46:41
I can see the hardware, read the firmware serial number , open it… But get an error when i try to set the output
The code now is as followsusing System;
using System.Runtime.InteropServices;
public class MyDll
{
[DllImport("C:\siudi\siudiUsb_developerkit5\src\DasHard2006.dll", CharSet = CharSet.Auto)]
public static extern int DasUsbCommand(uint command, uint param, byte bloc);
}
'@
Add-Type -TypeDefinition $Code
$DHC_INIT = 9
$DHC_EXIT = 10
$DHC_OPEN = 1
$DHC_CLOSE = 2
$DHC_DMXOUTOFF = 3
$DHC_DMXOUT = 4
$DHC_DMX2OUT = 13
$DHC_PORTREAD = 5
$DHC_VERSION = 7
$DHC_SERIAL = 14
$DHC_DMXENABLE = 16
$DHC_DMX2ENABLE = 12
$DHE_OK = 1
$DHE_ERROR_COMMAND = -1
$DHE_ERROR_NOTOPEN = -2
$channel_select = [int]
$hardware_ok = [int]
$channel = [int]
$result = [int]
$command = [int]
$dmxBlock = [byte]
$channel = 1
$dmxBlock = 0xff
$interfaceOpen = 0
$numberOfInterface = 0
$ban = [MyDll]::DasUsbCommand($DHC_INIT,0,0)
Write-Host "DLL is version" $ban
$interfaceOpen = [MyDll]::DasUsbCommand($DHC_OPEN,0,0)
Write-Host "Interface Open status is " $interfaceOpen
$san = [MyDll]::DasUsbCommand($DHC_VERSION,0,0)
Write-Host "Serial Number is " $san
$fan = [MyDll]::DasUsbCommand($DHC_SERIAL,0,0)
Write-Host "Firmware Version is " $fan
if ($interfaceOpen -gt 0)
{
$CAN = [MyDll]::DasUsbCommand($DHC_DMXOUTOFF,0,0)
Write-Host "All Output off Status" $CAN
}
if ($interfaceOpen -gt 0)
{
$lan = [MyDll]::DasUsbCommand($DHC_DMXOUT,$channel,$dmxBlock)
Write-Host "Sent to Channel # " $channel "Value" $dmxBlock "Status is " $lan
}
if ($interfaceOpen -gt 0)
{
[MyDll]::DasUsbCommand($DHC_CLOSE,0,0)
[MyDll]::DasUsbCommand($DHC_EXIT,0,0)
}
The output comes as
DLL is version 136
Interface Open status is 1
Serial Number is 108
Firmware Version is 262568
All Output off Status 1
Sent to Channel # 1 Value 255 Status is -1
1
1
The -1 indicates an error…
My guess is that the way we defined the unsigned char bloc is the problem.
The way the DLL is declared in a DEMO app that came with the hardware is
[code2=cpp]#include "_dashard.h"
extern int HardDllCommand(int command, int param, unsigned char *bloc);
extern int ref_open;[/code2]
I appreciate it if you can take a look and maybe spot something wrong
If i can sort that out, I will then add the loops to cycle through the channels and set the output
Thanks
It looks like people treat the bloc parameter as a pointer to an unsigned byte array. Try changing your function declaration to the following:by Hanman at 2013-04-24 23:33:42$Code = @'Then try making the following, slightly modified call:
using System;
using System.Runtime.InteropServices;
public class YourDll
{
[DllImport("C]
public static extern int DasUsbCommand(uint command, uint param, ref Byte bloc);
}
'@$lan = [MyDll]]$dmxBlock)
Thanks a lot for the prompt answer.by Hanman at 2013-04-25 03:00:29
That did not work , Once i call the DLL with [ref] added I get an error.
I looked through the documentation again and bloc is described as a pointer to the DMX block of memory to send or read. so you are correct
block is not used in the the line bellow:$ban = [MyDll]]
Before the last amendment, the above worked, now after the pointer [ref], it does not …
Argument: ‘3’ should be a System.Management.Automation.PSReference. Use [ref].
At D:\Folders\PS\dmxtest final 77 2.ps1:45 char:1
+ $ban = [MyDll]::DasUsbCommand($DHC_INIT,0,0)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (, MethodException
+ FullyQualifiedErrorId : NonRefArgumentToRefParameterMsg
I have a pdf document describing the DLL and I have a sample application that works in C++ and another in VB. The one in VB uses another DLL
I wonder if I can send you an e-mail with these files to take a look. the support online for this Hardware is limited to this PDF file
Thanks
By the way, There is a link online for the Developer Kit with C++ samples
http://www.dmxsoft.com/global/ftp/siudi_usb_developerkit.exe
Thanks