• Welcome to Valhalla Legends Archive.
 
Menu

Show posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.

Show posts Menu

Messages - Dyndrilliac

#1
Java Programming / Detecting Keyboard Events
March 12, 2012, 09:33 PM
I'm having trouble detecting keyboard events in my program. I'm implementing KeyListener in my JFrame, and I'm registering it in my constructor, but I don't get any hits on my JOptionPanes when in Debug Mode despite banging on the keyboard. What am I doing wrong? My end goal in this regard is to enable the Enter key to activate a mouse click on the Throw button when pressed, and add keyboard shortcuts to the menu.


package games.dicebag.gui;

import games.dicebag.*;
import java.awt.*;
import java.awt.event.*;
import java.text.SimpleDateFormat;
import java.util.*;
import javax.swing.*;
import javax.swing.text.*;

public class DiceBagDemo extends JFrame implements ActionListener, KeyListener
{
private static final int WINDOW_WIDTH  = 800;
private static final int WINDOW_HEIGHT = 600;

private boolean   bDebugMode  = false;
private String    strFilePath = null;
private JButton   btnThrow    = null;
private JComboBox txtInput    = null;
private JTextPane txtOutput   = null;

private SimpleDateFormat dateFormat = new SimpleDateFormat("MM.dd.yyyy hh:mm:ss a z");

public static void main(String[] args)
{
DiceBagDemo diceBag = null;
int intDebugChoice = JOptionPane.showConfirmDialog(null, "Do you wish to activate debug mode?", "Debug Mode", JOptionPane.YES_NO_OPTION);

if (intDebugChoice == JOptionPane.YES_OPTION)
{
diceBag = new DiceBagDemo(true);
}
else if (intDebugChoice == JOptionPane.NO_OPTION)
{
diceBag = new DiceBagDemo(false);
}
else
{
return;
}

diceBag.setVisible(true);
}

public DiceBagDemo(boolean bDebugMode)
{
super("Dice Bag");
this.bDebugMode = bDebugMode;
this.setSize(new Dimension(WINDOW_WIDTH, WINDOW_HEIGHT));
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setResizable(false);
this.setLocationRelativeTo(null);
this.addKeyListener(this);
this.drawGUI();
}

public void actionPerformed(ActionEvent e)
{
String actionCommand = e.getActionCommand();

if (this.bDebugMode)
{
JOptionPane.showMessageDialog(this, "What: " + actionCommand + "\nWhere: " + e.getSource().getClass().getSimpleName() + " (" + e.getSource().getClass().getCanonicalName() + ")" + "\nWhen: " + this.getDateTimeStamp(), "Event Occurred", JOptionPane.INFORMATION_MESSAGE);
}

if (actionCommand.equals("Throw"))
{
if (((String)this.txtInput.getSelectedItem() != null) && (checkInput((String)this.txtInput.getSelectedItem())))
{
if (this.bDebugMode)
{
JOptionPane.showMessageDialog(this, "Input: " + (String)this.txtInput.getSelectedItem() + "\nWhen: " + this.getDateTimeStamp(), "Input Received", JOptionPane.INFORMATION_MESSAGE);
}

this.processInput((String)this.txtInput.getSelectedItem());

if (this.txtInput.getSelectedIndex() == -1)
{
this.txtInput.addItem((String)this.txtInput.getSelectedItem());
}

this.txtInput.setSelectedIndex(-1);
this.txtInput.grabFocus();
}
else
{
JOptionPane.showMessageDialog(this, "Improperly formatted input. Please check your input and try again.\n", "Input Invalid", JOptionPane.ERROR_MESSAGE);

this.txtInput.setSelectedIndex(-1);
this.txtInput.grabFocus();
}
}

if (actionCommand.equals("Clear"))
{
this.resetOutput();
this.txtInput.grabFocus();
}

if (actionCommand.equals("Open"))
{
this.fileOperation(actionCommand);
this.txtInput.grabFocus();
}

if (actionCommand.equals("Save"))
{
this.fileOperation(actionCommand);
this.txtInput.grabFocus();
}
}

public void keyPressed(KeyEvent e)
{
if (this.bDebugMode)
{
JOptionPane.showMessageDialog(this, "What: " + e.getKeyCode() + "\nWhere: " + e.getSource().getClass().getSimpleName() + " (" + e.getSource().getClass().getCanonicalName() + ")" + "\nWhen: " + this.getDateTimeStamp(), "Key Pressed", JOptionPane.INFORMATION_MESSAGE);
}
}
public void keyTyped(KeyEvent e)
{
if (this.bDebugMode)
{
JOptionPane.showMessageDialog(this, "What: " + e.getKeyCode() + "\nWhere: " + e.getSource().getClass().getSimpleName() + " (" + e.getSource().getClass().getCanonicalName() + ")" + "\nWhen: " + this.getDateTimeStamp(), "Key Typed", JOptionPane.INFORMATION_MESSAGE);
}
}

public void keyReleased(KeyEvent e)
{
if (this.bDebugMode)
{
JOptionPane.showMessageDialog(this, "What: " + e.getKeyCode() + "\nWhere: " + e.getSource().getClass().getSimpleName() + " (" + e.getSource().getClass().getCanonicalName() + ")" + "\nWhen: " + this.getDateTimeStamp(), "Key Released", JOptionPane.INFORMATION_MESSAGE);
}
}

private void drawGUI()
{
Container contentPane = this.getContentPane();
contentPane.setLayout(new BorderLayout());

JMenu fileMenu = new JMenu("File");
JMenuItem m;

m = new JMenuItem("Clear");
m.addActionListener(this);
fileMenu.add(m);

m = new JMenuItem("Open");
m.addActionListener(this);
fileMenu.add(m);

m = new JMenuItem("Save");
m.addActionListener(this);
fileMenu.add(m);

JMenuBar mBar = new JMenuBar();
mBar.add(fileMenu);
this.setJMenuBar(mBar);

this.txtOutput = new JTextPane();
this.resetOutput();
this.txtOutput.setFocusable(false);
this.txtOutput.setEditable(false);
this.txtOutput.setFont(new Font("Lucida Console", Font.PLAIN, 14));
JScrollPane outputPanel = new JScrollPane(this.txtOutput);

JPanel inputPanel = new JPanel();
inputPanel.setLayout(new FlowLayout());

this.txtInput = new JComboBox();
this.txtInput.setFont(new Font("Lucida Console", Font.PLAIN, 14));
this.txtInput.setEditable(true);
this.txtInput.setPreferredSize(new Dimension(600, 20));
this.txtInput.addActionListener(this);
inputPanel.add(this.txtInput);

this.btnThrow = new JButton("Throw");
this.btnThrow.setPreferredSize(new Dimension(100, 20));
this.btnThrow.addActionListener(this);
inputPanel.add(this.btnThrow);

contentPane.add(outputPanel, BorderLayout.CENTER);
contentPane.add(inputPanel, BorderLayout.SOUTH);
}

private void fileOperation(String strType)
{
int intChoice = 0;

JFileChooser fc = new JFileChooser();

if (strType.equals("Open"))
{
intChoice = fc.showOpenDialog(this);
}
else if (strType.equals("Save"))
{
intChoice = fc.showSaveDialog(this);
}
else
{
return;
}

if (intChoice == JFileChooser.APPROVE_OPTION)
{
try
{
this.strFilePath = fc.getSelectedFile().getCanonicalPath();

if (strType.equals("Open"))
{
FileIO.openOutputFile(this.txtOutput, this.strFilePath);
}
else if (strType.equals("Save"))
{
FileIO.saveOutputFile(this.txtOutput, this.strFilePath);
}
else
{
return;
}

if (this.bDebugMode)
{
JOptionPane.showMessageDialog(this, "File Path: " + this.strFilePath + "\nWhen: " + this.getDateTimeStamp(), "File Accessed", JOptionPane.INFORMATION_MESSAGE);
}
}
catch(Exception err)
{
JOptionPane.showMessageDialog(this, "Unable to access file.\nSource File: " + err.getStackTrace()[0].getFileName() + "\nLine Number: " + err.getStackTrace()[0].getLineNumber(), "Internal Error", JOptionPane.ERROR_MESSAGE);
err.printStackTrace();
}
}
}

private boolean checkInput(String strInput)
{
return strInput.matches("[0-9]+d[0-9]+");
}

private void processInput(String strInput)
{
String[] strParamArray   = strInput.split("d");
int[]    intResultsArray = DiceBag.throwDice(Integer.parseInt(strParamArray[0]), Integer.parseInt(strParamArray[1]));

StringBuilder output = new StringBuilder();

for (int i = 0; i < intResultsArray.length-1; i++) { output.append(intResultsArray[i] + " "); }

this.appendOutput(Color.GRAY, "Results: ", Color.RED, output.toString() + "\n", Color.GRAY, "Sum:     ", Color.BLUE, intResultsArray[intResultsArray.length-1] + "\n\n");
}

private void appendOutput(Object... oArgs)
{
if ((oArgs.length % 2) != 0)
{
JOptionPane.showMessageDialog(this, "appendOutput(Object[] oArgs) recieved a bad list of arguments.\n", "Internal Error", JOptionPane.ERROR_MESSAGE);
return;
}

this.appendOutput(this.txtOutput, Color.BLACK, "[" + this.getDateTimeStamp() + "]\n");

for (int i = 0; i < oArgs.length; i += 2) { this.appendOutput(this.txtOutput, (Color)oArgs[i], oArgs[i+1].toString()); }
}

private void appendOutput(JTextPane o, Color c, String s)
{
StyleContext sc = StyleContext.getDefaultStyleContext();

AttributeSet aset = sc.addAttribute(SimpleAttributeSet.EMPTY, StyleConstants.Foreground, c);

try
{
o.getDocument().insertString(o.getDocument().getLength(), s, aset);
}
catch (BadLocationException e)
{
JOptionPane.showMessageDialog(this, "BadLocationException thrown in appendOutput(JTextPane o, Color c, String s).\nSource File: " + e.getStackTrace()[0].getFileName() + "\nLine Number: " + e.getStackTrace()[0].getLineNumber(), "Internal Error", JOptionPane.ERROR_MESSAGE);
e.printStackTrace();
}
}

private void resetOutput()
{
StyledEditorKit sek = new StyledEditorKit();
this.txtOutput.setEditorKit(sek);
this.txtOutput.setDocument(sek.createDefaultDocument());
}

private String getDateTimeStamp()
{
return this.dateFormat.format(new Date());
}
}


