Added the main loop.

master
Pacman Ghost 8 years ago
parent 9f7c4b0401
commit 6551257a6d
  1. 13
      MainApp/MainForm.Designer.cs
  2. 47
      MainApp/MainForm.cs
  3. 120
      MainApp/MainForm.resx
  4. 24
      MainApp/MouseDll.cs
  5. 3
      MainApp/MouseInterception.csproj
  6. 87
      MainApp/Program.cs
  7. 24
      MainApp/Utils.cs
  8. 1
      MouseDll/actions.cpp
  9. 21
      MouseDll/api.cpp
  10. 11
      MouseDll/api.hpp
  11. 2
      MouseDll/appProfile.cpp
  12. 10
      MouseDll/core.cpp
  13. 55
      MouseDll/core2.cpp
  14. 2
      MouseDll/device.cpp
  15. 2
      MouseDll/deviceConfig.cpp
  16. 2
      MouseDll/event.cpp
  17. 3
      MouseDll/globals.cpp
  18. 16
      MouseDll/globals.hpp
  19. 4
      MouseDll/mouse.vcproj

@ -28,9 +28,20 @@
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.SuspendLayout();
//
// MainForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF( 6F , 13F );
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size( 284 , 262 );
this.Name = "MainForm";
this.Text = "Form1";
this.Load += new System.EventHandler( this.MainForm_Load );
this.Shown += new System.EventHandler( this.MainForm_Shown );
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler( this.MainForm_FormClosing );
this.ResumeLayout( false );
}
#endregion

@ -6,14 +6,59 @@ using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using System.Diagnostics;
namespace MouseInterception
{
public partial class MainForm : Form
{
private Thread mMouseDllThread ;
private int mExitFlag ;
public MainForm()
{
InitializeComponent();
// initialize the MainForm
InitializeComponent() ;
}
private void MainForm_Load( object sender , EventArgs e )
{
}
private void MainForm_Shown( object sender , EventArgs e )
{
// start the main loop
mMouseDllThread = new Thread(
delegate() {
try
{
mExitFlag = 0 ;
Program.mouseDll.runMainLoop( out mExitFlag ) ;
}
catch( Exception xcptn )
{
// NOTE: We get here if the main loop throws an unhandled exception.
Debug.Assert( false ) ;
Program.onCallback( MouseDll.CBTYPE_FATAL_ERROR , Utils.toUtf8(xcptn.Message) ) ;
}
Invoke( (MethodInvoker)delegate { Close() ; } ) ; // nb: close the main window
}
) ;
mMouseDllThread.Start() ;
}
private void MainForm_FormClosing( object sender , FormClosingEventArgs e )
{
// stop the main loop
if ( mExitFlag == 0 )
{
// NOTE: Setting this flag tells the main loop to end. We cancel the request to close the form, and wait
// for the call to runMainLoop() to return and the worker thread to finish, then we close the form.
mExitFlag = 1 ;
e.Cancel = true ;
}
}
}
}

@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

