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;
31 using System.Collections.Generic;
32 using System.ComponentModel;
34 using System.Drawing.Imaging;
35 using System.Globalization;
38 using System.Reflection;
40 using System.Windows.Forms;
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? growlApp;
54 private object? targetConnector;
55 private bool initialized = false;
57 public class NotifyCallbackEventArgs : EventArgs
59 public long StatusId { get; set; }
61 public NotifyType NotifyType { get; set; }
63 public NotifyCallbackEventArgs(NotifyType notifyType, string statusId)
65 if (statusId.Length > 1)
67 this.StatusId = long.Parse(statusId);
68 this.NotifyType = notifyType;
73 public event EventHandler<NotifyCallbackEventArgs>? NotifyClicked;
75 public string AppName { get; }
77 public enum NotifyType
84 public GrowlHelper(string appName)
85 => this.AppName = appName;
87 public bool IsAvailable
91 if (this.connector == null || this.core == null || !this.initialized)
98 private byte[] IconToByteArray(string filename)
100 using var ic = new Icon(filename);
101 return this.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 this.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 this.connector = Assembly.LoadFile(connectorPath);
137 this.core = Assembly.LoadFile(corePath);
146 this.targetConnector = this.connector.CreateInstance("Growl.Connector.GrowlConnector");
147 var t = this.connector.GetType("Growl.Connector.NotificationType");
149 this.growlNTreply = t.InvokeMember(
151 BindingFlags.CreateInstance,
154 new object[] { "REPLY", "Reply" },
155 CultureInfo.InvariantCulture);
157 this.growlNTdm = t.InvokeMember(null,
158 BindingFlags.CreateInstance,
161 new object[] { "DIRECT_MESSAGE", "DirectMessage" },
162 CultureInfo.InvariantCulture);
164 this.growlNTnew = t.InvokeMember(
166 BindingFlags.CreateInstance,
169 new object[] { "NOTIFY", "新着通知" },
170 CultureInfo.InvariantCulture);
173 this.connector.GetType("Growl.Connector.Cryptography+SymmetricAlgorithmType").InvokeMember(
174 "PlainText", BindingFlags.GetField, null, null, null, CultureInfo.InvariantCulture);
175 this.targetConnector.GetType().InvokeMember("EncryptionAlgorithm", BindingFlags.SetProperty, null, this.targetConnector, new object[] { encryptType }, CultureInfo.InvariantCulture);
177 this.growlApp = this.connector.CreateInstance(
178 "Growl.Connector.Application", false, BindingFlags.Default, null, new object[] { this.AppName }, null, null);
180 if (File.Exists(Path.Combine(Application.StartupPath, "Icons\\Tween.png")))
182 // Icons\Tween.pngを使用
183 var ci = this.core.GetType("Growl.CoreLibrary.Resource").GetConstructor(
184 BindingFlags.NonPublic | BindingFlags.Instance,
186 new Type[] { typeof(string) },
189 var data = ci.Invoke(new object[] { Path.Combine(Application.StartupPath, "Icons\\Tween.png") });
190 var pi = this.growlApp.GetType().GetProperty("Icon");
191 pi.SetValue(this.growlApp, data, null);
193 else if (File.Exists(Path.Combine(Application.StartupPath, "Icons\\MIcon.ico")))
195 // アイコンセットにMIcon.icoが存在する場合それを使用
196 var cibd = this.core.GetType("Growl.CoreLibrary.BinaryData").GetConstructor(
197 BindingFlags.Public | BindingFlags.Instance,
199 new Type[] { typeof(byte[]) },
201 var bdata = cibd.Invoke(
202 new object[] { this.IconToByteArray(Path.Combine(Application.StartupPath, "Icons\\MIcon.ico")) });
204 var ciRes = this.core.GetType("Growl.CoreLibrary.Resource").GetConstructor(
205 BindingFlags.NonPublic | BindingFlags.Instance,
207 new Type[] { bdata.GetType() },
210 var data = ciRes.Invoke(new object[] { bdata });
211 var pi = this.growlApp.GetType().GetProperty("Icon");
212 pi.SetValue(this.growlApp, data, null);
217 var cibd = this.core.GetType("Growl.CoreLibrary.BinaryData").GetConstructor(
218 BindingFlags.Public | BindingFlags.Instance,
220 new Type[] { typeof(byte[]) },
222 var bdata = cibd.Invoke(
223 new object[] { this.IconToByteArray(Properties.Resources.MIcon) });
225 var ciRes = this.core.GetType("Growl.CoreLibrary.Resource").GetConstructor(
226 BindingFlags.NonPublic | BindingFlags.Instance,
228 new Type[] { bdata.GetType() },
231 var data = ciRes.Invoke(new object[] { bdata });
232 var pi = this.growlApp.GetType().GetProperty("Icon");
233 pi.SetValue(this.growlApp, data, null);
236 var mi = this.targetConnector.GetType().GetMethod("Register", new Type[] { this.growlApp.GetType(), this.connector.GetType("Growl.Connector.NotificationType[]") });
238 t = this.connector.GetType("Growl.Connector.NotificationType");
240 var arglist = new ArrayList
247 mi.Invoke(this.targetConnector, new object[] { this.growlApp, arglist.ToArray(t) });
250 var tGrowlConnector = this.connector.GetType("Growl.Connector.GrowlConnector");
251 var evNotificationCallback = tGrowlConnector.GetEvent("NotificationCallback");
252 var tDelegate = evNotificationCallback.EventHandlerType;
253 var miHandler = typeof(GrowlHelper).GetMethod("GrowlCallbackHandler", BindingFlags.NonPublic | BindingFlags.Instance);
254 var d = Delegate.CreateDelegate(tDelegate, this, miHandler);
255 var miAddHandler = evNotificationCallback.GetAddMethod();
256 object[] addHandlerArgs = { d };
257 miAddHandler.Invoke(this.targetConnector, addHandlerArgs);
259 this.initialized = true;
263 this.initialized = false;
270 public void Notify(NotifyType notificationType, string id, string title, string text, Image? icon = null, string url = "")
272 if (!this.initialized) return;
274 var notificationName = notificationType switch
276 NotifyType.Reply => "REPLY",
277 NotifyType.DirectMessage => "DIRECT_MESSAGE",
278 NotifyType.Notify => "NOTIFY",
283 if (icon != null || !MyCommon.IsNullOrEmpty(url))
285 var gCore = this.core!.GetType("Growl.CoreLibrary.Resource");
289 res = gCore.InvokeMember("op_Implicit",
290 BindingFlags.Public | BindingFlags.Static | BindingFlags.InvokeMethod,
293 new object[] { icon },
294 CultureInfo.InvariantCulture);
298 res = gCore.InvokeMember("op_Implicit",
299 BindingFlags.Public | BindingFlags.Static | BindingFlags.InvokeMethod,
302 new object[] { url },
303 CultureInfo.InvariantCulture);
306 this.connector!.GetType("Growl.Connector.Priority").InvokeMember(
307 "Normal", BindingFlags.GetField, null, null, null, CultureInfo.InvariantCulture);
308 n = this.connector!.GetType("Growl.Connector.Notification").InvokeMember(
310 BindingFlags.CreateInstance,
325 CultureInfo.InvariantCulture);
329 n = this.connector!.GetType("Growl.Connector.Notification").InvokeMember(
331 BindingFlags.CreateInstance,
342 CultureInfo.InvariantCulture);
344 var cc = this.connector.GetType("Growl.Connector.CallbackContext").InvokeMember(
346 BindingFlags.CreateInstance,
349 new object[] { "some fake information", notificationName },
350 CultureInfo.InvariantCulture);
351 this.targetConnector!.GetType().InvokeMember("Notify", BindingFlags.InvokeMethod, null, this.targetConnector, new object[] { n, cc }, CultureInfo.InvariantCulture);
354 private void GrowlCallbackHandler(object response, object callbackData, object state)
360 this.core!.GetType("Growl.CoreLibrary.CallbackResult").GetField(
362 BindingFlags.Public | BindingFlags.Static).GetRawConstantValue();
364 var vResult = callbackData.GetType().GetProperty(
366 BindingFlags.Public | BindingFlags.Instance).GetGetMethod().Invoke(callbackData, null);
367 vResult = (int)vResult;
368 var notifyId = (string)callbackData.GetType().GetProperty("NotificationID").GetGetMethod().Invoke(callbackData, null);
369 var notifyName = (string)callbackData.GetType().GetProperty("Type").GetGetMethod().Invoke(callbackData, null);
370 if (vCLICK.Equals(vResult))
376 nt = NotifyType.Reply;
378 case "DIRECT_MESSAGE":
379 nt = NotifyType.DirectMessage;
382 nt = NotifyType.Notify;
388 this.NotifyClicked?.Invoke(this, new NotifyCallbackEventArgs(nt, notifyId));