Edit:

FileIO static class:

package games.dicebag.gui;

import java.io.*;
import javax.swing.JTextPane;
import javax.swing.text.Document;

public class FileIO
{
public static final void openOutputFile(JTextPane pane, String strFilePath)
{
ObjectInputStream inputStream = null;

try
{
inputStream = new ObjectInputStream(new FileInputStream(strFilePath));
pane.setDocument((Document)inputStream.readObject());
inputStream.close();
}
catch(Exception e)
{
System.out.println("Reading from the file failed.\n");
e.printStackTrace();
}
}

public static final void saveOutputFile(JTextPane pane, String strFilePath)
{
ObjectOutputStream outputStream = null;

try
{
outputStream = new ObjectOutputStream(new FileOutputStream(strFilePath));
outputStream.writeObject(pane.getDocument());
outputStream.close();
}
catch(Exception e)
{
System.out.println("Writing to the file failed.\n");
e.printStackTrace();
}
}
}


DiceBag static class:

package games.dicebag;

import java.util.Random;

public class DiceBag
{
public static final int[] throwDice(int intNumberOfDice, int intNumberOfSides)
{
int[] intResultsArray = new int[intNumberOfDice+1];

for (int i = 0; i < intNumberOfDice; i++) { intResultsArray[i] = getRandomInteger(1, intNumberOfSides, true); }

intResultsArray[intNumberOfDice] = getSumFromIntegerArray(intResultsArray);

return intResultsArray;
}

private static final int getRandomInteger(int intMin, int intMax, boolean bIsRangeInclusive)
{
Random rand = new Random(System.nanoTime());

if (bIsRangeInclusive)
{
return (rand.nextInt(intMax - intMin + 1) + intMin);
}
else
{
return (rand.nextInt(intMax - intMin) + intMin);
}
}

private static final int getSumFromIntegerArray(int[] ArrayOfIntegers)
{
int intSum = 0;

for (int i = 0; i < ArrayOfIntegers.length; i++) { intSum += ArrayOfIntegers[i]; }

return intSum;
}
}
#2
I was looking around at WinDbg extensions recently and found SDbgExt on Skywing's blog, and wanted to try it out. I'm using Visual Studio 2008 Professional Edition and the first thing that it did when I opened his project files was convert them to the new format. After that, I tried building it and everything was mostly fine, although it claims the "ntnative.h" header referenced in "precompiled.h" doesn't exist. Where do I get this header file from (and any lib's it requires)? I have the Windows Platform SDK installed, is it only available in the DDK or WDK?
#3
Edit: Wow, I just realized I totally forgot to tell the linker I even _had_ a *.def file... :facepalm:

So I've been putting the finishing touches on a new plugin feature for a project of mine, but GetProcAddress keeps failing when it shouldn't (at least, as far as I can tell). The system I'm using to implement the plugin functionality is as follows. My main project DLL loads all the dll's in the plugins directory (which is determined on-the-fly) and keeps track of their handles. Then, once loaded into the same address space, the plugins access the main DLL and retrieve a handle to it's base address. Then, they call GetProcAddress to obtain the addresses for some of it's API functions, the most vital of which allows the plugin to register data (such as the name of the plugin, it's author, it's version, and some function pointers) with my application so that it can send the plugins notifications of events (such as when a key has been pressed on the keyboard).

Here's the code for the plugins calls to GetProcAddress:/*
Grab addresses for API's we can expect to be available.
*/

const HMODULE EXODUS_HANDLE = GetModuleHandleA("EXODUS.DLL");
if (!EXODUS_HANDLE) {
ReportError("Error! Could not locate the module handle for Exodus!");
return;
}

char TempBuffer[MAX_PATH] = {NULL};

ExRegPluginInfo = (EXREGPLUGININFO)GetProcAddress(EXODUS_HANDLE,"ExRegPluginInfo");
if (!ExRegPluginInfo) {
wsprintfA(TempBuffer,"Error! Could not locate the expected API: ExRegPluginInfo\nError Code: %u",GetLastError());
ReportError(TempBuffer);
return;
}
WriteMemory = (WRITEMEMORY)GetProcAddress(EXODUS_HANDLE,"WriteMemory");
if (!WriteMemory) {
wsprintfA(TempBuffer,"Error! Could not locate the expected API: WriteMemory\nError Code: %u",GetLastError());
ReportError(TempBuffer);
return;
}
WriteDetour = (WRITEDETOUR)GetProcAddress(EXODUS_HANDLE,"WriteDetour");
if (!WriteDetour) {
wsprintfA(TempBuffer,"Error! Could not locate the expected API: WriteDetour\nError Code: %u",GetLastError());
ReportError(TempBuffer);
return;
}
InjectDLL = (INJECTDLL)GetProcAddress(EXODUS_HANDLE,"InjectDLL");
if (!InjectDLL) {
wsprintfA(TempBuffer,"Error! Could not locate the expected API: InjectDLL\nError Code: %u",GetLastError());
ReportError(TempBuffer);
return;
}