@ -5,14 +5,20 @@ namespace MouseInterception
{
class MouseDll
{
// IMPORTANT! The definitions here must be kept in sync with their C equivalents in api.hpp
// NOTE: The first place DLL's are loaded from are the application directory.
private const string DLL_NAME = "mouse.dll" ;
public delegate void callbackDelegate( int callbackType , IntPtr pCallbackMsg ) ; // nb: pCallbackMsg is UTF8
public const int CBTYPE_STARTED = 1 ;
public const int CBTYPE_STOPPED = 2 ;
public const int CBTYPE_FATAL_ERROR = 3 ;
[DllImport( @DLL_NAME , CallingConvention=CallingConvention.Cdecl )]
[return: MarshalAs(UnmanagedType.BStr)]
private static extern string open_api( ref DebugConfig.ApiSettings pDebugSettings , int initConsole ) ;
private static extern string open_api( callbackDelegate deleg , ref DebugConfig.ApiSettings pDebugSettings ) ;
[DllImport( @DLL_NAME , CallingConvention=CallingConvention.Cdecl )]
[return: MarshalAs(UnmanagedType.BStr)]
@ -33,11 +39,15 @@ namespace MouseInterception
[return: MarshalAs(UnmanagedType.BStr)]
private static extern string reload_debug_config( ref DebugConfig.ApiSettings pDebugSettings ) ;
public MouseDll( bool initConsole )
[DllImport( @DLL_NAME , CallingConvention=CallingConvention.Cdecl )]
[return: MarshalAs(UnmanagedType.BStr)]
private static extern string run_main_loop( out int pExitFlag ) ;
public MouseDll( callbackDelegate cbDeleg )
{
// open the mouse API
DebugConfig.ApiSettings debugSettings = Program.debugConfig.settings ;
string errorMsg = open_api( ref debugSettings , initConsole?1:0 ) ;
string errorMsg = open_api( cbDeleg , ref debugSettings ) ;
if ( errorMsg != null )
throw new Exception( errorMsg ) ;
reloadConfig() ;
@ -81,5 +91,13 @@ namespace MouseInterception
throw new Exception( errorMsg ) ;
}
public void runMainLoop( out int exitFlag )
{
// run the main loop
string errorMsg = run_main_loop( out exitFlag ) ;
if ( errorMsg != null )
throw new Exception( errorMsg ) ;
}
}
}

@ -60,6 +60,9 @@
<Compile Include="MouseDll.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<EmbeddedResource Include="MainForm.resx">
<DependentUpon>MainForm.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>

