As a part of my project I am learning how to handle the printers using "winspool.drv" and "PRINTUI.DLL,PrintUIEntry" to which I am new. I am using powershell for this project. The problem is that my code is throwing an error when I am trying to get printer Handle with openprinter method
Error: Method invocation failed because [OpenPrinter1.Program1] does not contain a method named 'OpenPrinterHandle'.
Code:
$code = #'
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.IO;
namespace OpenPrinter1
{
public class Program1
{
[DllImport("winspool.drv", EntryPoint = "OpenPrinter", SetLastError =true)]
internal static extern bool OpenPrinter(string pPrinterName, ref IntPtr phPrinter, PRINTER_DEFAULTS pDefault);
[DllImport("winspool.drv", EntryPoint = "ClosePrinter", SetLastError = true)]
internal static extern int ClosePrinter(IntPtr hPrinter);
[StructLayout(LayoutKind.Sequential)]
public class PRINTER_DEFAULTS
{
public string pDatatype;
public IntPtr pDevMode;
public int DesiredAccess;
}
public struct OpenPrinterAccessCodes
{
public const int DELETE = 0x10000; // DELETE - Allowed to delete printers
public const int READ_CONTROL = 0x20000; // READ_CONTROL -
public const int WRITE_DAC = 0x40000; // WRITE_DAC -
public const int WRITE_OWNER = 0x80000; // WRITE_OWNER -
public const int SERVER_ACCESS_ADMINISTER = 0x1;
public const int SERVER_ACCESS_ENUMERATE = 0x2;
public const int PRINTER_ACCESS_ADMINISTER = 0x4;
public const int PRINTER_ACCESS_USE = 0x8;
public const int STANDARD_RIGHTS_REQUIRED = 0xF0000;
public const int PRINTER_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED |PRINTER_ACCESS_ADMINISTER | PRINTER_ACCESS_USE);
public const int SERVER_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED | SERVER_ACCESS_ADMINISTER | SERVER_ACCESS_ENUMERATE);
public const int MAX_PORTNAME_LEN = 64;
public const int MAX_NETWORKNAME_LEN = 49;
public const int MAX_SNMP_COMMUNITY_STR_LEN = 33;
public const int MAX_QUEUENAME_LEN = 33;
public const int MAX_IPADDR_STR_LEN = 16;
public const int ERROR_INSUFFICIENT_BUFFER = 122;
public const int ERROR_INVALID_FLAGS = 1004;
}
public IntPtr OpenPrinterHandle(string printerName)
{
var def = new PRINTER_DEFAULTS { pDatatype = null, pDevMode = IntPtr.Zero, DesiredAccess = OpenPrinterAccessCodes.PRINTER_ALL_ACCESS };
var hPrinter = IntPtr.Zero;
if (!OpenPrinter(printerName, ref hPrinter, def))
{
var lastWin32Error = new Win32Exception(Marshal.GetLastWin32Error());
throw lastWin32Error;
}
return hPrinter;
}
}
}
'#
cls
Add-Type -TypeDefinition $code -Language CSharp
if(!([OpenPrinter1.Program1]:: OpenPrinterHandle("hp LaserJet 1320 PCL 6 (Copy 1)")))
{
throw (New-Object componentmodel.win32Exception )
}
This syntax:
[Namespace.Class]::Method()
denotes invocation of a static method. The OpenPrinterHandle() method in your type definition is an instance method.
To change the behavior, just introduce the static keyword in the method signature:
public static IntPtr OpenPrinterHandle(string printerName)
and then you should be able to do:
[OpenPrinter1.Program1]::OpenPrinterHandle($printername)
Related
I have the following powershell code to dump the process memory from a given process. In this case, cmd.exe.
It opens the given process with PROCESS_ALL_ACCESS and uses VirtualQueryEx to list all the memory regions. For each memory region it finds, it calls ReadProcessMemory and writes the bytes read to a file.
$typeDefinition = #"
using System;
using System.Text;
using System.Runtime.InteropServices;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
public static partial class MemApi
{
[StructLayout(LayoutKind.Sequential)]
public struct MEMORY_BASIC_INFORMATION64
{
public ulong BaseAddress;
public ulong AllocationBase;
public int AllocationProtect;
public int __alignment1;
public ulong RegionSize;
public int State;
public int Protect;
public int Type;
public int __alignment2;
}
[Flags]
public enum ProcessAccessFlags : uint
{
VM_READ = 0x00000010,
PROCESS_ALL_ACCESS = 0x001F0FFF
}
[DllImport("kernel32.dll")]
public static extern uint GetLastError();
[DllImport("kernel32.dll", CharSet=CharSet.Auto)]
public static extern IntPtr OpenProcess(
ProcessAccessFlags dwAccess,
[MarshalAs(UnmanagedType.Bool)]
bool bInheritHandle,
int dwProcId
);
[DllImport("kernel32.dll", CharSet=CharSet.Auto)]
public static extern int VirtualQueryEx(
IntPtr hProc,
IntPtr lpAddr,
out MEMORY_BASIC_INFORMATION64 lpBuf,
int dwLen
);
public static List<MEMORY_BASIC_INFORMATION64> ListMemoryRegions(
IntPtr hProc
)
{
long maxAddr = 0x00007FFFFFFFFFFF;
long addr = 0;
List<MEMORY_BASIC_INFORMATION64> regions = new List<MEMORY_BASIC_INFORMATION64>();
do
{
MEMORY_BASIC_INFORMATION64 m;
int result = VirtualQueryEx(hProc, (IntPtr)addr, out m, (int)Marshal.SizeOf(typeof(MEMORY_BASIC_INFORMATION64)));
if (addr == (long)m.BaseAddress + (long)m.RegionSize)
break;
addr = (long)m.BaseAddress + (long)m.RegionSize;
regions.Add(m);
} while (addr <= maxAddr);
return regions;
}
[DllImport("kernel32.dll", CharSet=CharSet.Auto, SetLastError=true)]
public static extern Boolean ReadProcessMemory(
IntPtr hProc,
IntPtr lpBaseAddr,
byte[] lpBuf,
UInt32 nSize,
ref UInt32 lpNBytes
);
}
"#
Add-Type -TypeDefinition $typeDefinition -Language CSharp
$cmd = Get-Process -Name cmd
$handle = [MemApi]::OpenProcess(0x1F0FFF, $false, $cmd.Id)
$regions = [MemApi]::ListMemoryRegions($handle)
$fileStream = [System.IO.File]::OpenWrite("$env:TEMP\cmd.DMP")
Write-Host "$($regions.Count) memory segments have been found"
for ($i = 0; $i -lt $regions.Count; $i++)
{
Write-Host "Exporting memory region $("{0:d4}/{1:d4}" -f $i, ($regions.Count + 1)) ($("0x{0:X16} - 0x{1:X16}" -f $regions[$i].BaseAddress, ($regions[$i].BaseAddress + $regions[$i].RegionSize)))..."
try
{
$read = 0
$buff = New-Object byte[] $regions[$i].RegionSize
if ([MemApi]::ReadProcessMemory($handle, [System.IntPtr]::new($regions[$i].BaseAddress), $buff, $buff.Length, [ref]$read) -eq $true)
{
$fileStream.Write($buff, 0, $buff.Length)
}
} catch { } finally { }
}
$fileStream.Close()
I would like to avoid using dbghelp.dll to do this, but is there a way I can create a MiniDump file out of this raw memory? Would I need to change the code at all or is there an external tool that can convert this?
I've tried to take a look into the MiniDumpWriteDump function to see if I can replicate it at all but I've had no luck.
I've also tried volatility's raw2dmp function, but this has not worked unfortunately.
Apologies if this is completely on the wrong tracks!
Any help would be much appreciated - Merry Christmas!
I'm trying to pull folder icons for a listview in a winform. I'm using [Drawing.Icon]::ExtractAssociatedIcon for file icons, but it doesn't work on folders.
I found this question here on stack which said to use SHGetStockIconInfo, but I can't wrap my head around how to load this function and use it in Powershell (I have no C programming experience). I managed to pull this from the linked question, but I'm stuck:
Add-Type -NameSpace WinAPI -Name DefaultIcons -MemberDefinition #'
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct SHSTOCKICONINFO {
public uint cbSize;
public IntPtr hIcon;
public int iSysIconIndex;
public int iIcon;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
public string szPath;
}
[DllImport("shell32.dll")]
public static extern int SHGetStockIconInfo(uint siid, uint uFlags, ref SHSTOCKICONINFO psii);
[DllImport("user32.dll")]
public static extern bool DestroyIcon(IntPtr handle);
private const uint SHSIID_FOLDER = 0x3;
private const uint SHGSI_ICON = 0x100;
private const uint SHGSI_LARGEICON = 0x0;
private const uint SHGSI_SMALLICON = 0x1;
'#
This runs without error, but that's as far as I can get and I don't fully understand what's going on.
I know I need to call the function SHGetStockIconInfo with three parameters:
uint to identify what icon I want
uint flag for the size of icon I want
a reference to a SHSTOCKICONINFO structure
The question I got all this from includes a GetStockIcon function definition, but I keep getting errors trying to include it saying The type or namespace name 'Icon' could not be found (are you missing a using directive or an assembly reference?)
With a few adjustments I got the code from that C# question to work under both PowerShell 5.1 and 7.2.6.
$refAsm = if( $PSVersionTable.PSVersion.Major -le 5 ) {'System.Drawing'} else {'System.Drawing.Common'}
Add-Type -ReferencedAssemblies $refAsm -TypeDefinition #'
using System;
using System.Runtime.InteropServices;
using System.Drawing;
public static class DefaultIcons
{
public static Icon GetStockIcon(uint type, uint size)
{
var info = new SHSTOCKICONINFO();
info.cbSize = (uint)Marshal.SizeOf(info);
SHGetStockIconInfo(type, SHGSI_ICON | size, ref info);
var icon = (Icon)Icon.FromHandle(info.hIcon).Clone(); // Get a copy that does not use the original handle
DestroyIcon(info.hIcon); // Clean up native icon to prevent resource leak
return icon;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct SHSTOCKICONINFO
{
public uint cbSize;
public IntPtr hIcon;
public int iSysIconIndex;
public int iIcon;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
public string szPath;
}
[DllImport("shell32.dll")]
public static extern int SHGetStockIconInfo(uint siid, uint uFlags, ref SHSTOCKICONINFO psii);
[DllImport("user32.dll")]
public static extern bool DestroyIcon(IntPtr handle);
public const uint SHSIID_FOLDER = 0x3;
public const uint SHGSI_ICON = 0x100;
public const uint SHGSI_LARGEICON = 0x0;
public const uint SHGSI_SMALLICON = 0x1;
}
'#
Use it like this:
$folderIconLarge = [DefaultIcons]::GetStockIcon( [DefaultIcons]::SHSIID_FOLDER, [DefaultIcons]::SHGSI_LARGEICON )
$folderIconSmall = [DefaultIcons]::GetStockIcon( [DefaultIcons]::SHSIID_FOLDER, [DefaultIcons]::SHGSI_SMALLICON )
I'm interested in displaying Depth data in Unity with Kinect for Windows. Unfortunately, I have Kinect v1.8 and I know this has been easily done with Kinect V2 (Kinect Fusion).
I found this example: https://github.com/rickbarraza/UnityKinectDepthExplorer
I installed all the necessary components and now getting DLLNOTFOUNDEXCEPTION:
Failed to load 'Assets/Plugins/x86_64/KinectUnityAddin.dll'
Concerning all the posts and forums I've been reading so far, It's because I'm using SDK 1.8 (instead of SDK 2.0).
Is there any way how I can use this example with Kinect v1.8? I tried to contact the author as well but he haven't responded back.
Thanks a lot!
I had the same Problem in an University Project maby its not to late for you.
This is an Kinect v1.8 Wrapper i made to read the kinect depth image only. I used the Kinect with MS-SDK from the Unity-Assetstore as an orientation, you dont have to download it. All you need is this Code.
Use The Init() Method to start and the GetDepthArray() Function to get the Deapth Frame.
hope it works for you !
You have to install the Kinect 1.8 sdk or have at least the Kinect10.dll from the 1.8 sdk in your Windows/System32 folder
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Runtime.InteropServices;
using System;
using System.Runtime.CompilerServices;
public class OwnKinectWrapper : MonoBehaviour {
DepthBuffer db;
#region Nui Variables/Structs/Intefraces
IntPtr streamReferenz;
public struct NuiImageViewArea
{
public int eDigitalZoom;
public int lCenterX;
public int lCenterY;
}
public struct NuiSurfaceDesc
{
uint width;
uint height;
}
public struct DepthBuffer
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 640 * 480, ArraySubType = UnmanagedType.U2)]
public ushort[] pixels;
}
public struct NuiLockedRect
{
public int pitch;
public int size;
public IntPtr pBits;
}
public struct NuiImageFrame
{
public Int64 liTimeStamp;
public uint dwFrameNumber;
public int eImageType;
public int eResolution;
public IntPtr pFrameTexture;
public uint dwFrameFlags_NotUsed;
public NuiImageViewArea ViewArea_NotUsed;
}
[Guid("13ea17f5-ff2e-4670-9ee5-1297a6e880d1")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[ComImport()]
public interface INuiFrameTexture
{
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
[PreserveSig]
int BufferLen();
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
[PreserveSig]
int Pitch();
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
[PreserveSig]
int LockRect(uint Level, ref NuiLockedRect pLockedRect, IntPtr pRect, uint Flags);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
[PreserveSig]
int GetLevelDesc(uint Level, ref NuiSurfaceDesc pDesc);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
[PreserveSig]
int UnlockRect(uint Level);
}
#endregion
// Use this for initialization
public int Init() {
int init = 0;
try {
init = NuiInitialize(0x00000020);
Debug.Log("init : " + init);
streamReferenz = IntPtr.Zero;
NuiImageStreamOpen(4, 2, 0, 2, IntPtr.Zero, ref streamReferenz);
}
catch (DllNotFoundException e)
{
string message = "Please check the Kinect SDK installation.";
Debug.LogError(message);
Debug.LogError(e.ToString());
return -1;
}
catch (Exception e)
{
Debug.LogError(e.ToString());
return -1;
}
return init;
}
// Update is called once per frame
void Update()
{
IntPtr imageStreamFrameReferenz = IntPtr.Zero;
int test = NuiImageStreamGetNextFrame(streamReferenz, 0, ref imageStreamFrameReferenz);
if (test == 0) {
NuiImageFrame imageFrame = (NuiImageFrame)Marshal.PtrToStructure(imageStreamFrameReferenz, typeof(NuiImageFrame));
INuiFrameTexture frameTexture = (INuiFrameTexture)Marshal.GetObjectForIUnknown(imageFrame.pFrameTexture);
NuiLockedRect lockedRectPtr = new NuiLockedRect();
IntPtr r = IntPtr.Zero;
frameTexture.LockRect(0, ref lockedRectPtr, r, 0);
db = (DepthBuffer)Marshal.PtrToStructure(lockedRectPtr.pBits, typeof(DepthBuffer));
frameTexture.UnlockRect(0);
NuiImageStreamReleaseFrame(streamReferenz, imageStreamFrameReferenz);
}
}
void OnDisable() {
NuiShutdown();
}
public ushort[] GetDepthArray(){
return db.pixels;
}
[DllImportAttribute(#"Kinect10.dll",EntryPoint="NuiInitialize")]
public static extern int NuiInitialize (uint dwFlags);
[DllImportAttribute(#"Kinect10.dll", EntryPoint = "NuiImageStreamOpen")]
public static extern int NuiImageStreamOpen(int enumImageType,int enumImgageResolution, uint image_Flags, uint frameBufferLimit, IntPtr nextFrameEvent, ref IntPtr streamHandle );
[DllImportAttribute(#"Kinect10.dll", EntryPoint = "NuiImageStreamGetNextFrame")]
public static extern int NuiImageStreamGetNextFrame(IntPtr streamReferenz, uint dwMillisecondsToWait, ref IntPtr ImageFrameReferenz);
[DllImportAttribute(#"Kinect10.dll", EntryPoint = "NuiImageStreamReleaseFrame")]
public static extern int NuiImageStreamReleaseFrame(IntPtr phStreamHandle, IntPtr ppcImageFrame);
[DllImportAttribute(#"Kinect10.dll",EntryPoint="NuiDepthPixelToDepth")]
public static extern ushort NuiDepthPixelToDepth (ushort depthPixel);
[DllImportAttribute(#"Kinect10.dll", EntryPoint = "NuiShutdown")]
public static extern void NuiShutdown();
}
if something is not working or you need help feel free to write some lines
hey how can i access this list of int and strings from another
script?
// Slot One Data
[Serializable]
public class SlotOneStats
{
public string nameOne;
public int roleOne;
public int strengthOne;
public int meleeOne;
public int shootingOne;
public int huntingOne;
public int cookingOne;
public int craftingOne;
public int buildingOne;
public int engineeringOne;
}
i tried changing 'public' to 'static' or 'public static' but whenever i changed to static
it will say
Static member `Main.SlotOneStats.ALLTHESTATICVARIABLEGOESHERE' cannot be accessed with an
instance reference, qualify it with a type name instead
BinaryFormatter bfWriter = new BinaryFormatter();
FileStream file = File.Create(Application.persistentDataPath + "/dataStats" + onSlot + ".fgsv");
if(onSlot == 1)
{
SlotOneStats slotoneStats = new SlotOneStats();
slotoneStats.nameOne = name;
slotoneStats.roleOne = role;
slotoneStats.strengthOne = strength;
slotoneStats.meleeOne = melee;
slotoneStats.shootingOne = shooting;
slotoneStats.huntingOne = hunting;
slotoneStats.cookingOne = cooking;
slotoneStats.craftingOne = crafting;
slotoneStats.buildingOne = building;
slotoneStats.engineeringOne = engineering;
bfWriter.Serialize(file, slotoneStats);
}
I would suggest adding a public instance of the class to the first script:
public class SlotOneStats
{
public string nameOne;
public int roleOne;
public int strengthOne;
public int meleeOne;
public int shootingOne;
public int huntingOne;
public int cookingOne;
public int craftingOne;
public int buildingOne;
public int engineeringOne;
}
public SlotOneStats SOS;
Now just access the public varaible SOS and it should work:
GameObject example = GameObject.Find("Object_with_script").GetComponent<Script_with_class>.SOS;
// do stuff with example
I'm trying to call CreateProcess from PowerShell. The API call indicates that it succeeded, but no new application or process is visible in Task Manager.
Add-Type -TypeDefinition #"
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
[StructLayout(LayoutKind.Sequential)]
public struct PROCESS_INFORMATION
{
public IntPtr hProcess;
public IntPtr hThread;
public uint dwProcessId;
public uint dwThreadId;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct STARTUPINFO
{
public uint cb;
public string lpReserved;
public string lpDesktop;
public string lpTitle;
public uint dwX;
public uint dwY;
public uint dwXSize;
public uint dwYSize;
public uint dwXCountChars;
public uint dwYCountChars;
public uint dwFillAttribute;
public STARTF dwFlags;
public ShowWindow wShowWindow;
public short cbReserved2;
public IntPtr lpReserved2;
public IntPtr hStdInput;
public IntPtr hStdOutput;
public IntPtr hStdError;
}
[StructLayout(LayoutKind.Sequential)]
public struct SECURITY_ATTRIBUTES
{
public int length;
public IntPtr lpSecurityDescriptor;
public bool bInheritHandle;
}
[Flags]
public enum CreationFlags : int
{
NONE = 0,
DEBUG_PROCESS = 0x00000001,
DEBUG_ONLY_THIS_PROCESS = 0x00000002,
CREATE_SUSPENDED = 0x00000004,
DETACHED_PROCESS = 0x00000008,
CREATE_NEW_CONSOLE = 0x00000010,
CREATE_NEW_PROCESS_GROUP = 0x00000200,
CREATE_UNICODE_ENVIRONMENT = 0x00000400,
CREATE_SEPARATE_WOW_VDM = 0x00000800,
CREATE_SHARED_WOW_VDM = 0x00001000,
CREATE_PROTECTED_PROCESS = 0x00040000,
EXTENDED_STARTUPINFO_PRESENT = 0x00080000,
CREATE_BREAKAWAY_FROM_JOB = 0x01000000,
CREATE_PRESERVE_CODE_AUTHZ_LEVEL = 0x02000000,
CREATE_DEFAULT_ERROR_MODE = 0x04000000,
CREATE_NO_WINDOW = 0x08000000,
}
[Flags]
public enum STARTF : uint
{
STARTF_USESHOWWINDOW = 0x00000001,
STARTF_USESIZE = 0x00000002,
STARTF_USEPOSITION = 0x00000004,
STARTF_USECOUNTCHARS = 0x00000008,
STARTF_USEFILLATTRIBUTE = 0x00000010,
STARTF_RUNFULLSCREEN = 0x00000020, // ignored for non-x86 platforms
STARTF_FORCEONFEEDBACK = 0x00000040,
STARTF_FORCEOFFFEEDBACK = 0x00000080,
STARTF_USESTDHANDLES = 0x00000100,
}
public enum ShowWindow : short
{
SW_HIDE = 0,
SW_SHOWNORMAL = 1,
SW_NORMAL = 1,
SW_SHOWMINIMIZED = 2,
SW_SHOWMAXIMIZED = 3,
SW_MAXIMIZE = 3,
SW_SHOWNOACTIVATE = 4,
SW_SHOW = 5,
SW_MINIMIZE = 6,
SW_SHOWMINNOACTIVE = 7,
SW_SHOWNA = 8,
SW_RESTORE = 9,
SW_SHOWDEFAULT = 10,
SW_FORCEMINIMIZE = 11,
SW_MAX = 11
}
public static class Kernel32
{
[DllImport("kernel32.dll", SetLastError=true)]
public static extern bool CreateProcess(
string lpApplicationName,
string lpCommandLine,
ref SECURITY_ATTRIBUTES lpProcessAttributes,
ref SECURITY_ATTRIBUTES lpThreadAttributes,
bool bInheritHandles,
CreationFlags dwCreationFlags,
IntPtr lpEnvironment,
string lpCurrentDirectory,
ref STARTUPINFO lpStartupInfo,
out PROCESS_INFORMATION lpProcessInformation);
}
"#
$si = New-Object STARTUPINFO
$pi = New-Object PROCESS_INFORMATION
$si.cb = [System.Runtime.InteropServices.Marshal]::SizeOf($si)
$si.wShowWindow = [ShowWindow]::SW_SHOW
$pSec = New-Object SECURITY_ATTRIBUTES
$tSec = New-Object SECURITY_ATTRIBUTES
$pSec.Length = [System.Runtime.InteropServices.Marshal]::SizeOf($pSec)
$tSec.Length = [System.Runtime.InteropServices.Marshal]::SizeOf($tSec)
[Kernel32]::CreateProcess("c:\windows\notepad.exe", $null, [ref] $pSec, [ref] $tSec, $false, [CreationFlags]::NONE, [IntPtr]::Zero, $null, [ref] $si, [ref] $pi)
[System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
$pi
Try using a real CurrentDirectory instead of $null:
[Kernel32]::CreateProcess("c:\windows\notepad.exe", $null, [ref] $pSec, [ref] $tSec, $false, [CreationFlags]::NONE, [IntPtr]::Zero, "c:", [ref] $si, [ref] $pi)