/*
Register the plugin's information with Exodus here.
*/

ExRegPluginInfo(&myEXPIS);
My typedefs and function pointer stuff:/*
Function pointer type definitions (delegate types for you .NET programmers).
*/

typedef bool (WINAPI *EXREGPLUGININFO)(EXPLUGINFOSTRUCT*);
typedef DWORD (WINAPI *WRITEDETOUR)(const DWORD,const DWORD,const DWORD,const bool);
typedef DWORD (WINAPI *WRITEMEMORY)(const DWORD,const DWORD,const DWORD);
typedef bool (WINAPI *INJECTDLL)(PCSTR,PCSTR,const BYTE);

/*
Function pointers (instances of delegates).
*/

static EXREGPLUGININFO ExRegPluginInfo;
static WRITEDETOUR WriteDetour;
static WRITEMEMORY WriteMemory;
static INJECTDLL InjectDLL;
I've tried identifying the function by both name and ordinal, and I still get the same result regardless. Here is how I've got the API exposed (Exodus.def):LIBRARY "Exodus"
EXPORTS
InjectDLL @1
WriteDetour @2
WriteMemory @3
ExRegPluginInfo @4
And here is what they're prototypes look like:extern "C" bool WINAPI ExRegPluginInfo(EXPLUGINFOSTRUCT *pEXPIS);
extern "C" DWORD WINAPI WriteDetour(const DWORD dwSource,const DWORD dwDestination,const DWORD dwPadSize,const bool bType);
extern "C" DWORD WINAPI WriteMemory(const DWORD dwDestination,const DWORD dwSource,const DWORD dwDataLength);
extern "C" bool WINAPI InjectDLL(PCSTR szFilename, PCSTR szIdentifier, const BYTE bFlag);
My structure (EXPLUGINFOSTRUCT) is exactly the same for both the main DLL and my test plugin:struct EXPLUGINFOSTRUCT {
PCSTR szPluginName; // plugin name
PCSTR szPluginAuthor; // plugin author
BYTE  dwVersion[3];  // The version is three bytes in this order [major version - minor version - revision]
DWORD (WINAPI *fxnKeyboardEvent)(int,WPARAM,LPARAM); // Keyboard event func ptr
};
#4
First, let's get my hardware out of the way.

