What is/how do I use HFont in C# - c#

I'm working with a printer SDK for a label printer in C#, details of which can be found here:
https://stackoverflow.com/questions/18083309/getting-a-printer-api-to-work-with-c-sharp
Taking the advice given there, I used PInvoke to get the functions in the DLLs to work, and to my surprise, it all has began to come together...mostly.
A function SlpDrawTextXY() is supposed to be able to take an argument for a font of the type Hfont. This can be created by a function called SlpCreateFont(). (details of these methods on pages 21 and 19 respectively of the documentation).
Now, my quest to discover what Hfont actually is has went poorly. MSDN mentions it a bit, but doesn't really tell me what it is exactly. The articles provided aren't really useful if you are going in blind and are definitely more suited to someone who is already half way there. Other documentation about it is really slim and I'm left guessing at what the hell is supposed to be happening.
I have a block of code that looks like this:
public partial class Form1 : Form
{
[DllImport("SlpApi7x32.dll")]
static extern void SlpDebugMode(int nMode);
[DllImport("SlpApi7x32.dll")]
static extern int SlpOpenPrinter(String strPrinterName, int nID, bool fPortrait);
[DllImport("SlpApi7x32.dll")]
static extern void SlpClosePrinter();
[DllImport("SlpApi7x32.dll")]
static extern bool SlpStartLabel();
[DllImport("SlpApi7x32.dll")]
static extern void SlpDrawTextXY(int x, int y, Font iFont, String lpText);
[DllImport("SlpApi7x32.dll")]
static extern bool SlpEndLabel();
[DllImport("SlpApi7x32.dll")]
static extern Font SlpCreateFont(String lpName, int nPoints, int nAttributes);
[DllImport("GDI32.dll")]
public static extern bool DeleteObject(IntPtr objectHandle);
public Form1()
{
InitializeComponent();
}
private void print_Click(object sender, EventArgs e)
{
//Font myFont = new Font("Arial", 12);
//IntPtr hFont = myFont.ToHfont();
SlpDebugMode(2);
SlpOpenPrinter("Smart Label Printer 440", 1, false);
{
SlpStartLabel();
//Font font = SlpCreateFont("Courier", 12, 0);
SlpDrawTextXY(30, 30, null, "Hello World!");
SlpEndLabel();
}
SlpClosePrinter();
}
}
There are some remnants of my toying around that have been commented out. If it's commented out, it doesn't work.
This code will actually go to the printer and will 'print' a blank label, so it does seem like I'm really close. The third argument in SlpDrawTextXY is where the font is supposed to be though and I have it set as 'null' just to see if I can get past it successfully. This code is based on the sample C code in the documentation on page 12. I would like to be able to transform this code into something that actually prints text.

[DllImport("SlpApi7x32.dll")]
static extern Font SlpCreateFont(...)
Using Font is not correct here. SlpCreateFont() returns a HFONT, a "handle to font". It is the way you manipulate a font when you create one in unmanaged code. And is the exact same kind of animal you get back from the Font.ToHfont() method. So you must declare it the way ToHfont() returns it, it must be IntPtr in your declarations. Update the other declarations accordingly.
Do note that you'll have some decent odds that you can use Font.ToHfont() instead of SlpCreateFont(). The rules are the same however, you must be sure to call DeleteObject() when you are done using the font or you'll leak GDI objects that eventually will crash your code.

Hans was absolutely right. For future reference, below is working code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace SSLP
{
public partial class Form1 : Form
{
[DllImport("SlpApi7x32.dll")]
static extern void SlpDebugMode(int nMode);
[DllImport("SlpApi7x32.dll")]
static extern int SlpOpenPrinter(String strPrinterName, int nID, bool fPortrait);
[DllImport("SlpApi7x32.dll")]
static extern void SlpClosePrinter();
[DllImport("SlpApi7x32.dll")]
static extern bool SlpStartLabel();
[DllImport("SlpApi7x32.dll")]
static extern void SlpDrawTextXY(int x, int y, IntPtr iFont, String lpText);
[DllImport("SlpApi7x32.dll")]
static extern bool SlpEndLabel();
[DllImport("SlpApi7x32.dll")]
static extern IntPtr SlpCreateFont(String lpName, int nPoints, int nAttributes);
[DllImport("GDI32.dll")]
public static extern bool DeleteObject(IntPtr objectHandle);
public Form1()
{
InitializeComponent();
}
private void Button1_Click(object sender, EventArgs e)
{
IntPtr font = SlpCreateFont("Arial", 10, 0);
SlpDebugMode(2);
//The second parameter defines the type of label per the documentation.
SlpOpenPrinter("Smart Label Printer 440", 3, false);
{
SlpStartLabel();
//Draw as much as you want with these!
SlpDrawTextXY(0, 0, font, "Hello World");
SlpEndLabel();
}
SlpClosePrinter();
DeleteObject(font);
}
}
}

