OSDN Git Service

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