Antenna: Click me!
TV Tuner: Lumanate TVT8 Wave NTSC/ATSC External USB2.0 (couldn't find a link for it)

So, I have an ancient (circa 1991 or earlier) LXI analog TV set in my "office". I have my antenna hooked up to a 1i/2o coaxial splitter with one output cable going into the TV and the other going into my external TV Tuner. There are five channels that I'm interested in getting in fairly good quality (my local channels basically, NBC/WB/ABC/FOX/CBS). My TV gets all 5 channels in as good a quality as you could expect from an analog TV hooked up to an indoor antenna. My TV Tuner on the other hand, for some reason appears to only be receiving the last two (FOX and CBS). When I say receiving, I mean FOX and CBS come in perfectly but it claims the signal is so bad for the others that all it produces is a black screen (which is BS, because I have my TV on right now getting the exact same signal and they are all fine). My drivers are up to date, and I am using Windows Media Center (Vista 32-bit) to view the signal.

I have come to the conclusion that the fault has to be with either the tuner or Windows Media Center. Does anyone have any suggestions as to how I might pinpoint which of the two is the cause of my issue, or any solutions?
#5
Well, that's why I ended up feeling so silly. I was trying to invoke nmake via the standard Windows command prompt mechanism, which lacked the Visual Studio environment settings in their entirety; Once I loaded up the command prompt mechanism that comes as part of Visual Studio, it was simply a matter of navigating to the source directory and inputting "nmake".
#6
Could you be more specific? The documentation for the Detours package simply states:
QuoteTo build the libraries and the sample applications, type "nmake".
And I double checked the MSDN documentation for nmake, and tried the following:
Quotenmake /f "C:\Program Files\Microsoft Research\Detours Express 2.1\makefile"
Where "makefile" is the name of the supplied makefile. 'cd' fails (nmake fatal-error U1077) and returns an exit code of 0x01.

So, I still have no idea what is wrong.

Edit: Wow, I feel really stupid now. I examined things closer and realized the problem, and you were absolutely right; it was clear-cut user error. Thanks for your assistance Kp. I got it to work very quickly once I realized my mistake.
#7
So, I downloaded and installed the latest version (2.1) of Microsoft's Detours Express Package (hyperlink), and as I anticipated I am to build the libs myself with nmake. However, I try to do so, and it claims that it is up to date and does nothing, to say the least of which is not the behavior I was expecting. I'm on Vista, and made sure to give the command prompt administrative privileges...

I installed the files to "C:\Program Files\Microsoft Research\Detours Express 2.1", and the command I am issuing is:
Quotenmake "C:\Program Files\Microsoft Research\Detours Express 2.1"
I am using the copy of nmake.exe that comes with Microsoft Visual C++ 2008 Express Edition.

The exact output I get is:
QuoteC:\Program Files\Microsoft Visual Studio 9.0\VC\bin>nmake "C:\Program Files\Micr
osoft Research\Detours Express 2.1"

Microsoft (R) Program Maintenance Utility Version 9.00.21022.08
Copyright (C) Microsoft Corporation.  All rights reserved.

'"C:\Program Files\Microsoft Research\Detours Express 2.1"' is up-to-date
Can anyone tell me what I am not doing, or failing to understand? I have not had issues with this sort of task before.
#8
Ok this code works absolutely perfectly, except there is some god awful flickering going on.void DrawCoords(const long X, const long Y) {

ZeroMemory(Buffer,sizeof(Buffer));
HDC MyHDC = GetDC(NULL);
RECT MyRect;
MyRect.top = Y-5;
MyRect.left = X+5;
MyRect.bottom = Y-40;
MyRect.right = X+40;
InvalidateRect(NULL, &MyRect,false);
SetBkColor(MyHDC,RGB(0,0,0));
SetTextColor(MyHDC,RGB(255,0,0));
sprintf_s<256>(Buffer,"{X: %i,Y: %i}",X,Y);
TextOutA(MyHDC,(X+10),(Y-10),Buffer,strlen(Buffer));
ReleaseDC(NULL, MyHDC);

}

LRESULT CALLBACK MouseProc(int nCode, WPARAM wParam, LPARAM lParam) {

if (nCode == HC_ACTION) {
MOUSEHOOKSTRUCT MyMHS = *(MOUSEHOOKSTRUCT*)lParam;
DrawCoords(MyMHS.pt.x,MyMHS.pt.y);
}

return (CallNextHookEx(hMseHook,nCode,wParam,lParam));

}
Keep in mind im using global mouse hook. Is there any way to get the window thread id of the parent hwnd for the process with only the process handle or process id?
#9
Recently I have been trying to print the mouse cursor's coordinates just below and to the right of the cursor and have it update in real time, regardless of what windows have focus. I am using GDI to draw the text on screen, and a Mouse Hook to get the coordinates.

This code seems to work, save for one minor glitch:#define VC_EXTRALEAN

#include <windows.h>
#include <stdio.h>

void MyInit();
void MyCleanUp();
void DrawCoords(const long X, const long Y);

static char    Buffer[256];
static HDC     MyHDC;

void MyInit() {

MyHDC = GetDC(NULL);

}

void MyCleanUp() {

ReleaseDC(NULL, MyHDC);

}

void DrawCoords(const long X, const long Y) {

ZeroMemory(Buffer,sizeof(Buffer));
SetBkColor(MyHDC,RGB(0,0,0));
SetTextColor(MyHDC,RGB(255,0,0));
sprintf_s<256>(Buffer,"[X: %i, Y: %i]",X,Y);
TextOutA(MyHDC,(X+10),(Y-10),Buffer,strlen(Buffer));

}
The glitch is that the old text strings aren't being removed automatically, and as you move the cursor eventually the screen gets covered in output. I have tried getting the device context just before drawing and releasing it right after, but it didn't work. Here is how/where I am calling the Drawing fxn:LRESULT CALLBACK MouseProc(int nCode, WPARAM wParam, LPARAM lParam) {

MOUSEHOOKSTRUCT MyMHS = *(MOUSEHOOKSTRUCT*)lParam;

DrawCoords(MyMHS.pt.x,MyMHS.pt.y);

return (CallNextHookEx(hMseHook,nCode,wParam,lParam));

}
I need a way to clear away old ouput prior to drawing new ouput. Any suggestions?
#10
Well, I wasn't trying to import MessageBox - it is simply what MSDN used for their example. I just don't understand why the documentation at MSDN is so flawed. How is it that they got the C linkage specifier to work, and I couldn't, with the same code? At any rate, thanks for the suggestion. I will try leaving out the "C", as per your example. I may just go back to the system I was using, including windows.h and simply utilizing it in non-managed code. But, I've been trying to avoid all those loader-lock scenarios MSDN talks about, and figured that making my assemblies pure MSIL would do the trick and be even more helpful down the road.
#11
I've been porting some old C++ code to C++/CLI, and with that comes porting vast amounts of the Win32 Platform SDK. I instantly started having issues performing the most basic tasks according to the MSDN documentation. Example:[DllImport("User32.dll", EntryPoint = "FindWindow")]
extern "C" IntPtr FindWindow(String^ lpszWndClass,
String^ lpszWndName);
The compiler has this to say:
Quoteerror C2526: 'FindWindow' : C linkage function cannot return C++ class 'System::IntPtr'
1>        c:\windows\microsoft.net\framework\v2.0.50727\mscorlib.dll : see declaration of 'System::IntPtr'
But that's exactly what MSDN claims you must do! The example MSDN provided is as follows:using namespace System::Runtime::InteropServices;
[DllImport("user32.dll")]
    extern "C" IntPtr MessageBox(int hWnd, String* pText,
    String* pCaption unsigned int uType);
I've also found that according to the compiler, '*' is an illegal indirection type for types of System::String. Is the documentation just flat-out wrong and untrustworthy, or am I missing something?
#12
I added if (MyKeyboardHook == 0) {
DbgPrint("wtf", NULL);
}
Right before the call to UnhookWindowsHookEx, but still nothing. Someone else suggested creating the Hook in a new thread and allowing it to idle, and it will automatically be unset when the thread terminates - but that still wouldn't explain why my hotkeys don't currently work, even though the only thing that appears to be wrong is the call to unhook...
#13
I'm working on an injectable DLL hack with a global keyboard hook, and although SetWindowsHookEx() returns as expected, when it comes time to unhook something fails, and GetLastError returns 0. I've attached only the relevant code, but I don't get any errors or warnings. I'm using VC++ 2008 Express Edition. Just say so if you need me to post the rest.

Core.cpp:#include <windows.h>
#include <stdio.h>

// ...

BYTE StatsHackToggle = 0;
BYTE GoldHackToggle  = 0;

HHOOK MyKeyboardHook = 0;
DWORD bRet = 0, ErrCode = 0;

LRESULT CALLBACK KeyboardProc(int code, WPARAM wParam, LPARAM lParam);

// ...

BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) {
switch (dwReason) {
case DLL_PROCESS_ATTACH:
// Register our keyboard hook.
MyKeyboardHook = SetWindowsHookEx(WH_KEYBOARD, (HOOKPROC)&KeyboardProc, hInstance, NULL);
if (MyKeyboardHook == NULL) { // Checking for errors...
DbgPrint("The call to SetWindowsHookEx() failed, [MyKeyboardHook] is null.", GetLastError());
}
break;
case DLL_PROCESS_DETACH:
// Unregister our keyboard hook.
bRet = UnhookWindowsHookEx(MyKeyboardHook);
if (bRet == NULL) { // Checking for errors...
DbgPrint("The call to UnhookWindowsHookEx() failed, [bRet] is null.", GetLastError());
}
break;
default:
break;
    }

return (TRUE);
}