@ -2,14 +2,22 @@
using System.IO ;
using System.Runtime.InteropServices ;
using System.Windows.Forms ;
using System.Diagnostics ;
using System.Text ;
namespace MouseInterception
{
static class Program
{
public const string APP_NAME = "udMeeces" ;
private static string mBaseDir ;
private static AppConfig mAppConfig ;
private static DebugConfig mDebugConfig ;
private static AppConfig mAppConfig = null ;
private static DebugConfig mDebugConfig = null ;
private static MouseDll mMouseDll = null ;
private static MainForm mMainForm = null ;
[DllImport( "kernel32.dll" )]
static extern bool AttachConsole( int processId ) ;
@ -24,6 +32,9 @@ namespace MouseInterception
if ( Directory.Exists( baseDir ) )
mBaseDir = baseDir ;
// initialize
bool hasConsole = AttachConsole( ATTACH_PARENT_PROCESS ) ;
try
{
// load the app config
@ -33,40 +44,80 @@ namespace MouseInterception
// load the debug config
fname = getAppRelativePath( "debug.xml" ) ; // FIXME! make this configurable
mDebugConfig = new DebugConfig( fname ) ;
// initialize
if ( hasConsole )
System.Console.WriteLine( "" ) ;
mMouseDll = new MouseDll( new MouseDll.callbackDelegate(onCallback) ) ;
}
catch( Exception xcptn )
{
// FIXME! handle this better
AttachConsole( ATTACH_PARENT_PROCESS ) ;
System.Console.WriteLine( String.Format( ">>> PROGRAM ERROR: {0}" , xcptn ) ) ;
System.Windows.Forms.SendKeys.SendWait( "{ENTER}" ) ;
Application.Exit() ;
string errorMsg = String.Format( "Startup error: {0}" , xcptn.Message ) ;
if ( hasConsole )
{
System.Console.WriteLine( errorMsg ) ;
System.Windows.Forms.SendKeys.SendWait( "{ENTER}" ) ;
}
else
showErrorMsg( errorMsg ) ;
return ;
}
if ( args.Length > 0 )
// run the main program
if ( hasConsole )
{
// run in console mode
AttachConsole( ATTACH_PARENT_PROCESS ) ;
System.Console.WriteLine( "\n>>> Initialized the C# console." ) ; // FIXME!
try
{
MouseDll mouseDll = new MouseDll( true ) ;
int exitFlag = 0 ;
Console.CancelKeyPress += delegate( object sender , ConsoleCancelEventArgs e )
{
// Ctrl+C was pressed - tell the main loop to stop
exitFlag = 1 ;
e.Cancel = true ;
} ;
// run the main loop (this will block until exitFlag is set)
mMouseDll.runMainLoop( out exitFlag ) ;
}
catch( Exception xcptn )
{
System.Console.WriteLine( String.Format( ">>> PROGRAM ERROR: {0}" , xcptn ) ) ;
// NOTE: We get here if the main loop throws an unhandled exception.
Debug.Assert( false ) ;
onCallback( MouseDll.CBTYPE_FATAL_ERROR , Utils.toUtf8(xcptn.Message) ) ;
}
System.Windows.Forms.SendKeys.SendWait( "{ENTER}" ) ;
Application.Exit() ;
}
else
{
// run with a GUI
MouseDll mouseDll = new MouseDll( false ) ;
Application.EnableVisualStyles() ;
Application.SetCompatibleTextRenderingDefault( false ) ;
Application.Run( new MainForm() ) ;
mMainForm = new MainForm() ;
Application.Run( mMainForm ) ;
}
}
public static void onCallback( int callbackType , IntPtr pCallbackMsg )
{
// handle the callback
string callbackMsg = (pCallbackMsg != null) ? Utils.fromUtf8(pCallbackMsg) : "" ;
switch( callbackType )
{
case MouseDll.CBTYPE_STARTED:
case MouseDll.CBTYPE_STOPPED:
//System.Console.WriteLine( callbackMsg ) ;
break ;
case MouseDll.CBTYPE_FATAL_ERROR:
string errorMsg = String.Format( "FATAL ERROR: {0}" , callbackMsg ) ;
System.Console.WriteLine( errorMsg ) ;
if ( Program.mainForm != null )
Program.showErrorMsg( errorMsg ) ;
Application.Exit() ;
break ;
default:
Debug.Assert( false ) ;
System.Console.WriteLine( String.Format( "UNKNOWN CALLBACK {0}: {1}" , callbackType , callbackMsg ) ) ;
break ;
}
}
@ -77,8 +128,14 @@ namespace MouseInterception
return System.IO.Path.GetFullPath( path );
}
public static void showInfoMsg( string msg ) { MessageBox.Show(msg,APP_NAME,MessageBoxButtons.OK,MessageBoxIcon.Information) ; }
public static void showWarningMsg( string msg ) { MessageBox.Show(msg,APP_NAME,MessageBoxButtons.OK,MessageBoxIcon.Warning) ; }
public static void showErrorMsg( string msg ) { MessageBox.Show(msg,APP_NAME,MessageBoxButtons.OK,MessageBoxIcon.Error) ; }
public static AppConfig appConfig { get { return mAppConfig ; } }
public static DebugConfig debugConfig { get { return mDebugConfig ; } }
public static MouseDll mouseDll { get { return mMouseDll ; } }
public static MainForm mainForm { get { return mMainForm ; } }
}
}

