This question already has an answer here:
Using WriteConsoleOutput to write Unicode with c#
(1 answer)
Closed 2 years ago.
Having looked at this question and modifying the code to print characters like '☺', '☻' or '█', I can't see how to get these characters to actually draw properly with WriteConsoleOutput. (There is no problem when using a stream or Console.Write but I can't individually control the character colour with these solutions so they're unsuitable.)
It seems there was a solution here for C++ but the "L" macro they talk about down the bottom does not apply to C#.
Finally, having checked the suggestions here, I can't see anything wrong with the code I ended up with:
class Program
{
[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
static extern SafeFileHandle CreateFile(
string fileName,
[MarshalAs(UnmanagedType.U4)] uint fileAccess,
[MarshalAs(UnmanagedType.U4)] uint fileShare,
IntPtr securityAttributes,
[MarshalAs(UnmanagedType.U4)] FileMode creationDisposition,
[MarshalAs(UnmanagedType.U4)] int flags,
IntPtr template
);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool WriteConsoleOutputW(
SafeFileHandle hConsoleOutput,
CharInfo[] lpBuffer,
Coord dwBufferSize,
Coord dwBufferCoord,
ref SmallRect lpWriteRegion
);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool SetConsoleOutputCP(uint wCodePageID);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool SetConsoleCP(uint wCodePageID);
[StructLayout(LayoutKind.Sequential)]
public struct Coord
{
public short X;
public short Y;
public Coord(short X, short Y)
{
this.X = X;
this.Y = Y;
}
};
[StructLayout(LayoutKind.Explicit)]
public struct CharUnion
{
[FieldOffset(0)] public char UnicodeChar;
[FieldOffset(0)] public byte AsciiChar;
}
[StructLayout(LayoutKind.Explicit)]
public struct CharInfo
{
[FieldOffset(0)] public CharUnion Char;
[FieldOffset(2)] public short Attributes;
}
[StructLayout(LayoutKind.Sequential)]
public struct SmallRect
{
public short Left;
public short Top;
public short Right;
public short Bottom;
}
static void Main(string[] args)
{
//SetConsoleOutputCP(65001);
//SetConsoleCP(65001);
SafeFileHandle fileHandle = CreateFile("CONOUT$", 0x40000000, 2, IntPtr.Zero, FileMode.Open, 0, IntPtr.Zero);
Console.TreatControlCAsInput = true;
//Console.OutputEncoding = Encoding.UTF8;
Console.OutputEncoding = System.Text.Encoding.Unicode;
Console.CursorVisible = false;
short screenWidth = 40;
short screenHeight = 20;
Console.SetWindowSize(screenWidth + 1, screenHeight + 1);
Console.SetBufferSize(screenWidth + 1, screenHeight + 1);
bool running = true;
while (running)
{
CharInfo[] buf = new CharInfo[screenWidth * screenHeight];
SmallRect rect = new SmallRect() { Left = 0, Top = 0, Right = screenWidth, Bottom = screenHeight };
for (int i = 0; i < buf.Length; ++i)
{
buf[i].Attributes = 6;
buf[i].Char.UnicodeChar = '☺';
}
bool b = WriteConsoleOutputW(
fileHandle,
buf,
new Coord() { X = screenWidth, Y = screenHeight },
new Coord() { X = 0, Y = 0 },
ref rect
);
Console.SetCursorPosition(0, 0);
}
}
}
I seem to have ruled out all combinations of CharSet, A/W DLLImport suffixes, code pages, Console properties & source-file encoding.
(Surely it can't be impossible to fast-print coloured smiley-face characters to a C# console. Somebody tell me I've missed something silly here; I've spent about 2 hours Googling & trying to emulate something Castle Adventure managed in 1984 with ease.)
How can I get the aforementioned '☺' to print anything other than a '?' or a ':'?
This seems to be a duplicate of Using WriteConsoleOutput to write Unicode with c#
The solution to that was to add the CharSet = CharSet.Unicode attribute to both the CharInfo and CharUnion structs.
Related
I'm trying to learn a few things, but I'm kinda stuck and I don't know where to go from here. I'm either blind or just confused.
I've been looking at some scripts from here: Answers.Unity
Right now, I got the background transparency working on my main screen, but I'm wondering what I should do to make this happen on my second monitor too. Or third, if I had one. As of right now the other screens turn black. This is the code:
[SerializeField]
private Material m_Material;
[SerializeField]
private Camera mainCamera;
private bool clickThrough = true;
private bool prevClickThrough = true;
private struct MARGINS
{
public int cxLeftWidth;
public int cxRightWidth;
public int cyTopHeight;
public int cyBottomHeight;
}
[DllImport("user32.dll")]
private static extern IntPtr GetActiveWindow();
[DllImport("user32.dll")]
private static extern int SetWindowLong(IntPtr hWnd, int nIndex, uint dwNewLong);
[DllImport("user32.dll")]
static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);
[DllImport("user32.dll", EntryPoint = "SetLayeredWindowAttributes")]
static extern int SetLayeredWindowAttributes(IntPtr hwnd, int crKey, byte bAlpha, int dwFlags);
[DllImport("user32.dll", EntryPoint = "SetWindowPos")]
private static extern int SetWindowPos(IntPtr hwnd, int hwndInsertAfter, int x, int y, int cx, int cy, int uFlags);
[DllImport("Dwmapi.dll")]
private static extern uint DwmExtendFrameIntoClientArea(IntPtr hWnd, ref MARGINS margins);
const int GWL_STYLE = -16;
const uint WS_POPUP = 0x80000000;
const uint WS_VISIBLE = 0x10000000;
const int HWND_TOPMOST = -1;
int fWidth;
int fHeight;
IntPtr hwnd;
MARGINS margins;
public bool OverUI()
{ //Use sparingly
//Set up the new Pointer Event
PointerEventData m_PointerEventData = new PointerEventData(EventSystem.current);
m_PointerEventData.position = Input.mousePosition;
List<RaycastResult> results = new List<RaycastResult>();
EventSystem.current.RaycastAll(m_PointerEventData, results);
if (results.Count > 0) return true;
return false;
}
void Start()
{
fWidth = Screen.width;
fHeight = Screen.height;
margins = new MARGINS() { cxLeftWidth = -1 };
hwnd = GetActiveWindow();
SetWindowLong(hwnd, GWL_STYLE, WS_POPUP | WS_VISIBLE);
SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, fWidth, fHeight, 32 | 64); //SWP_FRAMECHANGED = 0x0020 (32); //SWP_SHOWWINDOW = 0x0040 (64)
DwmExtendFrameIntoClientArea(hwnd, ref margins);
Application.runInBackground = true;
}
void Update()
{
// If our mouse is overlapping an object
RaycastHit hit = new RaycastHit();
clickThrough = !Physics.Raycast(mainCamera.ScreenPointToRay(Input.mousePosition).origin,
mainCamera.ScreenPointToRay(Input.mousePosition).direction, out hit, 100,
Physics.DefaultRaycastLayers) && !OverUI();
if (clickThrough != prevClickThrough)
{
if (clickThrough)
{
SetWindowLong(hwnd, GWL_STYLE, WS_POPUP | WS_VISIBLE);
SetWindowLong (hwnd, -20, (uint)524288 | (uint)32);//GWL_EXSTYLE=-20; WS_EX_LAYERED=524288=&h80000, WS_EX_TRANSPARENT=32=0x00000020L
SetLayeredWindowAttributes (hwnd, 0, 255, 2);// Transparency=51=20%, LWA_ALPHA=2
SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, fWidth, fHeight, 32 | 64); //SWP_FRAMECHANGED = 0x0020 (32); //SWP_SHOWWINDOW = 0x0040 (64)
}
else
{
SetWindowLong (hwnd, -20, ~(((uint)524288) | ((uint)32)));//GWL_EXSTYLE=-20; WS_EX_LAYERED=524288=&h80000, WS_EX_TRANSPARENT=32=0x00000020L
SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, fWidth, fHeight, 32 | 64); //SWP_FRAMECHANGED = 0x0020 (32); //SWP_SHOWWINDOW = 0x0040 (64)
}
prevClickThrough = clickThrough;
}
}
void OnRenderImage(RenderTexture from, RenderTexture to)
{
Graphics.Blit(from, to, m_Material);
}
Could anyone guide me a little bit so that I can figure this out?
Edit: I've figured out a little bit.. I think.
When Unity opens, (with multiple displays), it creates two windows in the task bar. I'm guessing I need to find that other window, set it as active and then run something similar to this code again. But I'm guessing I would need to fix the pos and margins before doing so.
It's beyond my understanding of WinApi right now, but I hope someone knows a bit more about this than me.
My C# calls a C++DLL in order to obtain data from a device. Data are returned through a callback function which has a window handle as input and one integer and two structs as by ref input values.
When the callback is triggered, the DLL is supposed to return 5 records, i.e. to be triggered 5 times. The first record arrives with all proper values but then the app crashes (0xC0000005: Access violation reading location 0x00000000), so my guess is that it crashes right before sending the second set of data.
I don’t have access to the source code of the DLL but I have access to the C++ app that demonstrates its usage.
This is how I declare the delegate and import the function that contains the callback as a member:
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void onGetParaminfoHandler( IntPtr handle, ref int hIndex, ref PATINFO pi, ref PARAMINFO pri);
private static onGetParaminfoHandler ogp; //--declaration reference of the callback to be used
[DllImport("DataTraffic.dll", SetLastError = true, CallingConvention = CallingConvention.Cdecl)]
private static extern void StartUpLoad(IntPtr handle, onGetParaminfoHandler myCallback);
Here’s the declaration of the two structs, PATINFO and PARAMINFO:
[StructLayout(LayoutKind.Sequential)]
public struct PATINFO
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
string szDeviceInfo;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
string szUserName;//name
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
string szTime;
[MarshalAs(UnmanagedType.U4)]
uint nID;
[MarshalAs(UnmanagedType.U4)]
uint nGender;//Sex 1 = male 0: Female
[MarshalAs(UnmanagedType.U4)]
uint nStandard;//Standard 1:ers 2:knudson 3:usa 4: Other
[MarshalAs(UnmanagedType.U4)]
uint nAge;//Age
[MarshalAs(UnmanagedType.U4)]
uint nHeight;//Height cm
[MarshalAs(UnmanagedType.U4)]
uint nWeight;//weight kg
[MarshalAs(UnmanagedType.Bool)]
bool BBDT;//whether relaxing True=Diastolic
[MarshalAs(UnmanagedType.Bool)]
bool bSmoker;//Smoking true= Smoking
};
[StructLayout(LayoutKind.Sequential)]
public struct PARAMINFO
{
//[MarshalAs(UnmanagedType.R4)]
float fffvc;//Maximum force capacity
//[MarshalAs(UnmanagedType.R4)]
float fFEV1;//a second amount
//[MarshalAs(UnmanagedType.R4)]
float fPEF;//Peak flow rate
//[MarshalAs(UnmanagedType.R4)]
float fFEV1Per;//FEV1/FVC
//[MarshalAs(UnmanagedType.R4)]
float fFEF25;//25% capacity
//[MarshalAs(UnmanagedType.R4)]
float fFEF750;//50% capacity
//[MarshalAs(UnmanagedType.R4)]
float fFEF75;//75% capacity
//[MarshalAs(UnmanagedType.R4)]
float fFEF2575;//25-75% capacity
//[MarshalAs(UnmanagedType.R4)]
float fFET;//exhalation Time
//[MarshalAs(UnmanagedType.R4)]
float fEVOL;//Extrapolation Volume
//[MarshalAs(UnmanagedType.R4)]
float fEOTV;//End of test volume
//[MarshalAs(UnmanagedType.R4)]
float fPEFT;//Peak Time
};
Here’s how I call the callback function:
public static void StartDataupload(IntPtr handle)
{
ogp = new onGetParaminfoHandler(GetParaminfo); //--keep reference of the delegate
GC.KeepAlive(ogp); //-- not much help from this one
StartUpLoad(handle, ogp);
}
And the callback itself:
private static void GetParaminfo(IntPtr handle, ref int hIndex,ref PATINFO pi, ref PARAMINFO pri)
{ enter code here
if (hIndex >= 1)
{
PATINFO pat = new PATINFO();
pat = pi;
PARAMINFO par = new PARAMINFO();
par = pri;
int error = Marshal.GetLastWin32Error();
if (error != 0)
throw new Win32Exception(error);
}
Some more info: the LastWin32Error returns large, random numbers which of course translate to Unknown errors. I suspect that between the first and the second call of the callback by the DLL, some pointer gets lost and so do I.
Here’s how the sample code (which works fine) in C calls the callback:
StartUpLoad(GetSafeHwnd(), GetParamInfo);
And part of the callback function of the sample C program which also uses the same DLL:
static void GetParamInfo(HWND hWnd, int &nIndex, PATINFO &PatientInf, PARAMINFO &ParamInf)
{
if(nIndex >= 1)
{
PATINFO *pPatientInf = new PATINFO;
PARAMINFO *pParamInf = new PARAMINFO;
*pPatientInf = PatientInf;
*pParamInf = ParamInf;
PostMessage(hWnd, WM_RECEIVEONECASE,
reinterpret_cast<WPARAM>(pPatientInf),
reinterpret_cast<LPARAM>(pParamInf));
}
else if(nIndex == FLAG_UPLOAD_STOP)
{
EnableOk(hWnd);
PostMessage(hWnd, WM_RECEIVECOMPLETE, PatientInf.nID, 0);
}
Any hints as to where to focus, would be greatly appreciated.
edit: here is the dllexport function signature:
__declspec(dllexport) void StartUpLoad(HWND hwnd, void (*pVoid)(HWND hWnd, int &nIndex, PATINFO &PatientInf, PARAMINFO &ParamInf));
and here are the definitions in C for the two structures:
typedef struct PATINFO
{
char szDeviceInfo[20];
char szUserName[20];
char szTime[20];
UINT nID;
UINT nGender;
UINT nStandard;
UINT nAge;
UINT nHeight;
UINT nWeight;
BOOL bBDT;
BOOL bSmoker;
PATINFO()
{
memset(szDeviceInfo, 0, sizeof(szDeviceInfo));
memset(szUserName, 0, sizeof(szUserName));
memset(szTime, 0, sizeof(szTime));
nID = 1;
nGender = 1;
nStandard = 2;
nAge = 20;
nHeight = 160;
nWeight = 50;
bBDT = FALSE;
bSmoker = FALSE;
};
}PATINFO;
typedef struct PARAMINFO
{
float fFVC;
float fFEV1;
float fPEF;
float fFEV1Per;//FEV1/FVC
float fFEF25;
float fFEF50;
float fFEF75;
float fFEF2575;
float fFET;
float fEVOL;
float fEOTV;
float fPEFT;
PARAMINFO()
{
fFVC = 0.0;
fFEV1 = 0.0;
fPEF = 0.0;
fFEV1Per = 0.0;
fFEF25 = 0.0;
fFEF50 = 0.0;
fFEF75 = 0.0;
fFEF2575 = 0.0;
fFET = 0.0f;
fEVOL = 0.0f;
fEOTV = 0.0f;
fPEFT = 0.0f;
};
}PARAMINFO;
EDIT2: the C handler OnReceiveOneCase is the following:
void CWaitDlg::OnReceiveOneCase(WPARAM wParam, LPARAM lParam)
{
PATINFO *pPatientInfo = reinterpret_cast<PATINFO *>(wParam);
PARAMINFO *pParamInfo = reinterpret_cast<PARAMINFO *>(lParam);
int nListCount = 0;
CString strNo("\0");
CString strFVC("\0");
strNo.Format("%d", pPatientInfo->nID);
strFVC.Format("%.2f", pParamInfo->fFVC);
nListCount = m_UploadList.GetItemCount();
m_UploadList.InsertItem(nListCount, strNo);
m_UploadList.SetItemText(nListCount, 1, pPatientInfo->szTime);
m_UploadList.SetItemText(nListCount, 2, strFVC);
++m_nCaseCount;
delete pPatientInfo;
delete pParamInfo;
}
I've just recently started playing with the InjectTouchInput for Windows 8 Consumer Preview. I've gone round and round in circles trying to get the darn thing to work but just can't seem to get it to actually interact. I'm working in c# and at the moment am only creating a metro interface with x and y coordinates in two text boxes and buttons which call the functions below to touch on the screen at those coordinates. Is this the right way to go about doing this?
protected unsafe class TouchDriver
{
public struct POINTER_TOUCH_INFO {
public POINTER_INFO pointerInfo; // An embedded POINTER_INFO header structure.
public TOUCH_FLAGS touchFlags; // Currently none.
public Rect rcContact; // Pointer contact area in pixel screen coordinates. By default, if the device does not report a contact area, this field defaults to a 0-by-0 rectangle centered around the pointer location.
public UInt32 orientation; // A pointer orientation, with a value between 0 and 359, where 0 indicates a touch pointer aligned with the x-axis and pointing from left to right; increasing values indicate degrees of rotation in the clockwise direction.
// This field defaults to 0 if the device does not report orientation.
public UInt32 pressure; // Pointer pressure normalized in a range of 0 to 256.
// This field defaults to 128 if the device does not report pressure.
// Question: Can this go from 0 to 1024 to match pen pressure?
}
public enum TOUCH_FLAGS
{
TOUCH_FLAGS_NONE = 0x00000000
}
public POINTER_TOUCH_INFO create_pointer_touch_info(POINTER_INFO pointerInfo, TOUCH_FLAGS touchFlags, RECT rcContact, UInt32 orientation, UInt32 pressure)
{
POINTER_TOUCH_INFO mi = new POINTER_TOUCH_INFO();
mi.pointerInfo = pointerInfo;
mi.touchFlags = touchFlags;
mi.rcContact = rcContact;
mi.orientation = orientation;
mi.pressure = pressure;
return mi;
}
public enum POINTER_INPUT_TYPE
{
PT_POINTER = 0x00000001,
PT_TOUCH = 0x00000002,
PT_PEN = 0x00000003,
PT_MOUSE = 0x00000004
}
public struct POINTER_INFO
{
public POINTER_INPUT_TYPE pointerType;
public UInt32 pointerId;
public UInt32 frameId;
public HANDLE sourceDevice;
public HWND hwndTarget;
public Point ptPixelLocation;
public Point ptHimetricLocation;
public Point ptPixelLocationPredicted;
public Point ptHimetricLocationPredicted;
public POINTER_FLAGS pointerFlags;
public DWORD dwTime;
public UInt32 historyCount;
// public UInt32 inputData;
public DWORD dwKeyStates;
public ULONGLONG Reserved;
}
public POINTER_INFO create_pointer_info(
POINTER_INPUT_TYPE pointerType,
UInt32 pointerId,
UInt32 frameId,
HANDLE sourceDevice,
HWND hwndTarget,
Point ptPixelLocation,
Point ptHimetricLocation,
Point ptPixelLocationPredicted,
Point ptHimetricLocationPredicted,
POINTER_FLAGS pointerFlags,
DWORD dwTime,
UInt32 historyCount,
// UInt32 inputData,
DWORD dwKeyStates,
ULONGLONG Reserved)
{
POINTER_INFO mi = new POINTER_INFO();
mi.pointerType = pointerType;
mi.pointerId = pointerId;
mi.frameId = frameId;
mi.sourceDevice = sourceDevice;
mi.hwndTarget = hwndTarget;
mi.ptPixelLocation = ptPixelLocation;
mi.ptHimetricLocation = ptHimetricLocation;
mi.ptPixelLocationPredicted = ptPixelLocationPredicted;
mi.ptHimetricLocationPredicted = ptHimetricLocationPredicted;
mi.pointerFlags = pointerFlags;
mi.dwTime = dwTime;
mi.historyCount = historyCount;
// mi.inputData = inputData;
mi.dwKeyStates = dwKeyStates;
mi.Reserved = Reserved;
return mi;
}
public enum POINTER_FLAGS
{
POINTER_FLAG_NONE = 0x00000000,
POINTER_FLAG_NEW = 0x00000001,
POINTER_FLAG_INRANGE = 0x00000002,
POINTER_FLAG_INCONTACT = 0x00000004,
POINTER_FLAG_FIRSTBUTTON = 0x00000010,
POINTER_FLAG_SECONDBUTTON = 0x00000020,
POINTER_FLAG_THIRDBUTTON = 0x00000040,
POINTER_FLAG_OTHERBUTTON = 0x00000080,
POINTER_FLAG_PRIMARY = 0x00000100,
POINTER_FLAG_CONFIDENCE = 0x00000200,
POINTER_FLAG_CANCELLED = 0x00000400,
POINTER_FLAG_DOWN = 0x00010000,
POINTER_FLAG_UPDATE = 0x00020000,
POINTER_FLAG_UP = 0x00040000,
POINTER_FLAG_WHEEL = 0x00080000,
POINTER_FLAG_HWHEEL = 0x00100000
}
[System.Runtime.InteropServices.DllImport("user32.dll", CallingConvention = CallingConvention.StdCall)]
private static extern Boolean InjectTouchInput(UInt32 count, POINTER_TOUCH_INFO* pntTchInfo);
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern Boolean InitializeTouchInjection(UInt32 maxCount, DWORD dwMode);
private const UInt32 MAX_TOUCH_COUNT = 256; // Can be as high as 256
private const UInt32 TOUCH_FEEDBACK_DEFAULT = 0x1;
private const UInt32 TOUCH_FEEDBACK_INDIRECT = 0x2;
private const UInt32 TOUCH_FEEDBACK_NONE = 0x3;
public unsafe static void MouseTouch(int x, int y)
{
bool ret = false;
ret = InitializeTouchInjection(1, TOUCH_FEEDBACK_DEFAULT);
if (!ret)
{
throw new NotSupportedException();
}
Point point = new Point(x,y);
POINTER_INFO ptrInfo = new POINTER_INFO();
POINTER_TOUCH_INFO* ptrTchInfo;
ptrInfo.pointerType = POINTER_INPUT_TYPE.PT_TOUCH;
ptrInfo.pointerId = 1;
ptrInfo.ptPixelLocation = point;
ptrInfo.pointerFlags = POINTER_FLAGS.POINTER_FLAG_PRIMARY;
POINTER_TOUCH_INFO ptrTchInfobase = new POINTER_TOUCH_INFO();
ptrTchInfo = &ptrTchInfobase;
ptrTchInfo->pointerInfo = ptrInfo;
ptrTchInfo->touchFlags = TOUCH_FLAGS.TOUCH_FLAGS_NONE;
ptrTchInfo->rcContact.X = x - 2;
ptrTchInfo->rcContact.Y = y - 2;
ptrTchInfo->rcContact.Width = 4;
ptrTchInfo->rcContact.Height = 4;
ptrTchInfo->pressure = 128;
ptrTchInfo->orientation = 0;
ret = InjectTouchInput(1, ptrTchInfo);
if (!ret)
{
throw new NotImplementedException();
}
}
}
Almost all of that I've tried to lift from the InjectTouchInput API I found online. I can InitializeTouchInject fine, its the Inject bit thats returning false and I have no idea why.
I went ahead and create some custom functions in c++ based on the sample Microsoft provided and then went and imported that into C# using alot of the same definitions as before but without farting about with all the type checking, pointers and arguments that were causing headaches before.
The DLL file that I've used is TouchInjectionDriver.dll and can be found here:
http://www.mediafire.com/file/do2h6m04omjweb3/TouchInjectionDriver.zip
Below is the C# code I used to implement it.
public enum TOUCH_MASK : uint
{
TOUCH_MASK_NONE = 0x00000000,
TOUCH_MASK_CONTACTAREA = 0x00000001,
TOUCH_MASK_ORIENTATION = 0x00000002,
TOUCH_MASK_PRESSURE = 0x00000004
}
public enum POINTER_INPUT_TYPE : uint
{
PT_POINTER = 0x00000001,
PT_TOUCH = 0x00000002,
PT_PEN = 0x00000003,
PT_MOUSE = 0x00000004
}
public enum POINTER_FLAGS : uint
{
POINTER_FLAG_NONE = 0x00000000,
POINTER_FLAG_NEW = 0x00000001,
POINTER_FLAG_INRANGE = 0x00000002,
POINTER_FLAG_INCONTACT = 0x00000004,
POINTER_FLAG_FIRSTBUTTON = 0x00000010,
POINTER_FLAG_SECONDBUTTON = 0x00000020,
POINTER_FLAG_THIRDBUTTON = 0x00000040,
POINTER_FLAG_OTHERBUTTON = 0x00000080,
POINTER_FLAG_PRIMARY = 0x00000100,
POINTER_FLAG_CONFIDENCE = 0x00000200,
POINTER_FLAG_CANCELLED = 0x00000400,
POINTER_FLAG_DOWN = 0x00010000,
POINTER_FLAG_UPDATE = 0x00020000,
POINTER_FLAG_UP = 0x00040000,
POINTER_FLAG_WHEEL = 0x00080000,
POINTER_FLAG_HWHEEL = 0x00100000
}
public enum TOUCH_FEEDBACK : uint
{
TOUCH_FEEDBACK_DEFAULT = 0x1,
TOUCH_FEEDBACK_INDIRECT = 0x2,
TOUCH_FEEDBACK_NONE = 0x3
}
[DllImport("TouchInjectionDriver.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern bool InjectTouch(int x, int y, POINTER_INPUT_TYPE pt_input, int pressure, int orientation, int id, int rcContactTop, int rcContactBottom, int rcContactLeft, int rcContactRight, POINTER_FLAGS pointerFlags, TOUCH_MASK touchMask);
[DllImport("TouchInjectionDriver.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern void setTouchFeedback(TOUCH_FEEDBACK fb);
[DllImport("TouchInjectionDriver.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern void setDefaultRectSize(int size);
[DllImport("TouchInjectionDriver.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern void setDefaultPressure(int pres);
[DllImport("TouchInjectionDriver.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern void setDefaultOrientation(int or);
[DllImport("User32.dll")]
static extern Boolean MessageBeep(UInt32 beepType);
public static void mouseclick(int x, int y)
{
bool ret;
setTouchFeedback(TOUCH_FEEDBACK.TOUCH_FEEDBACK_INDIRECT);
ret = InjectTouch(x, y, POINTER_INPUT_TYPE.PT_TOUCH, 3200, 0, 0, x - 4, x + 4, y - 4, y + 4,POINTER_FLAGS.POINTER_FLAG_DOWN|POINTER_FLAGS.POINTER_FLAG_INCONTACT|POINTER_FLAGS.POINTER_FLAG_INRANGE,TOUCH_MASK.TOUCH_MASK_CONTACTAREA|TOUCH_MASK.TOUCH_MASK_ORIENTATION|TOUCH_MASK.TOUCH_MASK_PRESSURE);
if (ret)
{
ret = InjectTouch(x, y, POINTER_INPUT_TYPE.PT_TOUCH, 3200, 0, 0, x - 4, x + 4, y - 4, y + 4, POINTER_FLAGS.POINTER_FLAG_UP, TOUCH_MASK.TOUCH_MASK_CONTACTAREA | TOUCH_MASK.TOUCH_MASK_ORIENTATION | TOUCH_MASK.TOUCH_MASK_PRESSURE);
}
else
{
MessageBeep(0);
}
}
I can connect and get images from my device with twaindotnet. But I want to handle the images as Image class. When I try something like this:
...
ArrayList pics = tw.TransferPictures();
EndingScan();
tw.CloseSrc();
if(pics.Count > 0) {
IntPtr img = (IntPtr) pics[ 0 ];
PicForm newpic = new PicForm( img );
Image r = Image.FromHbitmap(img, this.Handle);
picturebox.Image = r;
}
...
I'm getting an error as "Error:Generic Error Occured in GDI+" on the line ,
Image r = Image.FromHbitmap(img, this.Handle);
So where am I wrong? How can I get as an Image the image?
I too found out that calling Image.FromHbitmap is not enough.
I had a look in the TwainDotNet library you mentioned and there I found the BitmapRenderer class.
Pulling out just the relevant bit it is easy enough to use that to create a simple static method that you can pass in the IntPtr you get from TWAIN (in your case your img variable) and convert it to a Bitmap. You, therefore, call it like so:
Image r = TwainBitmapConvertor.ToBitmap(img);
and here is the code (it only works on x86 and needs tidying but it does the job):
public static class TwainBitmapConvertor
{
[StructLayout(LayoutKind.Sequential, Pack = 2)]
private class BitmapInfoHeader
{
public int Size;
public int Width;
public int Height;
public short Planes;
public short BitCount;
public int Compression;
public int SizeImage;
public int XPelsPerMeter;
public int YPelsPerMeter;
public int ClrUsed;
public int ClrImportant;
}
[DllImport("gdi32.dll", ExactSpelling = true)]
private static extern int SetDIBitsToDevice(IntPtr hdc,
int xdst, int ydst, int width, int height, int xsrc,
int ysrc, int start, int lines, IntPtr bitsptr,
IntPtr bmiptr, int color);
[DllImport("kernel32.dll", ExactSpelling = true)]
private static extern IntPtr GlobalLock(IntPtr handle);
[DllImport("kernel32.dll", ExactSpelling = true)]
private static extern bool GlobalUnlock(IntPtr handle);
[DllImport("kernel32.dll", ExactSpelling = true)]
private static extern IntPtr GlobalFree(IntPtr handle);
public static Bitmap ToBitmap(IntPtr dibHandle)
{
var bitmapPointer = GlobalLock(dibHandle);
var bitmapInfo = new BitmapInfoHeader();
Marshal.PtrToStructure(bitmapPointer, bitmapInfo);
var rectangle = new Rectangle();
rectangle.X = rectangle.Y = 0;
rectangle.Width = bitmapInfo.Width;
rectangle.Height = bitmapInfo.Height;
if (bitmapInfo.SizeImage == 0)
{
bitmapInfo.SizeImage =
((((bitmapInfo.Width * bitmapInfo.BitCount) + 31) & ~31) >> 3)
* bitmapInfo.Height;
}
// The following code only works on x86
Debug.Assert(Marshal.SizeOf(typeof(IntPtr)) == 4);
int pixelInfoPointer = bitmapInfo.ClrUsed;
if ((pixelInfoPointer == 0) && (bitmapInfo.BitCount <= 8))
{
pixelInfoPointer = 1 << bitmapInfo.BitCount;
}
pixelInfoPointer = (pixelInfoPointer * 4) + bitmapInfo.Size
+ bitmapPointer.ToInt32();
IntPtr pixelInfoIntPointer = new IntPtr(pixelInfoPointer);
Bitmap bitmap = new Bitmap(rectangle.Width, rectangle.Height);
using (Graphics graphics = Graphics.FromImage(bitmap))
{
IntPtr hdc = graphics.GetHdc();
try
{
SetDIBitsToDevice(hdc,
0, 0, rectangle.Width, rectangle.Height, 0, 0, 0,
rectangle.Height, pixelInfoIntPointer, bitmapPointer, 0);
}
finally
{
graphics.ReleaseHdc(hdc);
}
}
bitmap.SetResolution(PpmToDpi(bitmapInfo.XPelsPerMeter),
PpmToDpi(bitmapInfo.YPelsPerMeter));
GlobalUnlock(dibHandle);
GlobalFree(dibHandle);
return bitmap;
}
private static float PpmToDpi(double pixelsPerMeter)
{
double pixelsPerMillimeter = (double)pixelsPerMeter / 1000.0;
double dotsPerInch = pixelsPerMillimeter * 25.4;
return (float)Math.Round(dotsPerInch, 2);
}
}
Assuming that tw.TransferPictures() returns an array of bitmap handles, then change Image r = ... to:
Image r = Image.FromHbitmap(img);
The second argument to FromHbitmap is a handle to a GDI palette, which I doubt you have.
This question has bugged me for a while now, and I realize it's hard to describe what I am looking for. I want to be able to reserve a row for text input in a C# Console Application, while still allowing other information to be updated in the remaining rows. More specifically, I'd like to make a small mud game where the game is updated even while the user is busy making input. It's important that the input doesn't block the information flow.
I'd like to achieve the effect of the user writing input to the last visible row in the screen, while the other text append as usual, but not scrolling down my line of input, nor overwrite it.
If I would describe this in terms of Forms, I'd imagine the equivalent of having a multi-line textbox as the upper portion for the information, with a single-line textbox at the bottom for the input.
One option that you could try, is to directly manipulate the console buffer to render your game area and use the Console.SetCursorPosition to position the cursor to the input line where you use Console.ReadLine for example to take the user input.
Since the direct manipulation of the buffer does not affect the cursor position and is independent of the Console Read/Write functionality you can have a thread updating the Console buffer which covers the first 24 lines and the 25 line is waiting for input. If I get some time I will try put together a sample of what I mean, but in the meantime you can reference the other answers I have provided for a pointer to writing directly to the Console buffer.
How can I write fast colored output to Console?
Deleting previously written lines in Console
Of course you will want to write some nice wrapper functions to make this easy to work with, I always think about doing this, I just don't do enough work with the console so that I actually get down and do something.
Update: Added a small example of updating the console in a thread while still accepting user input. Just type 'quit' to stop it running. Note the the ConsoleBuffer class is not ideal, I am not closing the console handle, it was just a quick piece of code for the demo.
using System;
using System.IO;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;
using System.Threading;
namespace ConsoleDemo
{
class Program
{
static void Main(string[] args)
{
Thread t = new Thread(new ThreadStart(UpdateConsole));
t.IsBackground=true;
t.Start();
string input;
do
{
Console.SetCursorPosition(0, 23);
Console.Write("Command: ");
input = Console.ReadLine();
ConsoleBuffer.ClearArea(0, 21, 80, 3);
Console.SetCursorPosition(0, 22);
Console.Write(input);
} while (!string.Equals(input, "quit", StringComparison.OrdinalIgnoreCase));
}
static void UpdateConsole()
{
int i = 0;
Random rnd = new Random();
while (true)
{
string s = new string((char)(65 + (i % 26)),1);
for (short x = 0; x < 80; ++x)
{
for (short y = 0; y < 20; ++y)
{
ConsoleBuffer.WriteAt(x, y, s);
ConsoleBuffer.SetAttribute(x, y, (short)(rnd.Next(15)+1));
}
}
Thread.Sleep(500);
i++;
}
}
}
public class ConsoleBuffer
{
private static SafeFileHandle _hBuffer = null;
static ConsoleBuffer()
{
_hBuffer = CreateFile("CONOUT$", 0x40000000, 2, IntPtr.Zero, FileMode.Open, 0, IntPtr.Zero);
if (_hBuffer.IsInvalid)
{
throw new Exception("Failed to open console buffer");
}
}
public static void WriteAt(short x, short y, string value)
{
int n = 0;
WriteConsoleOutputCharacter(_hBuffer, value, value.Length, new Coord(x, y), ref n);
}
public static void SetAttribute(short x, short y, short attr)
{
SetAttribute( x, y, new short[] { attr });
}
public static void SetAttribute(short x, short y, short[] attrs)
{
int n = 0;
WriteConsoleOutputAttribute(_hBuffer, attrs, attrs.Length, new Coord(x, y), ref n);
}
public static void ClearArea(short left, short top, short width, short height, char ch = ' ')
{
ClearArea(left, top, width, height, new CharInfo() { Char = new CharUnion() { UnicodeChar = ch } });
}
public static void ClearArea(short left, short top, short width, short height)
{
ClearArea(left, top, width, height, new CharInfo() { Char = new CharUnion() { AsciiChar = 32 } });
}
private static void ClearArea(short left, short top, short width, short height, CharInfo charAttr)
{
CharInfo[] buf = new CharInfo[width * height];
for (int i = 0; i < buf.Length; ++i)
{
buf[i] = charAttr;
}
SmallRect rect = new SmallRect() { Left = left, Top = top, Right = (short)(left + width), Bottom = (short)(top + height) };
WriteConsoleOutput(_hBuffer, buf,
new Coord() { X = width, Y = height },
new Coord() { X = 0, Y = 0 },
ref rect);
}
[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern SafeFileHandle CreateFile(
string fileName,
[MarshalAs(UnmanagedType.U4)] uint fileAccess,
[MarshalAs(UnmanagedType.U4)] uint fileShare,
IntPtr securityAttributes,
[MarshalAs(UnmanagedType.U4)] FileMode creationDisposition,
[MarshalAs(UnmanagedType.U4)] int flags,
IntPtr template);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool CloseHandle(IntPtr hObject);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool WriteConsoleOutput(
SafeFileHandle hConsoleOutput,
CharInfo[] lpBuffer,
Coord dwBufferSize,
Coord dwBufferCoord,
ref SmallRect lpWriteRegion);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool WriteConsoleOutputCharacter(
SafeFileHandle hConsoleOutput,
string lpCharacter,
int nLength,
Coord dwWriteCoord,
ref int lpumberOfCharsWritten);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool WriteConsoleOutputAttribute(
SafeFileHandle hConsoleOutput,
short[] lpAttributes,
int nLength,
Coord dwWriteCoord,
ref int lpumberOfAttrsWritten);
[StructLayout(LayoutKind.Sequential)]
struct Coord
{
public short X;
public short Y;
public Coord(short X, short Y)
{
this.X = X;
this.Y = Y;
}
};
[StructLayout(LayoutKind.Explicit)]
struct CharUnion
{
[FieldOffset(0)]
public char UnicodeChar;
[FieldOffset(0)]
public byte AsciiChar;
}
[StructLayout(LayoutKind.Explicit)]
struct CharInfo
{
[FieldOffset(0)]
public CharUnion Char;
[FieldOffset(2)]
public short Attributes;
}
[StructLayout(LayoutKind.Sequential)]
struct SmallRect
{
public short Left;
public short Top;
public short Right;
public short Bottom;
}
}
}
The dotNet Console supports SetCursorPosition() and you also use the old DOS trick of ending a line with \r instead of \n\r.
But multi-threading and Append doesn't sound like a good combination.
Look at these .NET bindings for curses
http://www.mono-project.com/Libraries#Curses
ncurses is obviously a UNIX invention, but the API's are said to be mostly cross-platform (I haven't tried the .NET bindings myself, but have had very good results working with ncurses in general).
This will absolutely contain the goods you need and more