diff --git a/Growl Extras/PhonyBalloony/AppContext.cs b/Growl Extras/PhonyBalloony/AppContext.cs new file mode 100644 index 0000000..9ac45b4 --- /dev/null +++ b/Growl Extras/PhonyBalloony/AppContext.cs @@ -0,0 +1,82 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Windows.Forms; + +namespace GrowlExtras.PhonyBalloony +{ + class AppContext : ApplicationContext, IDisposable + { + private WndProcReader wpr; + private SystemBalloonIntercepter sbi; + + public AppContext() + { + this.wpr = new WndProcReader(WndProc); + Microsoft.Win32.SystemEvents.SessionEnding += new Microsoft.Win32.SessionEndingEventHandler(SystemEvents_SessionEnding); + + // this is just a useful addition for debugging. this allows us to stop the process without logging of or shutting down the computer +#if DEBUG + Microsoft.Win32.SystemEvents.SessionSwitch += new Microsoft.Win32.SessionSwitchEventHandler(SystemEvents_SessionSwitch); +#endif + } + + public void Start() + { + Stop(); + + this.sbi = new SystemBalloonIntercepter(this.wpr.Handle); + sbi.Start(); + } + + public void Stop() + { + if (sbi != null) + { + this.sbi.Stop(); + this.sbi = null; + } + } + + private void WndProc(ref Message m) + { + /* this is for handling intercepted system balloon messages */ + if (this.sbi != null) + sbi.ProcessWindowMessage(ref m); + } + + void SystemEvents_SessionEnding(object sender, Microsoft.Win32.SessionEndingEventArgs e) + { + Stop(); + } + + void SystemEvents_SessionSwitch(object sender, Microsoft.Win32.SessionSwitchEventArgs e) + { + if(e.Reason == Microsoft.Win32.SessionSwitchReason.SessionUnlock) + Stop(); + } + + #region IDisposable Members + + protected override void Dispose(bool disposing) + { + if (disposing) + { + try + { + Microsoft.Win32.SystemEvents.SessionEnding -= new Microsoft.Win32.SessionEndingEventHandler(SystemEvents_SessionEnding); +#if DEBUG + Microsoft.Win32.SystemEvents.SessionSwitch -= new Microsoft.Win32.SessionSwitchEventHandler(SystemEvents_SessionSwitch); +#endif + this.Stop(); + } + catch + { + // suppress + } + } + } + + #endregion + } +} diff --git a/Growl Extras/PhonyBalloony/PhonyBalloony.csproj b/Growl Extras/PhonyBalloony/PhonyBalloony.csproj new file mode 100644 index 0000000..b8d5a9b --- /dev/null +++ b/Growl Extras/PhonyBalloony/PhonyBalloony.csproj @@ -0,0 +1,95 @@ + + + Debug + AnyCPU + 8.0.50727 + 2.0 + {34A423AD-4D5F-42AB-9339-DFB5FD717642} + WinExe + Properties + GrowlExtras.PhonyBalloony + PhonyBalloony + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + AnyCPU + + + + False + ..\..\Growl Connectors\NET\libraries\Growl.Connector.dll + + + False + ..\..\Growl Connectors\NET\libraries\Growl.CoreLibrary.dll + + + + + + + + + + + + + + ResXFileCodeGenerator + Resources.Designer.cs + Designer + + + True + Resources.resx + True + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + True + Settings.settings + True + + + + + + + PreserveNewest + + + + + + PreserveNewest + + + PreserveNewest + + + + + \ No newline at end of file diff --git a/Growl Extras/PhonyBalloony/PhonyBalloony.sln b/Growl Extras/PhonyBalloony/PhonyBalloony.sln new file mode 100644 index 0000000..2b29a4e --- /dev/null +++ b/Growl Extras/PhonyBalloony/PhonyBalloony.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PhonyBalloony", "PhonyBalloony.csproj", "{34A423AD-4D5F-42AB-9339-DFB5FD717642}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {34A423AD-4D5F-42AB-9339-DFB5FD717642}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {34A423AD-4D5F-42AB-9339-DFB5FD717642}.Debug|Any CPU.Build.0 = Debug|Any CPU + {34A423AD-4D5F-42AB-9339-DFB5FD717642}.Release|Any CPU.ActiveCfg = Release|Any CPU + {34A423AD-4D5F-42AB-9339-DFB5FD717642}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Growl Extras/PhonyBalloony/Program.cs b/Growl Extras/PhonyBalloony/Program.cs new file mode 100644 index 0000000..9b7a623 --- /dev/null +++ b/Growl Extras/PhonyBalloony/Program.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Windows.Forms; + +namespace GrowlExtras.PhonyBalloony +{ + static class Program + { + /// + /// The main entry point for the application. + /// + [STAThread] + static void Main() + { + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + AppContext context = new AppContext(); + using (context) + { + context.Start(); + Application.Run(context); + context.Stop(); + } + } + } +} \ No newline at end of file diff --git a/Growl Extras/PhonyBalloony/Properties/AssemblyInfo.cs b/Growl Extras/PhonyBalloony/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..1e58f85 --- /dev/null +++ b/Growl Extras/PhonyBalloony/Properties/AssemblyInfo.cs @@ -0,0 +1,33 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("PhonyBalloony")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("element code project")] +[assembly: AssemblyProduct("PhonyBalloony")] +[assembly: AssemblyCopyright("Copyright © element code project 2010")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("d6ec9a72-c9a2-45c4-8960-2c0401d48677")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Growl Extras/PhonyBalloony/Properties/Resources.Designer.cs b/Growl Extras/PhonyBalloony/Properties/Resources.Designer.cs new file mode 100644 index 0000000..ec7c4b1 --- /dev/null +++ b/Growl Extras/PhonyBalloony/Properties/Resources.Designer.cs @@ -0,0 +1,84 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:2.0.50727.3082 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace GrowlExtras.PhonyBalloony.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "2.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("GrowlExtras.PhonyBalloony.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + internal static System.Drawing.Bitmap error { + get { + object obj = ResourceManager.GetObject("error", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap info { + get { + object obj = ResourceManager.GetObject("info", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap warning { + get { + object obj = ResourceManager.GetObject("warning", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + } +} diff --git a/Growl Extras/PhonyBalloony/Properties/Resources.resx b/Growl Extras/PhonyBalloony/Properties/Resources.resx new file mode 100644 index 0000000..80c5cce --- /dev/null +++ b/Growl Extras/PhonyBalloony/Properties/Resources.resx @@ -0,0 +1,130 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + ..\Resources\error.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\info.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\warning.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + \ No newline at end of file diff --git a/Growl Extras/PhonyBalloony/Properties/Settings.Designer.cs b/Growl Extras/PhonyBalloony/Properties/Settings.Designer.cs new file mode 100644 index 0000000..fce8b59 --- /dev/null +++ b/Growl Extras/PhonyBalloony/Properties/Settings.Designer.cs @@ -0,0 +1,26 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:2.0.50727.3082 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace GrowlExtras.PhonyBalloony.Properties { + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "8.0.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default { + get { + return defaultInstance; + } + } + } +} diff --git a/Growl Extras/PhonyBalloony/Properties/Settings.settings b/Growl Extras/PhonyBalloony/Properties/Settings.settings new file mode 100644 index 0000000..abf36c5 --- /dev/null +++ b/Growl Extras/PhonyBalloony/Properties/Settings.settings @@ -0,0 +1,7 @@ + + + + + + + diff --git a/Growl Extras/PhonyBalloony/README.txt b/Growl Extras/PhonyBalloony/README.txt new file mode 100644 index 0000000..896ab45 --- /dev/null +++ b/Growl Extras/PhonyBalloony/README.txt @@ -0,0 +1,29 @@ +PhonyBalloony +------------------------------ + +PhonyBalloony is a process that runs in the background and intercepts Windows +system balloon messages and re-routes them through Growl for Windows. + +Since PhonyBalloony intercepts system-level messages and has no UI, the best +way to use PhonyBalloony is to have it automatically start when you log on to +Windows. + +1. Unzip the following files into a folder: + PhonyBalloony.exe + Growl.Connector.dll + Growl.CoreLibrary.dll + SystemBalloonIntercepter.dll + +2. Drag PhonyBalloony.exe to your 'Startup' folder + Start Button > Programs > Startup + +If you want to start PhonyBalloony for your current session manually, just +double-click the PhonyBalloony.exe file. There is no UI or tray icon, but the +PhonyBalloony process will show up in Task Manager. + +PhonyBalloony automatically shuts itself down when you log off or shutdown +your computer. If Growl is not running or is closed while PhonyBalloony is +running, it will revert to using the system balloons. + +NOTE: PhonyBalloony has not been tested on 64-bit systems and may not work +properly. \ No newline at end of file diff --git a/Growl Extras/PhonyBalloony/Resources/error.png b/Growl Extras/PhonyBalloony/Resources/error.png new file mode 100644 index 0000000..d7301e5 Binary files /dev/null and b/Growl Extras/PhonyBalloony/Resources/error.png differ diff --git a/Growl Extras/PhonyBalloony/Resources/info.png b/Growl Extras/PhonyBalloony/Resources/info.png new file mode 100644 index 0000000..cde124d Binary files /dev/null and b/Growl Extras/PhonyBalloony/Resources/info.png differ diff --git a/Growl Extras/PhonyBalloony/Resources/warning.png b/Growl Extras/PhonyBalloony/Resources/warning.png new file mode 100644 index 0000000..303e809 Binary files /dev/null and b/Growl Extras/PhonyBalloony/Resources/warning.png differ diff --git a/Growl Extras/PhonyBalloony/SystemBalloonIntercepter.cs b/Growl Extras/PhonyBalloony/SystemBalloonIntercepter.cs new file mode 100644 index 0000000..45bfd74 --- /dev/null +++ b/Growl Extras/PhonyBalloony/SystemBalloonIntercepter.cs @@ -0,0 +1,292 @@ +using System; +using System.Runtime.InteropServices; +using System.Windows.Forms; +using Growl.Connector; + +namespace GrowlExtras.PhonyBalloony +{ + public delegate void HookReplacedEventHandler(); + + public class SystemBalloonIntercepter : Hook + { + public const int WM_COPYDATA = 74; + + private IntPtr MSG_REPLACED; // value will come from RegisterWindowMessage + private const string MSG_NAME_REPLACED = "GFW_HOOK_CALLWNDPROC_REPLACED"; + + // icon flags are mutually exclusive and take only the lowest 2 bits + public const int NIIF_NONE = 0x00000000; + public const int NIIF_INFO = 0x00000001; + public const int NIIF_WARNING = 0x00000002; + public const int NIIF_ERROR = 0x00000003; + public const int NIIF_USER = 0x00000004; + + private static System.Drawing.Image IMAGE_INFO = Properties.Resources.info; + private static System.Drawing.Image IMAGE_ERROR = Properties.Resources.error; + private static System.Drawing.Image IMAGE_WARNING = Properties.Resources.warning; + + public event HookReplacedEventHandler HookReplaced; + + private bool registered; + private bool hooked; + private IntPtr handle; + private GrowlConnector growl; + private Growl.Connector.Application app; + private Growl.Connector.NotificationType ntBalloon; + private System.Timers.Timer timer; + + public SystemBalloonIntercepter(IntPtr handle) : base(handle) + { + this.handle = handle; + + this.app = new Growl.Connector.Application("Windows"); + this.app.Icon = IMAGE_INFO; + this.ntBalloon = new NotificationType("balloon", "System Balloons"); + this.growl = new GrowlConnector(); + this.growl.EncryptionAlgorithm = Cryptography.SymmetricAlgorithmType.PlainText; + + this.timer = new System.Timers.Timer(10 * 1000); // ten seconds + this.timer.AutoReset = false; + this.timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed); + } + + void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) + { + TrySetHook(); + } + + ~SystemBalloonIntercepter() + { + this.Stop(); + } + + protected override void OnStart() + { + // Retreive the message IDs that we'll look for in WndProc + MSG_REPLACED = RegisterWindowMessage(MSG_NAME_REPLACED); + + TrySetHook(); + } + + protected override void OnStop() + { + UninitializeCallWndProcHook(); + } + + private bool Register() + { + if (growl.IsGrowlRunning()) + { + this.growl.Register(this.app, new NotificationType[] { this.ntBalloon }); + this.registered = true; + } + return this.registered; + } + + private void TrySetHook() + { + bool ok = Register(); + + // Start the hook + if (ok && !this.hooked) + { + this.hooked = true; + InitializeCallWndProcHook(IntPtr.Zero, _Handle); + } + + // try again later if Growl is not yet running + if (!ok) + { + this.timer.Start(); + } + } + + public override void ProcessWindowMessage(ref Message m) + { + if (m.Msg == WM_COPYDATA) + { + if ((int)m.WParam == 97) + { + if (growl.IsGrowlRunning()) + { + COPYDATASTRUCT cds = new COPYDATASTRUCT(); + cds = (COPYDATASTRUCT)m.GetLParam(typeof(COPYDATASTRUCT)); + //Utility.WriteLine(cds.cbData); + //Utility.WriteLine(cds.dwData); + //Utility.WriteLine(cds.lpData); + + TRAYINFO ti = new TRAYINFO(); + ti = (TRAYINFO)Marshal.PtrToStructure(cds.lpData, typeof(TRAYINFO)); + //Console.WriteLine("_title: " + ti.nid.szInfoTitle); + //Console.WriteLine("_text: " + ti.nid.szInfo); + + // get the icon + // it is important to check these in descending order since the 'flags' are not mutually exclusive + System.Drawing.Image image = IMAGE_INFO; // default to INFO + if (IsFlagSet(ti.nid.dwInfoFlags, NIIF_USER) && ti.nid.hIcon != IntPtr.Zero) + { + System.Drawing.Icon icon = System.Drawing.Icon.FromHandle(ti.nid.hIcon); + using (icon) + { + image = icon.ToBitmap(); + } + } + else if (IsFlagSet(ti.nid.dwInfoFlags, NIIF_ERROR)) + image = IMAGE_ERROR; + else if (IsFlagSet(ti.nid.dwInfoFlags, NIIF_WARNING)) + image = IMAGE_WARNING; + // flag 1 == IMAGE_INFO anyway + + if (!String.IsNullOrEmpty(ti.nid.szInfo)) + OnSystemBalloonIntercepted(ti.nid.szInfoTitle, ti.nid.szInfo, image); + + // zero == success + m.Result = IntPtr.Zero; + } + else + { + // non-zero == growl not running + // the hook will show the standard system balloon instead + m.Result = new IntPtr(int.MaxValue); + } + } + } + else if (m.Msg == (int) MSG_REPLACED) + { + if (HookReplaced != null) + HookReplaced(); + } + } + + private void OnSystemBalloonIntercepted(string title, string text, System.Drawing.Image icon) + { + if (String.IsNullOrEmpty(title)) title = "[no title]"; + if (String.IsNullOrEmpty(text)) text = "[no text]"; + + Notification notification = new Notification(this.app.Name, this.ntBalloon.Name, String.Empty, title, text); + notification.Icon = icon; + this.growl.Notify(notification); + } + + private bool IsFlagSet(int val, int flag) + { + int result = (val & flag); + return (result == flag); + } + + private static void InitializeCallWndProcHook(IntPtr threadID, IntPtr DestWindow) + { + if (IntPtr.Size == 8) + InitializeCallWndProcHook64(threadID, DestWindow); + else + InitializeCallWndProcHook32(threadID, DestWindow); + } + + private static void UninitializeCallWndProcHook() + { + if (IntPtr.Size == 8) + UninitializeCallWndProcHook64(); + else + UninitializeCallWndProcHook32(); + } + + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + struct TRAYINFO + { + public IntPtr x; + public IntPtr y; + public NOTIFYICONDATA nid; + } + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + struct NOTIFYICONDATA + { + public System.Int32 cbSize; // DWORD + public System.IntPtr hWnd; // HWND + public System.Int32 uID; // UINT + public System.Int32 uFlags; // UINT + public System.Int32 uCallbackMessage; // UINT + public System.IntPtr hIcon; // HICON + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] + public System.String szTip; // char[128] + public System.Int32 dwState; // DWORD + public System.Int32 dwStateMask; // DWORD + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] + public System.String szInfo; // char[256] + public System.Int32 uTimeoutOrVersion; // UINT + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)] + public System.String szInfoTitle; // char[64] + public System.Int32 dwInfoFlags; // DWORD + //GUID guidItem; > IE 6 + } + + + [StructLayout(LayoutKind.Sequential)] + private struct COPYDATASTRUCT + { + public IntPtr dwData; + public IntPtr cbData; + public IntPtr lpData; + } + + // Functions imported from our unmanaged DLL (32-bit) + [DllImport("SystemBalloonIntercepter.dll", EntryPoint = "InitializeCallWndProcHook")] + private static extern void InitializeCallWndProcHook32(IntPtr threadID, IntPtr DestWindow); + [DllImport("SystemBalloonIntercepter.dll", EntryPoint = "UninitializeCallWndProcHook")] + private static extern void UninitializeCallWndProcHook32(); + + // Functions imported from our unmanaged DLL (64-bit) + [DllImport("SystemBalloonIntercepter64.dll", EntryPoint = "InitializeCallWndProcHook")] + private static extern void InitializeCallWndProcHook64(IntPtr threadID, IntPtr DestWindow); + [DllImport("SystemBalloonIntercepter64.dll", EntryPoint = "UninitializeCallWndProcHook")] + private static extern void UninitializeCallWndProcHook64(); + + // Win32 API methods + [DllImport("user32.dll")] + private static extern IntPtr RegisterWindowMessage(string lpString); + } + + public abstract class Hook + { + protected bool _IsActive = false; + protected IntPtr _Handle; + + protected Hook(IntPtr Handle) + { + _Handle = Handle; + } + + public void Start() + { + if (!_IsActive) + { + _IsActive = true; + OnStart(); + } + } + + public void Stop() + { + if (_IsActive) + { + OnStop(); + _IsActive = false; + } + } + + ~Hook() + { + Stop(); + } + + public bool IsActive + { + get { return _IsActive; } + } + + protected abstract void OnStart(); + protected abstract void OnStop(); + public abstract void ProcessWindowMessage(ref System.Windows.Forms.Message m); + } +} \ No newline at end of file diff --git a/Growl Extras/PhonyBalloony/SystemBalloonIntercepter.dll b/Growl Extras/PhonyBalloony/SystemBalloonIntercepter.dll new file mode 100644 index 0000000..3adc20d Binary files /dev/null and b/Growl Extras/PhonyBalloony/SystemBalloonIntercepter.dll differ diff --git a/Growl Extras/PhonyBalloony/SystemBalloonIntercepter64.dll b/Growl Extras/PhonyBalloony/SystemBalloonIntercepter64.dll new file mode 100644 index 0000000..cd4c299 Binary files /dev/null and b/Growl Extras/PhonyBalloony/SystemBalloonIntercepter64.dll differ diff --git a/Growl Extras/PhonyBalloony/WndProcReader.cs b/Growl Extras/PhonyBalloony/WndProcReader.cs new file mode 100644 index 0000000..20e2f29 --- /dev/null +++ b/Growl Extras/PhonyBalloony/WndProcReader.cs @@ -0,0 +1,32 @@ +using System; +using System.Windows.Forms; + +namespace GrowlExtras.PhonyBalloony +{ + class WndProcReader : NativeWindow + { + public delegate void WndProcDelegate(ref Message m); + + CreateParams cp = new CreateParams(); + WndProcDelegate del; + + public WndProcReader(WndProcDelegate del) + { + this.del = del; + + // Create the actual window + this.CreateHandle(cp); + } + + protected override void WndProc(ref Message m) + { + // let the delegate process the message + if (this.del != null) this.del(ref m); + + // if the delegate didnt set the result, let the message pass through to the base method. + // otherwise, we assume the delegate set the result to an error value and return that instead. + if(m.Result == IntPtr.Zero) + base.WndProc(ref m); + } + } +} diff --git a/Growl Extras/SystemBalloonIntercepter/DllMain.cpp b/Growl Extras/SystemBalloonIntercepter/DllMain.cpp new file mode 100644 index 0000000..8cd3d1b --- /dev/null +++ b/Growl Extras/SystemBalloonIntercepter/DllMain.cpp @@ -0,0 +1,41 @@ +#include "stdafx.h" +#include +#include + +// +// Capture the application instance of this module to pass to +// hook initialization. +// +extern HINSTANCE g_appInstance; + +BOOL APIENTRY DllMain(HINSTANCE hinstDLL, DWORD ul_reason_for_call, LPVOID lpReserved) +{ + switch (ul_reason_for_call) + { + case DLL_PROCESS_ATTACH: + // + // Capture the application instance of this module to pass to + // hook initialization. + // + if (g_appInstance == NULL) + { + g_appInstance = hinstDLL; + } + break; + + case DLL_THREAD_ATTACH: + break; + + case DLL_THREAD_DETACH: + break; + + case DLL_PROCESS_DETACH: + break; + + default: + OutputDebugString("That's weird.\n"); + break; + } + + return TRUE; +} diff --git a/Growl Extras/SystemBalloonIntercepter/GlobalCbtHook.vcproj b/Growl Extras/SystemBalloonIntercepter/GlobalCbtHook.vcproj new file mode 100644 index 0000000..58d446d --- /dev/null +++ b/Growl Extras/SystemBalloonIntercepter/GlobalCbtHook.vcproj @@ -0,0 +1,598 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Growl Extras/SystemBalloonIntercepter/SystemBalloonIntercepter.cpp b/Growl Extras/SystemBalloonIntercepter/SystemBalloonIntercepter.cpp new file mode 100644 index 0000000..277c8c8 --- /dev/null +++ b/Growl Extras/SystemBalloonIntercepter/SystemBalloonIntercepter.cpp @@ -0,0 +1,109 @@ +#include "stdafx.h" +#include +#include "SystemBalloonIntercepter.h" + +// Store the application instance of this module to pass to hook initialization. This is set in DLLMain(). +HINSTANCE g_appInstance = NULL; + +UINT msg_unsubclass = 0; +UINT msg_replaced = 0; +HHOOK hookCallWndProc = NULL; +LRESULT CALLBACK CallWndProcHookCallback(UINT code, WPARAM wparam, LPARAM lparam); +LRESULT CALLBACK SubclassWndProc(HWND hwnd, UINT code, WPARAM wparam, LPARAM lparam); +LRESULT oldWndProc; +UINT WM_UNSUBCLASS = 0; +BOOL isSubclassed = false; + +bool InitializeCallWndProcHook(DWORD threadID, HWND destination) +{ + if (g_appInstance == NULL) + { + return false; + } + + msg_unsubclass = RegisterWindowMessage("GFW_HOOK_UNSUBCLASS"); + msg_replaced = RegisterWindowMessage("GFW_HOOK_CALLWNDPROC_REPLACED"); + HWND dstWnd = (HWND)GetProp(GetDesktopWindow(), "GFW_HOOK_HWND_CALLWNDPROC"); + if (dstWnd != NULL) + { + PostMessage(dstWnd, msg_replaced, 0, 0); + } + dstWnd = destination; + SetProp(GetDesktopWindow(), "GFW_HOOK_HWND_CALLWNDPROC", dstWnd); + + hookCallWndProc = SetWindowsHookEx(WH_CALLWNDPROC, (HOOKPROC)CallWndProcHookCallback, g_appInstance, threadID); + return hookCallWndProc != NULL; +} + +void UninitializeCallWndProcHook() +{ + // stop subclassing + HWND trayHwnd = FindWindow("Shell_TrayWnd", NULL); + SendMessageW(trayHwnd, msg_unsubclass, 0, 0); + RemoveProp(GetDesktopWindow(), "GFW_HOOK_HWND_CALLWNDPROC"); + + // unhook + if (hookCallWndProc != NULL) + { + UnhookWindowsHookEx(hookCallWndProc); + hookCallWndProc = NULL; + } +} + + +LRESULT CALLBACK CallWndProcHookCallback(UINT code, WPARAM wparam, LPARAM lparam) +{ + if(WM_UNSUBCLASS == 0) WM_UNSUBCLASS = RegisterWindowMessage("GFW_HOOK_UNSUBCLASS"); + + if (code >= 0) + { + PCWPSTRUCT pCwpStruct = (PCWPSTRUCT)lparam; + HWND hwnd = pCwpStruct->hwnd; + HWND trayHwnd = FindWindow("Shell_TrayWnd", NULL); + + if((LONG_PTR) hwnd == (LONG_PTR) trayHwnd) + { + if(!isSubclassed) + { + isSubclassed = true; + oldWndProc = (LRESULT) SetWindowLongPtr(trayHwnd, GWLP_WNDPROC, (LONG_PTR) SubclassWndProc); + } + } + } + + return CallNextHookEx(hookCallWndProc, code, wparam, lparam); +} + +LRESULT CALLBACK SubclassWndProc(HWND hwnd, UINT code, WPARAM wparam, LPARAM lparam) +{ + LRESULT r = 0; + BOOL handled = false; + + if(code == WM_COPYDATA) + { + PCOPYDATASTRUCT cpData = (PCOPYDATASTRUCT) lparam; + + if (cpData->dwData == 1) + { + DWORD trayCommand = *(DWORD *) (((BYTE *)cpData->lpData) + 4); + PNOTIFYICONDATA iconData = (PNOTIFYICONDATA) (((BYTE *)cpData->lpData) + 8); + + BOOL isBalloon = (iconData->uFlags & NIF_INFO); + if(isBalloon) + { + HWND dstWnd = (HWND)GetProp(GetDesktopWindow(), "GFW_HOOK_HWND_CALLWNDPROC"); + r = SendMessageW(dstWnd, WM_COPYDATA, 97, lparam); + if(r == 0) handled = true; + } + } + } + else if(code == WM_UNSUBCLASS) + { + SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG) oldWndProc); + isSubclassed = false; + handled = true; + } + + if(!handled) r = CallWindowProc((WNDPROC)oldWndProc, hwnd, code, wparam, lparam); + return r; +} \ No newline at end of file diff --git a/Growl Extras/SystemBalloonIntercepter/SystemBalloonIntercepter.def b/Growl Extras/SystemBalloonIntercepter/SystemBalloonIntercepter.def new file mode 100644 index 0000000..30cf456 --- /dev/null +++ b/Growl Extras/SystemBalloonIntercepter/SystemBalloonIntercepter.def @@ -0,0 +1,5 @@ +LIBRARY SystemHookCore + +EXPORTS + InitializeCallWndProcHook + UninitializeCallWndProcHook diff --git a/Growl Extras/SystemBalloonIntercepter/SystemBalloonIntercepter.h b/Growl Extras/SystemBalloonIntercepter/SystemBalloonIntercepter.h new file mode 100644 index 0000000..c16bdd4 --- /dev/null +++ b/Growl Extras/SystemBalloonIntercepter/SystemBalloonIntercepter.h @@ -0,0 +1,19 @@ +#pragma once + +namespace HookCoreErrors +{ + namespace SetCallBack + { + const int SUCCESS = 1; + const int ALREADY_SET = -2; + const int NOT_IMPLEMENTED = -3; + const int ARGUMENT_ERROR = -4; + } + namespace FilterMessage + { + const int SUCCESS = 1; + const int FAILED = -2; + const int NOT_IMPLEMENTED = -3; + } +} + diff --git a/Growl Extras/SystemBalloonIntercepter/SystemBalloonIntercepter.rc b/Growl Extras/SystemBalloonIntercepter/SystemBalloonIntercepter.rc new file mode 100644 index 0000000..88b2b98 --- /dev/null +++ b/Growl Extras/SystemBalloonIntercepter/SystemBalloonIntercepter.rc @@ -0,0 +1,102 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,0 + PRODUCTVERSION 1,0,0,0 + FILEFLAGSMASK 0x17L +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", "element code project" + VALUE "FileDescription", "SystemBalloonIntercepter" + VALUE "FileVersion", "1, 0, 0, 0" + VALUE "InternalName", "SystemBalloonIntercepter" + VALUE "LegalCopyright", "" + VALUE "OriginalFilename", "SystemBalloonIntercepter.dll" + VALUE "ProductName", "Growl for Windows System Balloon Intercepter" + VALUE "ProductVersion", "1, 0, 0, 0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/Growl Extras/SystemBalloonIntercepter/SystemBalloonIntercepter.sln b/Growl Extras/SystemBalloonIntercepter/SystemBalloonIntercepter.sln new file mode 100644 index 0000000..6fc8b9e --- /dev/null +++ b/Growl Extras/SystemBalloonIntercepter/SystemBalloonIntercepter.sln @@ -0,0 +1,37 @@ + +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SystemBalloonIntercepter", "GlobalCbtHook.vcproj", "{A558485A-58F7-4748-A0BE-EE1BB01732F5}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{EA1A9905-09FF-4FF4-9F74-3C6D4FF61C3D}" + ProjectSection(SolutionItems) = preProject + save.txt = save.txt + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Documentation|Win32 = Documentation|Win32 + Documentation|x64 = Documentation|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {A558485A-58F7-4748-A0BE-EE1BB01732F5}.Debug|Win32.ActiveCfg = Debug|Win32 + {A558485A-58F7-4748-A0BE-EE1BB01732F5}.Debug|Win32.Build.0 = Debug|Win32 + {A558485A-58F7-4748-A0BE-EE1BB01732F5}.Debug|x64.ActiveCfg = Debug|x64 + {A558485A-58F7-4748-A0BE-EE1BB01732F5}.Debug|x64.Build.0 = Debug|x64 + {A558485A-58F7-4748-A0BE-EE1BB01732F5}.Documentation|Win32.ActiveCfg = Documentation|Win32 + {A558485A-58F7-4748-A0BE-EE1BB01732F5}.Documentation|Win32.Build.0 = Documentation|Win32 + {A558485A-58F7-4748-A0BE-EE1BB01732F5}.Documentation|x64.ActiveCfg = Documentation|x64 + {A558485A-58F7-4748-A0BE-EE1BB01732F5}.Documentation|x64.Build.0 = Documentation|x64 + {A558485A-58F7-4748-A0BE-EE1BB01732F5}.Release|Win32.ActiveCfg = Release|Win32 + {A558485A-58F7-4748-A0BE-EE1BB01732F5}.Release|Win32.Build.0 = Release|Win32 + {A558485A-58F7-4748-A0BE-EE1BB01732F5}.Release|x64.ActiveCfg = Release|x64 + {A558485A-58F7-4748-A0BE-EE1BB01732F5}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Growl Extras/SystemBalloonIntercepter/resource.h b/Growl Extras/SystemBalloonIntercepter/resource.h new file mode 100644 index 0000000..4666cd8 --- /dev/null +++ b/Growl Extras/SystemBalloonIntercepter/resource.h @@ -0,0 +1,15 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by SystemBalloonIntercepter.rc +// + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/Growl Extras/SystemBalloonIntercepter/save.txt b/Growl Extras/SystemBalloonIntercepter/save.txt new file mode 100644 index 0000000..5f3829a --- /dev/null +++ b/Growl Extras/SystemBalloonIntercepter/save.txt @@ -0,0 +1,196 @@ +#include "stdafx.h" +#include +#include "SystemBalloonIntercepter.h" + +HHOOK hookCallWndProc = NULL; +HHOOK hookCBT = NULL; +HHOOK hookShell = NULL; + +// Store the application instance of this module to pass to hook initialization. This is set in DLLMain(). +HINSTANCE g_appInstance = NULL; + + +typedef void (CALLBACK *HookProc)(int code, WPARAM w, LPARAM l); + +static LRESULT CALLBACK CallWndProcHookCallback(int code, WPARAM wparam, LPARAM lparam); +static LRESULT CALLBACK CBTHookCallback(int code, WPARAM wparam, LPARAM lparam); +static LRESULT CALLBACK ShellHookCallback(int code, WPARAM wparam, LPARAM lparam); + + + +/* +static LRESULT FAR PASCAL SubClassFunc(HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam); +static FARPROC lpfnOldWndProc; +LONG x = SetWindowLongW(trayHwnd, GWL_WNDPROC, (DWORD) func); +*/ + + + + + + +bool InitializeCallWndProcHook(int threadID, HWND destination) +{ + if (g_appInstance == NULL) + { + return false; + } + + UINT msg_sysnot = RegisterWindowMessage("GFW_HOOK_INTERCEPT_SYSNOT"); + UINT msg_replaced = RegisterWindowMessage("GFW_HOOK_CALLWNDPROC_REPLACED"); + HWND dstWnd = (HWND)GetProp(GetDesktopWindow(), "GFW_HOOK_HWND_CALLWNDPROC"); + if (dstWnd != NULL) + { + PostMessage(dstWnd, msg_replaced, 0, 0); + } + dstWnd = destination; + SetProp(GetDesktopWindow(), "GFW_HOOK_HWND_CALLWNDPROC", dstWnd); + + PostMessage(dstWnd, msg_sysnot, 0, 0); + + // Uncomment these if you want to play with them + //hookCBT = SetWindowsHookEx(WH_CBT, (HOOKPROC)CBTHookCallback, g_appInstance, threadID); + //hookShell = SetWindowsHookEx(WH_SHELL, (HOOKPROC)ShellHookCallback, g_appInstance, threadID); + + hookCallWndProc = SetWindowsHookEx(WH_CALLWNDPROC, (HOOKPROC)CallWndProcHookCallback, g_appInstance, threadID); + return hookCallWndProc != NULL; +} + +void UninitializeCallWndProcHook() +{ + if (hookCallWndProc != NULL) + UnhookWindowsHookEx(hookCallWndProc); + hookCallWndProc = NULL; + + if (hookCBT != NULL) + UnhookWindowsHookEx(hookCBT); + hookCBT = NULL; + + if (hookShell != NULL) + UnhookWindowsHookEx(hookShell); + hookShell = NULL; +} + +static LRESULT CALLBACK CallWndProcHookCallback(int code, WPARAM wparam, LPARAM lparam) +{ + if (code >= 0) + { + UINT msg_sysnot = RegisterWindowMessage("GFW_HOOK_INTERCEPT_SYSNOT"); + UINT msg_replaced = RegisterWindowMessage("GFW_HOOK_CALLWNDPROC_REPLACED"); + HWND dstWnd = (HWND)GetProp(GetDesktopWindow(), "GFW_HOOK_HWND_CALLWNDPROC"); + + PCWPSTRUCT pCwpStruct = (PCWPSTRUCT)lparam; + HWND hwnd = pCwpStruct->hwnd; + HWND trayHwnd = FindWindow("Shell_TrayWnd", NULL); + + if((UINT) hwnd == (UINT) trayHwnd && pCwpStruct->message == WM_COPYDATA) + { + PCOPYDATASTRUCT cpData = (PCOPYDATASTRUCT)pCwpStruct->lParam; + + if (cpData->dwData == 1) + { + DWORD trayCommand = *(DWORD *) (((BYTE *)cpData->lpData) + 4); + PNOTIFYICONDATA iconData = (PNOTIFYICONDATA) (((BYTE *)cpData->lpData) + 8); + + BOOL isBalloon = (iconData->uFlags & NIF_INFO); + if(isBalloon) + { + /* Attempt #1 to hide the system balloon - but it is not yet visible at this point, so no dice + NOTIFYICONDATA nid; + ZeroMemory(&nid, NOTIFYICONDATA_V2_SIZE); + nid.cbSize = NOTIFYICONDATA_V2_SIZE; + nid.hWnd = iconData->hWnd; + nid.uID = iconData->uID; + nid.hIcon = iconData->hIcon; + nid.uFlags = NIF_INFO; + nid.szInfo[0] = 0; + Shell_NotifyIcon(NIM_MODIFY, &nid); + */ + + /* Attempt #2 to hide the system balloon - same result as above for the same reason + iconData->szInfo[0] = 0; + Shell_NotifyIcon(NIM_MODIFY, iconData); + */ + + // THIS IS THE LINE THAT SENDS A MESSAGE TO GROWL TO TRIGGER THE NOTIFICATION + // IT ONLY WORKS ON GROWL BUILDS THAT SUPPORT SYSTEM BALLOONS (WHICH IS JUST MY LOCAL BUILD AT THE MOMENT) + pCwpStruct->message = WM_USER + 44; + + return SendMessageW(dstWnd, WM_COPYDATA, 97, (LPARAM)cpData); + } + } + } + } + + return CallNextHookEx(hookCallWndProc, code, wparam, lparam); +} + +static LRESULT CALLBACK CBTHookCallback(int code, WPARAM wparam, LPARAM lparam) +{ + if(code > 0) + { + HWND newHwnd = (HWND) wparam; + CHAR szClassName[255]; + GetClassName(newHwnd, szClassName, 255); + + if(code == HCBT_CREATEWND) + { + OutputDebugString(szClassName); + + if((lstrcmpi(szClassName, TEXT("tooltips_class32")) == 0) + || (lstrcmpi(szClassName, TEXT("tooltips_class")) == 0)) + { + WINDOWINFO pwi; + pwi.cbSize = sizeof(PWINDOWINFO); + GetWindowInfo(newHwnd, &pwi); + + TCHAR szBuffer[256]; + + OutputDebugString("style:"); + wsprintf(szBuffer, "%lu", pwi.dwStyle); + OutputDebugString(szBuffer); + OutputDebugString(szClassName); + if((pwi.dwStyle & 0x40)) OutputDebugString("THIS WINDOW HAS TTS_BALLOON STYLE"); + OutputDebugString("----------------------"); + } + } + } + + return CallNextHookEx(hookCBT, code, wparam, lparam); +} + +static LRESULT CALLBACK ShellHookCallback(int code, WPARAM wparam, LPARAM lparam) +{ + if(code == HSHELL_WINDOWACTIVATED + || code == HSHELL_WINDOWCREATED + || code == HSHELL_WINDOWREPLACED + || code == HSHELL_RUDEAPPACTIVATED) + { + HWND newHwnd = (HWND) wparam; + CHAR szClassName[255]; + GetClassName(newHwnd, szClassName, 255); + + OutputDebugString(szClassName); + + /* + //if(!lstrcmp(szClassName, "tooltips_class32")) + //if(!lstrcmp(szClassName, "UserEventWindow")) + //{ + WINDOWINFO pwi; + pwi.cbSize = sizeof(PWINDOWINFO); + GetWindowInfo(newHwnd, &pwi); + + TCHAR szBuffer[256]; + + OutputDebugString("style:"); + wsprintf(szBuffer, "%lu", pwi.dwStyle); + OutputDebugString(szBuffer); + OutputDebugString(szClassName); + if((pwi.dwStyle & 0x40)) OutputDebugString("THIS WINDOW HAS TTS_BALLOON STYLE"); + OutputDebugString("----------------------"); + //} + */ + } + + return CallNextHookEx(hookShell, code, wparam, lparam); +} \ No newline at end of file diff --git a/Growl Extras/SystemBalloonIntercepter/stdafx.cpp b/Growl Extras/SystemBalloonIntercepter/stdafx.cpp new file mode 100644 index 0000000..a59630b --- /dev/null +++ b/Growl Extras/SystemBalloonIntercepter/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : source file that includes just the standard includes +// SystemHookCore.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file diff --git a/Growl Extras/SystemBalloonIntercepter/stdafx.h b/Growl Extras/SystemBalloonIntercepter/stdafx.h new file mode 100644 index 0000000..7c255ab --- /dev/null +++ b/Growl Extras/SystemBalloonIntercepter/stdafx.h @@ -0,0 +1,20 @@ +// +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#pragma once + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers + +#define WINVER 0x0501 +#define _WIN32_WINNT 0x0501 + +#define _WIN32_IE 0x0600 + +#include +#include +#include + +// TODO: reference additional headers your program requires here