OSDN Git Service

AppliStation-GUI,ウイルススキャン直前にファイルの存在確認をするように
[applistation/AppliStation.git] / na-get-lib / NaGet.Net / DownloadScanner.cs
1 /*\r
2  * This code is based on /mozilla/source/toolkit/components/downloads/src/nsDownloadScanner.cpp\r
3  * and sample code at https://bugzilla.mozilla.org/show_bug.cgi?id=103487,\r
4  * created by Rob Arnold.\r
5  */\r
6 \r
7 using System;\r
8 using System.Reflection;\r
9 using System.Collections.Generic;\r
10 using System.Runtime.InteropServices;\r
11 using System.Runtime.InteropServices.ComTypes;\r
12 using NaGet.InteropServices;\r
13 \r
14 namespace NaGet.Net\r
15 {\r
16         /// <summary>\r
17         /// ダウンロードしたファイルをスキャンする\r
18         /// </summary>\r
19         public class DownloadScanner : IDisposable\r
20         {\r
21                 #region COMInterop\r
22                 [Flags()]\r
23                 private enum MSOAVINFOFLAG : uint {\r
24                         fPath = 1,\r
25                         fReadOnlyRequest = 2,\r
26                         fInstalled = 4,\r
27                         fHttpDownload = 8,\r
28                 }\r
29                 \r
30                 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]\r
31                 private struct MSOAVINFO {\r
32                         public int cbsize;\r
33 \r
34                         [MarshalAs(UnmanagedType.U4)]\r
35                         public MSOAVINFOFLAG uFlags;\r
36                         \r
37                         public IntPtr hwnd;\r
38 \r
39                         [MarshalAs(UnmanagedType.LPWStr)]\r
40                         public string pwzFullPath;\r
41                         [MarshalAs(UnmanagedType.LPWStr)]\r
42                         public string pwzHostName;\r
43                         [MarshalAs(UnmanagedType.LPWStr)]\r
44                         public string pwzOrigURL;\r
45                 }\r
46                 \r
47                 [ComImport()]\r
48                 [Guid("56FFCC30-D398-11D0-B2AE-00A0C908FA49")]\r
49                 [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]\r
50                 private interface IOfficeAntiVirus {\r
51                         void Scan(ref MSOAVINFO pmsoavinfo);\r
52                 }\r
53                 #endregion\r
54                 \r
55                 /// <summary>\r
56                 /// ウイルススキャナーに渡すプログラム・ホスト名。\r
57                 /// </summary>\r
58                 public string HostName {\r
59                         get {\r
60                                 // 実行アセンブリ名を返す\r
61                                 return Assembly.GetExecutingAssembly().GetName().FullName;\r
62                         }\r
63                 }\r
64                 \r
65                 private List<IOfficeAntiVirus> scanners;\r
66 \r
67                 /// <summary>\r
68                 /// コンストラクタ。内部でCOM呼び出し初期化(CoInitialize)されます。\r
69                 /// </summary>\r
70                 public DownloadScanner()\r
71                 {\r
72                         ComDirectAccess.CoInitialize(IntPtr.Zero);\r
73                 }\r
74                 \r
75                 /// <summary>\r
76                 /// 内部でCOM開放(CoUninitialize)します。必ず呼び出す必要があります。\r
77                 /// </summary>\r
78                 public void Dispose()\r
79                 {\r
80                         Release();\r
81                         ComDirectAccess.CoUninitialize();\r
82                 }\r
83                 \r
84                 /// <summary>\r
85                 /// ウイルススキャンがあるかないか\r
86                 /// </summary>\r
87                 /// <remarks>Init()呼出し後に使える</remarks>\r
88                 public bool HasScanner {\r
89                         get { return scanners.Count > 0; }\r
90                 }\r
91                 \r
92                 /// <summary>\r
93                 /// 初期化処理としてウイルススキャンを探す。\r
94                 /// </summary>\r
95                 public void Init()\r
96                 {\r
97                         scanners = new List<IOfficeAntiVirus>();\r
98                         \r
99                         Guid IID_MSOfficeAntiVirus = new Guid(((GuidAttribute) Attribute.GetCustomAttribute(typeof(IOfficeAntiVirus), typeof(GuidAttribute))).Value);\r
100                         \r
101                         using (GuidEnumeratorForCategories guids = new GuidEnumeratorForCategories(IID_MSOfficeAntiVirus)) {\r
102                                 foreach (Guid guid in guids) {\r
103                                         IOfficeAntiVirus oav = ComDirectAccess.CreateInstance<IOfficeAntiVirus>(guid, ComDirectAccess.CLSCTX.CLSCTX_INPROC_SERVER);\r
104                                         \r
105                                         scanners.Add(oav);\r
106                                 }\r
107                         }\r
108                 }\r
109                 \r
110                 /// <summary>\r
111                 /// ウイルススキャンのオブジェクトを開放しInitの前の状態に戻す。\r
112                 /// </summary>\r
113                 public void Release()\r
114                 {\r
115                         if ((scanners != null) && (scanners.Count > 0)) {\r
116                                 foreach (IOfficeAntiVirus i in scanners) {\r
117                                         Marshal.ReleaseComObject(i);\r
118                                 }\r
119                                 scanners.Clear();\r
120                         }\r
121                 }\r
122                 \r
123                 /// <summary>\r
124                 /// ファイルをスキャンする。ウイルススキャンが複数個見つかっている\r
125                 /// ならばそれらすべてでスキャンする。\r
126                 /// ウイルススキャンの実装によるが、ウイルス発見時にはダイアログが開く。\r
127                 /// ウイルスの処理はユーザに委ねられるので、それの制御は一切できない。\r
128                 /// </summary>\r
129                 /// <remarks>ウイルスが見つかったか否かは取得できない。</remarks>\r
130                 /// <remarks>本メソッド呼び出し後にウイルスが退避されているかもしれないが、ファイルの存在確認でしかそれをチェックできない</remarks>\r
131                 /// <param name="path">ファイルのパス</param>\r
132                 /// <param name="origin">ファイルをダウンロードしたURL。nullであってはならない</param>\r
133                 /// <exception cref="COMException">COMのエラー発生時。たとえば、AVGではウイルスと検出されたのにユーザが「無視」を指定したときにも投げられる。</exception>\r
134                 /// <returns>ウイルススキャンがされたか否か</returns>\r
135                 /// <remarks>Init()呼出し後に使える</remarks>\r
136                 public bool Scan(string path, string origin)\r
137                 {\r
138                         if (scanners.Count <= 0) {\r
139                                 return false;\r
140                         }\r
141                         \r
142                         MSOAVINFO info = new MSOAVINFO();\r
143                         info.cbsize = Marshal.SizeOf(info);\r
144                         info.uFlags = MSOAVINFOFLAG.fPath | MSOAVINFOFLAG.fHttpDownload;\r
145                         info.hwnd = IntPtr.Zero;\r
146                         info.pwzFullPath = path;\r
147                         info.pwzHostName = HostName;\r
148                         info.pwzOrigURL = origin;\r
149                         \r
150                         foreach (IOfficeAntiVirus i in scanners) {\r
151                                 if (! System.IO.File.Exists(path)) break;\r
152                                 i.Scan(ref info);\r
153                         }\r
154                         return true;\r
155                 }\r
156         }\r
157 }\r