@ -1,5 +1,7 @@
using System ;
using System.Runtime.InteropServices ;
using System.Xml ;
using System.Text ;
namespace MouseInterception
{
@ -35,6 +37,28 @@ namespace MouseInterception
}
public static string getXmlAttr( XmlNode xn , string s ) { return getXmlAttr(xn,s,"") ; }
public static IntPtr toUtf8( string val )
{
// convert the string to UTF8
byte[] buf = Encoding.UTF8.GetBytes( val ) ;
Array.Resize( ref buf , buf.Length+1 ) ;
buf[buf.Length-1] = 0 ;
IntPtr pUtf8Val = Marshal.AllocHGlobal( buf.Length ) ;
Marshal.Copy( buf , 0 , pUtf8Val , buf.Length ) ;
return pUtf8Val ;
}
public static string fromUtf8( IntPtr pVal )
{
// convert the string from UTF8
int nChars = 0 ;
while ( Marshal.ReadByte( pVal , nChars ) != 0 )
++ nChars ;
byte[] buf = new byte[ nChars ] ;
Marshal.Copy( pVal , buf , 0 , buf.Length ) ;
return Encoding.UTF8.GetString( buf ) ;
}
public static bool? getKeyState( XmlNode xmlNode , string attrName )
{
// get the key state

@ -1,5 +1,4 @@
#include "actions.hpp"
#include "api.hpp"
#include "globals.hpp"
using namespace std ;

@ -8,12 +8,12 @@ using namespace std ;
// ---------------------------------------------------------------------
extern "C" __declspec(dllexport) BSTR
open_api( const ApiDebugConfig* pDebugConfig , int initConsole )
open_api( PCALLBACKFN pCallbackFn , const ApiDebugConfig* pDebugConfig )
{
// open the API
try
{
openApi( pDebugConfig , initConsole != 0 ) ;
openApi( pCallbackFn , pDebugConfig ) ;
return NULL ;
}
catch ( exception& xcptn )
@ -86,3 +86,20 @@ reload_debug_config( const ApiDebugConfig* pDebugConfig )
return SysAllocString( fromUtf8( MAKE_STRING( xcptn.what() ) ).c_str() ) ;
}
}
// ---------------------------------------------------------------------
extern "C" __declspec(dllexport) BSTR
run_main_loop( int* pExitFlag )
{
// run the main loop
try
{
runMainLoop( pExitFlag ) ;
return NULL ;
}
catch ( exception& xcptn )
{
return SysAllocString( fromUtf8( MAKE_STRING( xcptn.what() ) ).c_str() ) ;
}
}