LRESULT CALLBACK KeyboardProc(int code, WPARAM wParam, LPARAM lParam) {
if (code != HC_ACTION) {
return (CallNextHookEx(MyKeyboardHook, code, wParam, lParam));
}

// This is where the conditions for certain keys
// being pressed go. Use the virtual key-codes
// for the keys you wish to hook. For more information,
// do a search on "Virtual key-codes on MSDN.
switch (wParam) {
case VK_PRIOR: // StatsHack
if (StatsHackToggle == 0) { // on toggle
DbgPrint("StatsHack Toggle [ON]!", NULL);
bRet = PlaceDetour(ptrStatsHack,(DWORD)&StatsHack,NULL);
if (bRet == NULL) {
DbgPrint("The call to PlaceDetour() failed during toggling of StatsHack.", NULL);
StatsHackToggle = 0;
}

StatsHackToggle = 1;
} else { // off toggle
DbgPrint("StatsHack Toggle [OFF]!", NULL);
bRet = WriteMemory(ptrStatsHack,StatsHackOldData,6);
if (bRet == NULL) {
DbgPrint("The call to WriteMemory() failed during toggling of StatsHack.", NULL);
StatsHackToggle = 1;
}

StatsHackToggle = 0;
}
break;
case VK_NEXT: // GoldHack
if (GoldHackToggle == 0) { // on toggle
DbgPrint("GoldHack Toggle [ON]!", NULL);
bRet = PlaceDetour(ptrGoldHack,(DWORD)&GoldHack,6);
if (bRet == NULL) {
DbgPrint("The call to PlaceDetour() failed during the [ON] toggle of GoldHack.", NULL);
GoldHackToggle = 0;
}

GoldHackToggle = 1;
} else { // off toggle
DbgPrint("GoldHack Toggle [OFF]!", NULL);
bRet = WriteMemory(ptrGoldHack,GoldHackOldData,6);
if (bRet == NULL) {
DbgPrint("The call to WriteMemory() failed during the [OFF] toggle of GoldHack.", NULL);
GoldHackToggle = 1;
}

GoldHackToggle = 0;
}
break;
default:
break;
}

// Call the next hook in the system's hook chain.
return (CallNextHookEx(MyKeyboardHook, code, wParam, lParam));
}
I would appreciate it if someone could tell me what I've done wrong...
#14
I never said I was going to use the queue. Besides, I need to know and understand the methodology behind creating a queue of my own.
#15
Edit: I feel rather silly now. After lots of thinking, I realized that I had forgotten to append the carot to my class name when retrieving a newly initialized instance. I also realized that my constructor call was ill-formed. The code has been fixed and re-pasted if anyone wants to use the queue.

