Rank: Administration
Groups: Translators, Members, Administrators Joined: 1/11/2018(UTC) Posts: 1,294  Location: Tampa, FL Thanks: 28 times Was thanked: 404 time(s) in 349 post(s)
|
Beginning in 0.4.0.6 you can now dynamically define and invoke your own types and native DLL calls from script. Below are some examples which cover the most common scenarios. Check the Extensions and Native and Dynamic sections in Script Help for more information. Code to define types and PInvokes:see Action code below to call these and how to check if the type already existsCode:if(!NativeModules.Types)
{
var Int32T = host.typeOf(clr.System.Int32);
var IntPtrT = host.typeOf(clr.System.IntPtr);
var BooleanT = host.typeOf(clr.System.Boolean);
var umt = clr.System.Runtime.InteropServices.UnmanagedType;
//------------------------------------------------------------------------------------------------
// Define and create (can only add nested types) the type which will contain the structs
//------------------------------------------------------------------------------------------------
var typesTB = sp.NativeModule().CreateType("Types", "Class,Public,SequentialLayout,Serializable");
typesTB.DefineNestedStruct("TestUnmanagedType",
"X,Y",
[Int32T,Int32T],
[umt.I4,umt.I4]
).Create();
typesTB.DefineNestedStruct("POINT",
"X,Y",
[Int32T,Int32T]).Create();
typesTB.DefineNestedStruct("RECT",
"Left,Top,Right,Bottom",
[Int32T,Int32T,Int32T,Int32T]).Create();
var POINTT = host.typeOf(NativeModules.Types.POINT);
var RECTT = host.typeOf(NativeModules.Types.RECT);
typesTB.DefineNestedStruct("WINDOWPLACEMENT",
"length,flags,showCmd,ptMinPosition,ptMaxPosition,rcNormalPosition",
[Int32T,Int32T,Int32T,POINTT,POINTT,RECTT]).Create();
typesTB.DefineNestedEnum("NestedEnum",
"Low,High",
[0,1]).Create();
//-----------------------------------------------------------------------------------------------
// Define the type which will contain the PInvokes
// Type can still be modified until .Create() is called
//-----------------------------------------------------------------------------------------------
var user32TB = sp.NativeModule().DefineType("User32", "Class,Public,SequentialLayout,Serializable");
var WINDOWPLACEMENT_refT = host.typeOf(NativeModules.Types.WINDOWPLACEMENT).MakeByRefType();
user32TB.DefinePInvokeMethod("GetWindowPlacement",
"user32.dll",
[IntPtrT,WINDOWPLACEMENT_refT],
BooleanT,
"PreserveSig");
user32TB.DefinePInvokeMethod("EnumWindows",
"user32.dll",
[IntPtrT,IntPtrT],
BooleanT,
"PreserveSig");
//--------------------------------------------------------------------------------------------
// Define other PInvokes here before calling user32TB.Create()
//--------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------------
// Creates the type (which cannot be changed after) and refreshes the
// NativeModules assembly in the script engine
//------------------------------------------------------------------------------------------------
user32TB.Create();
//------------------------------------------------------------------------------------------------
// Creates an enum at the top level of NativeModules, make sure it doesn't have
// same name as another type
//------------------------------------------------------------------------------------------------
sp.NativeModule().DefineEnum("TestEnum",
"Low,High",
[0,1]).Create();
}
//------------------------------------------------------------------------------------------------
// Create a custom type and method at the top level of NativeModules, make sure it
// doesn't have same name as another type
//------------------------------------------------------------------------------------------------
if(!NativeModules.MyType)
{
var StringT = host.typeOf(clr.System.String);
var emit = clr.System.Reflection.Emit;
myTypeTB = sp.NativeModule().DefineType("MyType", "Class,Public,SequentialLayout,Serializable");
var myMethod = myTypeTB.NewMethod("MyMethod",
[StringT],
StringT,
"Public",
"Standard"
);
//Additional code necessary to build method, below is a simple example
var myMethodIL = myMethod.GetILGenerator();
myMethodIL.Emit(emit.OpCodes.Ldstr, "Hi! ");
myMethodIL.Emit(emit.OpCodes.Ldarg_1);
var conCatParamTypes = new List(clr.System.Type);
conCatParamTypes.Add(StringT);
conCatParamTypes.Add(StringT);
var infoMethod = StringT.GetMethod("Concat", conCatParamTypes.ToArray());
myMethodIL.Emit(emit.OpCodes.Call, infoMethod);
myMethodIL.Emit(emit.OpCodes.Ret);
// Create type and refresh native modules
myTypeTB.Create();
}
Example Action script after defining the types above:Code:if(!NativeModules.Types || !NativeModules.User32)
{
sp.MessageBox("No API types defined", "No Types");
}
else
{
sp.MessageBox(NativeModules.Types.NestedEnum.High, "NativeModules.Types.NestedEnum.High");
sp.MessageBox(NativeModules.TestEnum.Low, "NativeModules.TestEnum.Low");
var wndP = host.newVar(NativeModules.Types.WINDOWPLACEMENT)
var res = NativeModules.User32.GetWindowPlacement(sp.ForegroundWindow().HWnd, wndP.ref);
sp.MessageBox("res: " + res
+ "\nwndP.rcNormalPosition.Top: " + wndP.rcNormalPosition.Top
+ "\nwndP.rcNormalPosition.Left: " + wndP.rcNormalPosition.Left
+ "\nwndP.showCmd: " + wndP.showCmd
, "Window Placement");
// Create the EnumWindows callback
function EnumWindowsProc(hWnd, lParam)
{
// Builds a string of all windows, put on clipboard after EnumWindows call
let currentStr = sp.GetStoredString("enumWindows");
currentStr += `Handle: ${hWnd.ToInt64()}\n`;
currentStr += `\t Text: ${sp.WindowFromHandle(hWnd).Text}\n`;
currentStr += `\t lParam: ${lParam.ToInt32()}\n`;
sp.StoreString("enumWindows", currentStr);
return true;
}
//Clear string for subsequent calls
sp.StoreString("enumWindows", "");
var BooleanT = host.typeOf(clr.System.Boolean);
var IntPtrT = host.typeOf(clr.System.IntPtr);
// Creates a static class, method, and delegate for script function,
// returns IntPtr of delegate
// functionName, parameterTypes[], returnType (null for void)
// After the first call, it won't create again, can be referenced via
// var delPtr = NativeDelegates.EnumWindowsProc_C.GetPointer();
// But you can use the same code as below, it will just return the already created pointer
var delPtr = sp.NativeDelegate("EnumWindowsProc", [IntPtrT, IntPtrT], BooleanT);
//Value passed to EnumWindowsProc, can be used to signal type of action to perform
var lParam = new IntPtr(123);
NativeModules.User32.EnumWindows(delPtr, lParam);
//Copy results of EnumWindows string to clipboard
clip.SetText(sp.GetStoredString("enumWindows"));
sp.MessageBox("EnumWindows Complete - Check Clipboard", "Done");
}
if(!NativeModules.MyType)
{
sp.MessageBox("MyType is not defined", "MyType Missing");
}
else
{
var newType = new NativeModules.MyType();
var result = newType.MyMethod("Test");
sp.MessageBox(`Result: ${result}`, "Success!")
}
Edited by user Thursday, December 17, 2020 9:40:42 PM(UTC)
| Reason: Updated scripts for better handling and demo NewMethod, updated setting of EnumWindowsProc function
|