1 // OpenTween - Client of Twitter
2 // Copyright (c) 2007-2011 kiri_feather (@kiri_feather) <kiri.feather@gmail.com>
3 // (c) 2008-2011 Moz (@syo68k)
4 // (c) 2008-2011 takeshik (@takeshik) <http://www.takeshik.org/>
5 // (c) 2010-2011 anis774 (@anis774) <http://d.hatena.ne.jp/anis774/>
6 // (c) 2010-2011 fantasticswallow (@f_swallow) <http://twitter.com/f_swallow>
7 // (c) 2011 kim_upsilon (@kim_upsilon) <https://upsilo.net/~upsilon/>
8 // All rights reserved.
10 // This file is part of OpenTween.
12 // This program is free software; you can redistribute it and/or modify it
13 // under the terms of the GNU General public License as published by the Free
14 // Software Foundation; either version 3 of the License, or (at your option)
17 // This program is distributed in the hope that it will be useful, but
18 // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19 // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General public License
22 // You should have received a copy of the GNU General public License along
23 // with this program. If not, see <http://www.gnu.org/licenses/>, or write to
24 // the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
25 // Boston, MA 02110-1301, USA.
30 using System.Collections.Generic;
33 using System.Reflection;
36 using System.Drawing.Imaging;
37 using System.Windows.Forms;
38 using System.ComponentModel;
39 using System.Collections;
40 using System.Globalization;
44 public class GrowlHelper
46 private Assembly? _connector = null;
47 private Assembly? _core = null;
49 private object? _growlNTreply;
50 private object? _growlNTdm;
51 private object? _growlNTnew;
52 private object? _growlNTusevent;
53 private object? _growlApp;
55 private object? _targetConnector;
56 bool _initialized = false;
58 public class NotifyCallbackEventArgs : EventArgs
60 public long StatusId { get; set; }
61 public NotifyType NotifyType { get; set; }
62 public NotifyCallbackEventArgs(NotifyType notifyType, string statusId)
64 if (statusId.Length > 1)
66 this.StatusId = long.Parse(statusId);
67 this.NotifyType = notifyType;
72 public event EventHandler<NotifyCallbackEventArgs> NotifyClicked;
74 public string AppName { get; }
76 public enum NotifyType
84 public GrowlHelper(string appName)
85 => this.AppName = appName;
87 public bool IsAvailable
91 if (_connector == null || _core == null || !_initialized)
98 private byte[] IconToByteArray(string filename)
100 using var ic = new Icon(filename);
101 return IconToByteArray(ic);
104 private byte[] IconToByteArray(Icon icondata)
106 using var ms = new MemoryStream();
107 using var ic = new Icon(icondata, 48, 48);
108 ic.ToBitmap().Save(ms, ImageFormat.Png);
112 public static bool IsDllExists
116 var dir = Application.StartupPath;
117 var connectorPath = Path.Combine(dir, "Growl.Connector.dll");
118 var corePath = Path.Combine(dir, "Growl.CoreLibrary.dll");
119 if (File.Exists(connectorPath) && File.Exists(corePath))
126 public bool RegisterGrowl()
128 _initialized = false;
129 var dir = Application.StartupPath;
130 var connectorPath = Path.Combine(dir, "Growl.Connector.dll");
131 var corePath = Path.Combine(dir, "Growl.CoreLibrary.dll");
135 if (!IsDllExists) return false;
136 _connector = Assembly.LoadFile(connectorPath);
137 _core = Assembly.LoadFile(corePath);
146 _targetConnector = _connector.CreateInstance("Growl.Connector.GrowlConnector");
147 var _t = _connector.GetType("Growl.Connector.NotificationType");
149 _growlNTreply = _t.InvokeMember(null,
150 BindingFlags.CreateInstance, null, null, new object[] { "REPLY", "Reply" }, CultureInfo.InvariantCulture);
152 _growlNTdm = _t.InvokeMember(null,
153 BindingFlags.CreateInstance, null, null, new object[] { "DIRECT_MESSAGE", "DirectMessage" }, CultureInfo.InvariantCulture);
155 _growlNTnew = _t.InvokeMember(null,
156 BindingFlags.CreateInstance, null, null, new object[] { "NOTIFY", "新着通知" }, CultureInfo.InvariantCulture);
158 _growlNTusevent = _t.InvokeMember(null,
159 BindingFlags.CreateInstance, null, null, new object[] { "USERSTREAM_EVENT", "UserStream Event" }, CultureInfo.InvariantCulture);
162 _connector.GetType("Growl.Connector.Cryptography+SymmetricAlgorithmType").InvokeMember(
163 "PlainText", BindingFlags.GetField, null, null, null, CultureInfo.InvariantCulture);
164 _targetConnector.GetType().InvokeMember("EncryptionAlgorithm", BindingFlags.SetProperty, null, _targetConnector, new object[] { encryptType }, CultureInfo.InvariantCulture);
166 _growlApp = _connector.CreateInstance(
167 "Growl.Connector.Application", false, BindingFlags.Default, null, new object[] { AppName }, null, null);
170 if (File.Exists(Path.Combine(Application.StartupPath, "Icons\\Tween.png")))
172 // Icons\Tween.pngを使用
173 var ci = _core.GetType(
174 "Growl.CoreLibrary.Resource").GetConstructor(
175 BindingFlags.NonPublic | BindingFlags.Instance,
176 null, new Type[] { typeof(string) }, null);
178 var data = ci.Invoke(new object[] { Path.Combine(Application.StartupPath, "Icons\\Tween.png") });
179 var pi = _growlApp.GetType().GetProperty("Icon");
180 pi.SetValue(_growlApp, data, null);
183 else if (File.Exists(Path.Combine(Application.StartupPath, "Icons\\MIcon.ico")))
185 // アイコンセットにMIcon.icoが存在する場合それを使用
186 var cibd = _core.GetType(
187 "Growl.CoreLibrary.BinaryData").GetConstructor(
188 BindingFlags.Public | BindingFlags.Instance,
189 null, new Type[] { typeof(byte[]) }, null);
190 var bdata = cibd.Invoke(
191 new object[] { IconToByteArray(Path.Combine(Application.StartupPath, "Icons\\MIcon.ico")) });
193 var ciRes = _core.GetType(
194 "Growl.CoreLibrary.Resource").GetConstructor(
195 BindingFlags.NonPublic | BindingFlags.Instance,
196 null, new Type[] { bdata.GetType() }, null);
198 var data = ciRes.Invoke(new object[] { bdata });
199 var pi = _growlApp.GetType().GetProperty("Icon");
200 pi.SetValue(_growlApp, data, null);
205 var cibd = _core.GetType(
206 "Growl.CoreLibrary.BinaryData").GetConstructor(
207 BindingFlags.Public | BindingFlags.Instance,
208 null, new Type[] { typeof(byte[]) }, null);
209 var bdata = cibd.Invoke(
210 new object[] { IconToByteArray(Properties.Resources.MIcon) });
212 var ciRes = _core.GetType(
213 "Growl.CoreLibrary.Resource").GetConstructor(
214 BindingFlags.NonPublic | BindingFlags.Instance,
215 null, new Type[] { bdata.GetType() }, null);
217 var data = ciRes.Invoke(new object[] { bdata });
218 var pi = _growlApp.GetType().GetProperty("Icon");
219 pi.SetValue(_growlApp, data, null);
222 var mi = _targetConnector.GetType().GetMethod("Register", new Type[] { _growlApp.GetType(), _connector.GetType("Growl.Connector.NotificationType[]") });
224 _t = _connector.GetType("Growl.Connector.NotificationType");
226 var arglist = new ArrayList
234 mi.Invoke(_targetConnector, new object[] { _growlApp, arglist.ToArray(_t) });
237 var tGrowlConnector = _connector.GetType("Growl.Connector.GrowlConnector");
238 var evNotificationCallback = tGrowlConnector.GetEvent("NotificationCallback");
239 var tDelegate = evNotificationCallback.EventHandlerType;
240 var miHandler = typeof(GrowlHelper).GetMethod("GrowlCallbackHandler", BindingFlags.NonPublic | BindingFlags.Instance);
241 var d = Delegate.CreateDelegate(tDelegate, this, miHandler);
242 var miAddHandler = evNotificationCallback.GetAddMethod();
243 object[] addHandlerArgs = { d };
244 miAddHandler.Invoke(_targetConnector, addHandlerArgs);
250 _initialized = false;
257 public void Notify(NotifyType notificationType, string id, string title, string text, Image? icon = null, string url = "")
259 if (!_initialized) return;
260 var notificationName = "";
261 switch (notificationType)
263 case NotifyType.Reply:
264 notificationName = "REPLY";
266 case NotifyType.DirectMessage:
267 notificationName = "DIRECT_MESSAGE";
269 case NotifyType.Notify:
270 notificationName = "NOTIFY";
272 case NotifyType.UserStreamEvent:
273 notificationName = "USERSTREAM_EVENT";
277 if (icon != null || !string.IsNullOrEmpty(url))
279 var gCore = _core!.GetType("Growl.CoreLibrary.Resource");
283 res = gCore.InvokeMember("op_Implicit",
284 BindingFlags.Public | BindingFlags.Static | BindingFlags.InvokeMethod,
287 new object[] { icon },
288 CultureInfo.InvariantCulture);
292 res = gCore.InvokeMember("op_Implicit",
293 BindingFlags.Public | BindingFlags.Static | BindingFlags.InvokeMethod,
296 new object[] { url },
297 CultureInfo.InvariantCulture);
300 _connector!.GetType("Growl.Connector.Priority").InvokeMember(
301 "Normal", BindingFlags.GetField, null, null, null, CultureInfo.InvariantCulture);
302 n = _connector!.GetType("Growl.Connector.Notification").InvokeMember(
304 BindingFlags.CreateInstance,
307 new object[] {AppName,
316 CultureInfo.InvariantCulture);
320 n = _connector!.GetType("Growl.Connector.Notification").InvokeMember(
322 BindingFlags.CreateInstance,
325 new object[] {AppName,
330 CultureInfo.InvariantCulture);
332 //_targetConnector.GetType.InvokeMember("Notify", BindingFlags.InvokeMethod, null, _targetConnector, new object[] {n});
333 var cc = _connector.GetType("Growl.Connector.CallbackContext").InvokeMember(
334 null, BindingFlags.CreateInstance, null, _connector,
335 new object[] { "some fake information", notificationName },
336 CultureInfo.InvariantCulture);
337 _targetConnector!.GetType().InvokeMember("Notify", BindingFlags.InvokeMethod, null, _targetConnector, new object[] { n, cc }, CultureInfo.InvariantCulture);
340 private void GrowlCallbackHandler(object response, object callbackData, object state)
346 _core!.GetType("Growl.CoreLibrary.CallbackResult").GetField(
348 BindingFlags.Public | BindingFlags.Static).GetRawConstantValue();
350 var vResult = callbackData.GetType().GetProperty(
352 BindingFlags.Public | BindingFlags.Instance).GetGetMethod().Invoke(callbackData, null);
353 vResult = (int)vResult;
354 var notifyId = (string)callbackData.GetType().GetProperty("NotificationID").GetGetMethod().Invoke(callbackData, null);
355 var notifyName = (string)callbackData.GetType().GetProperty("Type").GetGetMethod().Invoke(callbackData, null);
356 if (vCLICK.Equals(vResult))
362 nt = NotifyType.Reply;
364 case "DIRECT_MESSAGE":
365 nt = NotifyType.DirectMessage;
368 nt = NotifyType.Notify;
370 case "USERSTREAM_EVENT":
371 nt = NotifyType.UserStreamEvent;
377 NotifyClicked?.Invoke(this, new NotifyCallbackEventArgs(nt, notifyId));