Professional Documents
Culture Documents
Fun With C
Fun With C
Using sockets and C#, you can customize the display of a networked HP Printer.
I wasn’t sure if I should put this article under “Code” or “Humor”, since it contains both.
Ultimately it is much funnier than technical, but full source is included for you to use in your
own environment.
I was studying the C# language one day and thought back to earlier in my career. Back then I
was learning the assembly language for a little 8 bit Hitachi CPU (the 6303) in order to
control a small thermal printer. With the right control codes you could get the printer to
display a custom message on the LCD. Then I was walking by the HP Laser printer in the
office and wondered if I could do the same here. Once I uncovered the Printer Job
Language Reference from HP, I realized this could be fun. After all, who would not get a
kick out of a printer with the message “TOUCH ME” on the LCD?
So I wrote some C# and had everything working. I put a list of messages together for the
program to display at random and setup a scheduled task to execute the assembly every hour.
It didn’t take long for people to notice and start commenting. Some people would check the
printer for a new message on every trip. I remained completely silent as to my knowledge of
the origin of these messages.
At one point I disabled my scheduled task because our chief network admin had made it his
mission to stop the printer hacking. After locking down everything on the printer he possibly
could, the messages still got through, but I figured the joke had run it’s course. Then, when
everyone realized we were going out of business, I turned it back on for a little bit of
amusement everyday.
After the company was sold and I did some consulting for the buyer, I setup the program in
their office too. I had it hit an HP printer nearest the engineering cubicles, where at least one
guy I know slept behind his high cubicle walls every afternoon for an hour. It never raised
many eyebrows that I know of while I was there, but afterwards someone told me they knew
one lady who stopped at the printer every day “because it says such nice things to me”. If I
can brighten one person's day, every day, my mission is accomplished.
The following listing is the code to pull it off. I think the selection of random messages is
quite funny to see on a printer, but feel free to modify these to match your own sense of
humor. To use the program just add the IP address of the printer and a message in quotes, or
type "random" for the message to select from the random message list.
namespace hphack
{
using System;
using System.Text;
using System.Net;
using System.Net.Sockets;
IPEndPoint ipEndPoint;
ipEndPoint = new IPEndPoint( Dns.Resolve(args[0]).AddressList[0], PJL_PORT);
Socket socket;
socket = new Socket(
AddressFamily.InterNetwork,
SocketType.Stream,
ProtocolType.Tcp
);
socket.Connect(ipEndPoint);
byte [] sendData;
string sendString;
sendString = String.Format(
"\x1B%-12345X@PJL RDYMSG DISPLAY = \"{0}\"\r\n\x1B%-12345X\r\n",
message
);
sendData = Encoding.ASCII.GetBytes(sendString);
int result;
result = socket.Send(sendData, sendData.Length, 0);
if(result == 0)
{
Console.WriteLine("Could not send on socket");
}
socket.Close();
Console.WriteLine("Finished\n\n");
return 0;
}
protected static bool ParseArgs(string[] args)
{
if(args.Length != 2)
{
Console.WriteLine(
"HP Display Hack: " +
"hphack printername \"message\" "
);
return false;
}
if(args[1].CompareTo("random") == 0)
{
message = GetRandomMessage();
}
else
{
message = args[1];
}
return true;
}
}
}
#include <iostream>
#include <string>
void main()
{
std::string str;
std::cin>>str;
if(str == "TheCorrectSerialNumber")
std::cout<<"Hello world!!!"<<std::endl;
}
For anyone that has used a memory profiler it's possible that you've come across leaks
related to the System.Windows.Form.ToolStripTextBoxcontrol. If you haven't, here's
a link to a blog post that can shed some light on this issue. It's a very good explanation of
the problem but in summary, the ToolStripTextBox control is hooking
theMicrosoft.Win32.SystemEvents.UserPreferenceChanged repeatedly and unhooking only
once. This is causing leaks because theUserPreferenceChanged event is static and does
not go out of scope for the life of your application. This creates a root reference for any
listeners of that event. Unfortunately, the workaround posted on the linked page did not
seem to work very well for me. After modifying the workaround until it sufficiently suited my
needs I found that the ToolStripTextBox control is not the only class that fails to unhook
from this event causing leaks. For the project I'm working on this was causing a chain
reaction of leaking objects that was fairly significant.
There are three ways to solve this problem that I can see. The first option is that you can try
to predict the nature of the bug in the class that is leaking. Using this information you can
code a very specific solution to this problem. The problem with this is that it requires that
you are correct in your analysis of the problem which is buried in a class that you don't have
the source code for and your targeted solution also works correctly. The second option I see
here is the brute force method. Just unhook the method a bunch of times and hopefully the
problem goes away. If I need to explain what's wrong with that don't waste your time
reading further. The third option I see for solving this problem is to create a generic method
that will look at the listeners of this event, find all references to the leaking object, and
unhook them. This is the approach I have used to solve this problem.
namespace HelperClasses
{
public class UnhookSystemEventUserPreferenceChangedEvent
{
//we'll use a static List to cache a reference to the internal list
of UserPreferenceChangedEvent listeners so that
// we do not need to search for it every time.
static System.Collections.IList _UserPreferenceChangedList = null;
System.Collections.IDictionary dictFieldInfoValue =
oFieldInfoValue as System.Collections.IDictionary;
foreach (object oEvent in dictFieldInfoValue)
{
System.Collections.DictionaryEntry deEvent =
(System.Collections.DictionaryEntry)oEvent;
System.Collections.IList listEventListeners =
deEvent.Value as System.Collections.IList;
//we need to take the first item in the list, get it's
delegate and check the type...
if (listEventListeners.Count > 0 &&
listEventListeners[0] != null)
{
Delegate oDelegate =
GetDelegateFromSystemEventInvokeInfo(listEventListeners[0]);
if (oDelegate is UserPreferenceChangedEventHandler)
{ _UserPreferenceChangedList = listEventListeners; }
}
//if we've found the list, no need to continue searching
if (_UserPreferenceChangedList != null) break;
}
}
//We should unhook using the public method because the internal
implementation of this event is unknown.
// iterating the private internal list is already shady enough
without manipulating it directly...
foreach (UserPreferenceChangedEventHandler itemToRemove in
listDelegatesToRemove)
{ SystemEvents.UserPreferenceChanged -= itemToRemove; }
}
return oReturn;
}
}
}
Pos