@ -57,7 +57,12 @@ struct ApiDebugConfig
// IMPORTANT! The definitions here must be kept in sync with their C# equivalents in MouseDll.cs.
extern void openApi( const ApiDebugConfig* pDebugConfig , bool initConsole ) ;
typedef int (__stdcall *PCALLBACKFN)( int callbackType , const char* pCallbackMsg ) ;
#define CBTYPE_STARTED 1
#define CBTYPE_STOPPED 2
#define CBTYPE_FATAL_ERROR 3
extern void openApi( PCALLBACKFN pCallbackFn , const ApiDebugConfig* pDebugConfig ) ;
extern void closeApi() ;
extern void reloadConfig(
@ -70,6 +75,8 @@ extern void reloadConfig(
) ;
extern void reloadDebugConfig( const ApiDebugConfig* pDebugConfig ) ;
extern void runMainLoop( int* pExitFlag ) ;
// ---------------------------------------------------------------------
#endif // API_HPP
#endif // API_HPP

@ -1,5 +1,5 @@
#include "appProfile.hpp"
#include "api.hpp"
#include "globals.hpp"
using namespace std ;

@ -1,4 +1,3 @@
#include "api.hpp"
#include "globals.hpp"
#include "utils.hpp"
@ -7,15 +6,16 @@ using namespace std ;
// ---------------------------------------------------------------------
void
openApi( const ApiDebugConfig* pDebugConfig , bool initConsole )
openApi( PCALLBACKFN pCallbackFn , const ApiDebugConfig* pDebugConfig )
{
// check if we are open
if ( ghInterceptionDll != NULL )
throw runtime_error( "API is already open." ) ;
// initialize
assert( gpCallbackFn == NULL ) ;
gpCallbackFn = pCallbackFn ;
reloadDebugConfig( pDebugConfig ) ;
gEnableConsole = initConsole ;
// load Interception
wchar_t buf[ _MAX_PATH+1 ] ;
@ -48,6 +48,10 @@ closeApi()
// close Interception
FreeLibrary( ghInterceptionDll ) ;
ghInterceptionDll = NULL ;
// clean up
assert( gpCallbackFn != NULL ) ;
gpCallbackFn = NULL ;
}
// ---------------------------------------------------------------------

@ -0,0 +1,55 @@
#include "globals.hpp"
using namespace std ;
// --- LOCAL DATA ------------------------------------------------------
// local functions:
static void doRunMainLoop( int* pExitFlag ) ;
// ---------------------------------------------------------------------
void
runMainLoop( int* pExitFlag )
{
assert( pExitFlag != NULL ) ;
// initialize
*pExitFlag = 0 ;
assert( gpCallbackFn != NULL ) ;
(*gpCallbackFn)( CBTYPE_STARTED , "Main loop started." ) ;
// run the main loop
try
{
doRunMainLoop( pExitFlag ) ;
(*gpCallbackFn)( CBTYPE_STOPPED , "Main loop stopped." ) ;
}
catch ( exception& xcptn )
{
(*gpCallbackFn)( CBTYPE_FATAL_ERROR , MAKE_CSTRING(xcptn.what()) ) ;
}
catch ( ... )
{
(*gpCallbackFn)( CBTYPE_FATAL_ERROR , "Unknown error." ) ;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
static void
doRunMainLoop( int* pExitFlag )
{
assert( pExitFlag != NULL ) ;
// run the main loop
for ( ; ; )
{
cout << "zzz..." << endl ;
Sleep( 1*1000 ) ;
// check if we should exit
if ( *pExitFlag != 0 )
break ;
}
}

@ -1,5 +1,5 @@
#include "device.hpp"
#include "api.hpp"
#include "globals.hpp"
using namespace std ;

@ -1,5 +1,5 @@
#include "deviceConfig.hpp"
#include "api.hpp"
#include "globals.hpp"
using namespace std ;

@ -1,5 +1,5 @@
#include "event.hpp"
#include "api.hpp"
#include "globals.hpp"
using namespace std ;

@ -11,7 +11,8 @@ HMODULE ghInterceptionDll = NULL ;
DeviceTable gDeviceTable ;
DeviceConfigTable gDeviceConfigTable ;
bool gEnableConsole = false ;
PCALLBACKFN gpCallbackFn = NULL ;
wstring gLogFilename ;
ofstream gLogFile ;

@ -7,6 +7,7 @@
#include "device.hpp"
#include "deviceConfig.hpp"
#include "api.hpp"
#include "utils.hpp"
// ---------------------------------------------------------------------
@ -19,24 +20,21 @@ extern DeviceTable gDeviceTable ;
typedef IntPtrMap<DeviceConfig> DeviceConfigTable ;
extern DeviceConfigTable gDeviceConfigTable ;
extern PCALLBACKFN gpCallbackFn ;
// ---------------------------------------------------------------------
#define LOG_MSG( msg ) \
{ \
if ( gEnableConsole || gLogFile.is_open() ) \
{ \
string _buf_ = MAKE_STRING( msg ) ; \
if ( gEnableConsole ) \
cout << _buf_ << endl ; \
if ( gLogFile.is_open() ) \
gLogFile << _buf_ << endl ; \
} \
string _buf_ = MAKE_STRING( msg ) ; \
cout << _buf_ << endl ; \
if ( gLogFile.is_open() ) \
gLogFile << _buf_ << endl ; \
}
extern void initLogging( const wchar_t* ) ;
extern bool isLoggingEnabled( const std::string& ) ;
extern bool gEnableConsole ;
extern std::wstring gLogFilename ;
extern std::ofstream gLogFile ;

@ -192,6 +192,10 @@
RelativePath=".\core.cpp"
>
</File>
<File
RelativePath=".\core2.cpp"
>
</File>
<File
RelativePath=".\device.cpp"
>

Loading…
Cancel
Save