I'm not sure quite how to describe the bug I'm facing - perhaps I should show you my output.
QuoteValue: SimpleQueue
Value: String
Value: 34.6
Press any key to continue . . .
The first value being displayed seems to have come from absolutely nowhere. SimpleQueue (as you'll see below) is the class name for an object in my program. However, what I don't know is how it found it's way to the output screen. There isn't any reference to the string in my code, and nothing in particular jumps out as the cause (to me). I would appreciate anyone with suggestions on how to best solve the issue.

Here's the code (this is all of it, I have no idea what might be causing the anomaly).
    using namespace System;

    public ref class SimpleQueue {

        private:

            ref struct Node {

                Node^   p;
                Node^   n;
                Object^ o;

                Node() {
                    this->n = nullptr;
                    this->p = nullptr;
                    this->o = nullptr;
                }

                Node(Node^ nn) {
                    this->n = nn->n;
                    this->p = nn->p;
                    this->o = nn->o;
                }

                Node(Node^ np, Node^ nn, Object^ oo) {
                    this->n = nn;
                    this->p = np;
                    this->o = oo;
                }

            };

            Int16 size;
            Node^ head;
            Node^ tail;

        public:

            SimpleQueue() {
                this->Clear();
            }

            void Clear() {
                this->head = gcnew Node(nullptr, tail, nullptr);
                this->tail = gcnew Node(head, nullptr, nullptr);
                this->size = 0;
            }

            void Push(Object^ o) {
                if (this->size >= (Int16::MaxValue - 1)) {
                    throw gcnew Exception("Queue is full.");
                }

                if (this->Empty) {
                    Node^ t = gcnew Node(head, tail, o);
                    this->head->n = t;
                    this->tail->p = t;
                    this->size = 1;
                } else {
                    Node^ g = gcnew Node(head, head->n, o);
                    Node^ k = head->n;
                    k->p = g;
                    this->head->n = g;
                    this->size++;
                }
            }

            Object^ Pop() {
                if (this->Empty) {
                    throw gcnew Exception("Queue is empty.");
                }

                Object^ o = tail->p->o;

                Node^ temp = gcnew Node(tail->p);
                temp = temp->p;
                temp->n = tail;
                tail->p = temp;

                return (o);
            }

            property Int16 Size {
                Int16 get() {
                    return (this->size);
                }
            }

            property bool Empty {
                bool get() {
                    return (this->size == 0);
                }
            }
    };

    int main() {

        SimpleQueue^ sq = gcnew SimpleQueue;

        sq->Push("String");
        sq->Push(34.6);

        long x = sq->Size;

        for (long i = 0; i < x; i++) {
            Console::WriteLine("Value: {0}", sq->Pop());
        }

        return 0;
    }