OSDN Git Service

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