Related

C# running exe inside panel

I am trying to open a compiled exe inside a panel of my code and that this program stays only inside this panel, in other words, if i move the window or even if I close the window, it would act as the same program.
It's working to some programs for example, "notepad.exe", but some others it doesn't (calc.exe for example it doesn't), they just insist to open outside the panel, so that's when I need help.
That's my code so far:
public partial class Form1 : Form
{
[DllImport("USER32.DLL")]
static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
[DllImport("USER32.dll")]
private static extern bool MoveWindow(IntPtr hwnd, int x, int y, int cx, int cy, bool repaint);
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
Process process = Process.Start("calc.exe");
process.WaitForInputIdle();
SetParent(process.MainWindowHandle, this.panel1.Handle);
MoveWindow(process.MainWindowHandle, 0, 0, this.Width - 90, this.Height, true);
}
}
I am a true newbie on C# and the progress I got so far was from some videos from youtube and even here, but it doesn't work exactly as I need, so I don't mind to reformulate the whole code, as long it works as only 1 program.

Turn Monitor completely off (not Standby) programmatically [duplicate]

Is it programmatically possible to turn a monitor on/off through code (C#)?
Did you even try googling it?
First hit:
http://www.codeproject.com/KB/cs/Monitor_management_guide.aspx
I am not surprised you need to use some DLL's supplied by Windows.
(I guessed you needed a C# solution, because that's the only tag you applied).
EDIT February 8th 2013:
It was mentioned that the solution no longer worked under Windows 7 en 8. Well here is one that works nicely under Windows 7, haven't tried Windows 8 yet.
http://cocoa.ninja/posts/Turn-off-your-monitor-in-Csharp.html
namespace MonitorOff {
public enum MonitorState {
MonitorStateOn = -1,
MonitorStateOff = 2,
MonitorStateStandBy = 1
}
public partial class Form1 : Form {
[DllImport("user32.dll")]
private static extern int SendMessage(int hWnd, int hMsg, int wParam, int lParam);
public Form1() {
InitializeComponent();
SystemEvents.SessionSwitch += SystemEvents_SessionSwitch;
}
void SystemEvents_SessionSwitch(object sender, SessionSwitchEventArgs e) {
SetMonitorInState(MonitorState.MonitorStateOff);
}
private void button1_Click(object sender, EventArgs e) {
SetMonitorInState(MonitorState.MonitorStateOff);
}
private void SetMonitorInState(MonitorState state) {
SendMessage(0xFFFF, 0x112, 0xF170, (int)state);
}
}
}
The answer https://stackoverflow.com/a/713504/636189 above works great for turning off a Windows 7/8 monitor but not for waking it up. On those systems you'll need to do something hackish like this (as found https://stackoverflow.com/a/14171736/636189):
[DllImport("user32.dll")]
static extern void mouse_event(Int32 dwFlags, Int32 dx, Int32 dy, Int32 dwData, UIntPtr dwExtraInfo);
private const int MOUSEEVENTF_MOVE = 0x0001;
private void Wake(){
mouse_event(MOUSEEVENTF_MOVE, 0, 1, 0, UIntPtr.Zero);
Sleep(40);
mouse_event(MOUSEEVENTF_MOVE, 0, -1, 0, UIntPtr.Zero);
}
Press the on/off button
If you want to do it in code, apparently this is possible in the Win32 API:
SendMessage hWnd, WM_SYSCOMMAND, SC_MONITORPOWER, param
where WM_SYSCOMMAND = 0x112 and
SC_MONITORPOWER = 0xF170 and
param indicates the mode to put the monitor in:
-1 : on
2 : off
1 : energy saving mode
hWnd can be a handle for any window - so if you have a Form, something like this should work
int WM_SYSCOMMAND = 0x112;
int SC_MONITORPOWER = 0xF170;
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern int SendMessage(IntPtr hWnd, int wMsg, IntPtr wParam, IntPtr lParam);
public static void Main(string[] args)
{
Form f = new Form();
bool turnOff = true; //set true if you want to turn off, false if on
SendMessage(f.Handle, WM_SYSCOMMAND, (IntPtr)SC_MONITORPOWER, (IntPtr)(turnOff ? 2 : -1));
}
Note I haven't actually tried this...
For who wants this functionality on a console application:
using System;
using System.Runtime.InteropServices;
using System.Timers;
namespace TurnScreenOFF
{
class Program
{
private static int WM_SYSCOMMAND = 0x0112;
private static uint SC_MONITORPOWER = 0xF170;
public static void Main(string[] args)
{
SendMessage(GetConsoleWindow(), WM_SYSCOMMAND, (IntPtr)SC_MONITORPOWER, (IntPtr)2);
}
[DllImport("kernel32.dll")]
static extern IntPtr GetConsoleWindow();
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern int SendMessage(IntPtr hWnd, int wMsg, IntPtr wParam, IntPtr lParam);
}
}
Adaptated and tested. 100% working on Windows 8.
This code can be useful for turning on and turning off.. It worked in Windows 7 also.
private int SC_MONITORPOWER = 0xF170;
private uint WM_SYSCOMMAND = 0x0112;
[DllImport("user32.dll")]
static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
enum MonitorState
{
ON = -1,
OFF = 2,
STANDBY = 1
}
private void SetMonitorState(MonitorState state)
{
Form frm = new Form();
SendMessage(frm.Handle, WM_SYSCOMMAND, (IntPtr)SC_MONITORPOWER, (IntPtr)state);
}
For calling the function you must do like:
SetMonitorState(MonitorState.ON);
OR
SetMonitorState(MonitorState.OFF);
Note: This code tested in WPF Application. With the below namespaces:
using System.Runtime.InteropServices;
using System.Windows.Forms;
I could not find a copy paste example, so created one myself, dont forget to add a reference to System.Windows.Forms.
using System;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows.Forms;
namespace monitor_on_off
{
class Program
{
[DllImport("user32.dll")]
static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll")]
static extern void mouse_event(Int32 dwFlags, Int32 dx, Int32 dy, Int32 dwData, UIntPtr dwExtraInfo);
private const int WmSyscommand = 0x0112;
private const int ScMonitorpower = 0xF170;
private const int MonitorShutoff = 2;
private const int MouseeventfMove = 0x0001;
public static void MonitorOff(IntPtr handle)
{
SendMessage(handle, WmSyscommand, (IntPtr)ScMonitorpower, (IntPtr)MonitorShutoff);
}
private static void MonitorOn()
{
mouse_event(MouseeventfMove, 0, 1, 0, UIntPtr.Zero);
Thread.Sleep(40);
mouse_event(MouseeventfMove, 0, -1, 0, UIntPtr.Zero);
}
static void Main()
{
var form = new Form();
while (true)
{
MonitorOff(form.Handle);
Thread.Sleep(5000);
MonitorOn();
Thread.Sleep(5000);
}
}
}
}
I have gone through every single method that everyone has published for putting a monitor to sleep and waking it later at some other time. Granted the SendMessage() does work with Windows XP but it doesn't wake the monitor after the monitor has been a sleep for a period of time. I have tried using C#, DOS, scripts for playing with power profiles, and Powershell. Eventually I gave up and went back to the beginning and my first thought was proven correct. You need to use the PostMessage() after the monitor has been turned off, better yet, you should probably always use PostMessage();
So all the code that you have seen before is correct, instead use the following:
using System.Runtime.InteropServices;
[DllImport("user32.dll")]
static extern IntPtr PostMessage(int hWnd, int msg, int wParam, int lParam);
PostMessage(-1, WM_SYSCOMMAND, SC_MONITORPOWER, MONITOR_OFF);
At this time of execution and working appropriately (May 11, 2015) I am running
Windows 7 Professional Version 6.1.7601 Service Pack 1 Build 7601
Visual Studio Profesional 2013 Version 12.0.31101.00 Update 4
.NET Framework 4.5.51209
C#
My system is completely up to date.
The answer with the least SLOC:
using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;
static class Program
{
[DllImport("user32.dll")]
static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, int wParam, int lParam);
[STAThread]
static void Main()
{
SendMessage(new Form().Handle, 0x0112, 0xF170, 2);
}
}
For Windows 10 (tested on Pro 64 bits), I was able to turn off the monitor using the SendMessage() technique mentioned in this page.
However, impossible for me to turn the monitor back on: the "mouse move" trick did not work, the SendMessage() technique would turn the screen back on for one second then back off and using PostMessage() did not change anything.
But the trick is in fact really simple, all I had to do was simulate a keypress with SendKeys(). I'm using ALT here because in itself it has no impact on the system but it could be any other key.
SendKeys.SendWait("%");
If you're not using Windows.Forms, sending "ALT" also works using SendInput() but it's longer to implement.

How can I get the word under the mouse cursor in Powerpoint 2013 using C#?

I would like to know the word under the mouse cursor in Powerpoint so that it can be used for a screen reader. Accessibility solutions are acceptable if it can distinguish between different words (vs a block).
This is actually really hard, if you do not know what you are doing. There is a easy way and a hard way to do this. Easy way would be to use Microsoft UI automation framework (that includes Powerpoint automation). Alternative frameworks can also be used.
Hard way wold be to directly use win api.
For example: To get window title currently under the mouse.
public static class dllRef
{
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool GetCursorPos(out Point lpPoint);
[DllImport("user32.dll")]
private static extern IntPtr WindowFromPoint(Point point);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern int RegisterWindowMessage(string lpString);
[DllImport("user32.dll", EntryPoint = "SendMessage", CharSet = CharSet.Auto)]
public static extern bool SendMessage(IntPtr hWnd, uint Msg, int wParam, StringBuilder lParam);
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr SendMessage(int hWnd, int Msg, int wparam, int lparam);
public const int WM_USER = 0x400;
public const int WM_COPYDATA = 0x4A;
public const int WM_GETTEXT = 0x000D;
public const int WM_GETTEXTLENGTH = 0x000E;
public static void RegisterControlforMessages()
{
RegisterWindowMessage("WM_GETTEXT");
}
public static string GetText()
{
StringBuilder title = new StringBuilder();
Point p = dllRef.getMousePosition();
var lhwnd = dllRef.WindowFromPoint(p);
var lTextlen = dllRef.SendMessage((int)lhwnd, dllRef.WM_GETTEXTLENGTH, 0, 0).ToInt32();
if (lTextlen > 0)
{
title = new StringBuilder(lTextlen + 1);
SendMessage(lhwnd, WM_GETTEXT, title.Capacity, title);
}
return title.ToString();
}
public static Point getMousePosition()
{
Point p = new Point();
GetCursorPos(out p);
return p;
}
}
and
private void Form1_Load(object sender, EventArgs e)
{
Timer t = new Timer();
t.Interval = 25;
t.Tick += new EventHandler(Timer_Tick);
t.Start();
}
public void Timer_Tick(object sender, EventArgs eArgs)
{
this.label1.Text = dllRef.GetText();
}
In addition you can use Microsoft Spy++
to find if information you are looking for is exposed. Other then that I can really recommend you use automation framework that is layer built on top of this. Google has more then enough examples on this (as well as how to build sophisticated keyloggers).
The same solutions as Margus came to mind. Either UI Automation or PowerPoint interop. Luckily UI Automation works.
The below works in my test putting the mouse over a PowerPoint 2013 text box. Let me know if you think something is missing.
using System.Windows.Automation;
using UIAutomationClient;
String TextUnderCursor()
{
System.Windows.Point point = new System.Windows.Point(Cursor.Position.X, Cursor.Position.Y);
AutomationElement element = AutomationElement.FromPoint(point);
object patternObj;
if (element.TryGetCurrentPattern(TextPattern.Pattern, out patternObj))
{
var textPattern = (TextPattern)patternObj;
return textPattern.DocumentRange.GetText(-1).TrimEnd('\r'); // often there is an extra '\r' hanging off the end.)
} else
{
return "no text found";
}
}
Update Sample http://download.veodin.com/misc/PowerPoint_Screen_Reader.zip
Focus Visual Studio, put the mouse over the PowerPoint then use F5 to run the code

C# Handle without a form

Im trying to get my program to send messages to control volume but I need a handle.
I currently tried to use broadcast as seen below in the current code but that would cause all processes to send a message causing volume to go up to 100 or 0 and freezing the program. Ive tried using Process.GetCurrentProcess().MainWindowHandle; but that only works if I have a form or command prompt. Note I wish to have this program work using my a modification of my current code.
using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Diagnostics;
namespace Utilities
{
static class VolumeMessage
{
private const int APPCOMMAND_VOLUME_MUTE = 0x80000;
private const int APPCOMMAND_VOLUME_UP = 0xA0000;
private const int APPCOMMAND_VOLUME_DOWN = 0x90000;
private const int WM_APPCOMMAND = 0x319;
private static IntPtr Handle = (IntPtr)0xffff;
[DllImport("user32.dll")]
public static extern IntPtr SendMessageW(IntPtr hWnd, int Msg,
IntPtr wParam, IntPtr lParam);
public static void Mute()
{
SendMessageW(Handle, WM_APPCOMMAND, Handle,
(IntPtr)APPCOMMAND_VOLUME_MUTE);
}
public static void volumeDown()
{
SendMessageW(Handle, WM_APPCOMMAND, Handle,
(IntPtr)APPCOMMAND_VOLUME_DOWN);
}
public static void volumeUp()
{
SendMessageW(Handle, WM_APPCOMMAND, Handle,
(IntPtr)APPCOMMAND_VOLUME_UP);
}
}
}
You can use
var handle = Process.GetProcessesByName("explorer").First().MainWindowHandle;
Note that for the second parameter you can pass IntPtr.Zero
BTW I faced the same problem, also with mute/volume control...
I think you sometimes just need a form to get windows messages working right, so create one and make it always hidden. We've had to so this previously for something along these lines.
If you really want to do it this way then you could send it to the desktop hwnd I believe. From memory there is an API to get this hwnd which is just something like GetDesktopWindow or something like that.
However there has got to be a better way. Surely an API exists to directly control the volume.

How can I change text on a win32 window?

Looking for hints, tips and search terms for changing the text on a win32 window from C#.
More specifically, I'm trying to change the text on the print dialog from "Print" to "OK", as I am using the dialog to create a print ticket and not do any printing.
How can I find the dialog's window handle? Once I've got it, how would I go about finding the button in the child windows of the form? Once I've found that, how would I change the text on the button? And how can I do all this before the dialog is shown?
There's a similar question here, but it points to a CodeProject article that is waaay more complex than needed and is taking me a bit longer to parse through than I'd like to spend on this. TIA.
You should use Spy++ to take a look at the dialog. The class name is important and the control ID of the button. If it is a native Windows dialog then the class name should be "#32770". In which case you'll have a lot of use for my post in this thread. Here is another in C#. You change the button text by P/Invoking SetWindowText() on the button handle.
using System;
using System.Text;
using System.Drawing;
using System.Windows.Forms;
using System.Runtime.InteropServices;
class SetDialogButton : IDisposable {
private Timer mTimer = new Timer();
private int mCtlId;
private string mText;
public SetDialogButton(int ctlId, string txt) {
mCtlId = ctlId;
mText = txt;
mTimer.Interval = 50;
mTimer.Enabled = true;
mTimer.Tick += (o, e) => findDialog();
}
private void findDialog() {
// Enumerate windows to find the message box
EnumThreadWndProc callback = new EnumThreadWndProc(checkWindow);
if (!EnumThreadWindows(GetCurrentThreadId(), callback, IntPtr.Zero)) mTimer.Enabled = false;
}
private bool checkWindow(IntPtr hWnd, IntPtr lp) {
// Checks if <hWnd> is a dialog
StringBuilder sb = new StringBuilder(260);
GetClassName(hWnd, sb, sb.Capacity);
if (sb.ToString() != "#32770") return true;
// Got it, get the STATIC control that displays the text
IntPtr hCtl = GetDlgItem(hWnd, mCtlId);
SetWindowText(hCtl, mText);
// Done
return true;
}
public void Dispose() {
mTimer.Enabled = false;
}
// P/Invoke declarations
private const int WM_SETFONT = 0x30;
private const int WM_GETFONT = 0x31;
private delegate bool EnumThreadWndProc(IntPtr hWnd, IntPtr lp);
[DllImport("user32.dll")]
private static extern bool EnumThreadWindows(int tid, EnumThreadWndProc callback, IntPtr lp);
[DllImport("kernel32.dll")]
private static extern int GetCurrentThreadId();
[DllImport("user32.dll")]
private static extern int GetClassName(IntPtr hWnd, StringBuilder buffer, int buflen);
[DllImport("user32.dll")]
private static extern IntPtr GetDlgItem(IntPtr hWnd, int item);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern bool SetWindowText(IntPtr hWnd, string txt);
}
Usage:
using (new SetDialogButton(1, "Okay")) {
printDialog1.ShowDialog();
}

Categories