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
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
17 /// ダウンロードしたファイルをスキャンする
\r
19 public class DownloadScanner : IDisposable
\r
23 private enum MSOAVINFOFLAG : uint {
\r
25 fReadOnlyRequest = 2,
\r
30 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
\r
31 private struct MSOAVINFO {
\r
34 [MarshalAs(UnmanagedType.U4)]
\r
35 public MSOAVINFOFLAG uFlags;
\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
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
56 /// ウイルススキャナーに渡すプログラム・ホスト名。
\r
58 public string HostName {
\r
61 return Assembly.GetExecutingAssembly().GetName().FullName;
\r
65 private List<IOfficeAntiVirus> scanners;
\r
68 /// コンストラクタ。内部でCOM呼び出し初期化(CoInitialize)されます。
\r
70 public DownloadScanner()
\r
72 ComDirectAccess.CoInitialize(IntPtr.Zero);
\r
76 /// 内部でCOM開放(CoUninitialize)します。必ず呼び出す必要があります。
\r
78 public void Dispose()
\r
81 ComDirectAccess.CoUninitialize();
\r
87 /// <remarks>Init()呼出し後に使える</remarks>
\r
88 public bool HasScanner {
\r
89 get { return scanners.Count > 0; }
\r
93 /// 初期化処理としてウイルススキャンを探す。
\r
97 scanners = new List<IOfficeAntiVirus>();
\r
99 Guid IID_MSOfficeAntiVirus = new Guid(((GuidAttribute) Attribute.GetCustomAttribute(typeof(IOfficeAntiVirus), typeof(GuidAttribute))).Value);
\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
111 /// ウイルススキャンのオブジェクトを開放しInitの前の状態に戻す。
\r
113 public void Release()
\r
115 if ((scanners != null) && (scanners.Count > 0)) {
\r
116 foreach (IOfficeAntiVirus i in scanners) {
\r
117 Marshal.ReleaseComObject(i);
\r
124 /// ファイルをスキャンする。ウイルススキャンが複数個見つかっている
\r
125 /// ならばそれらすべてでスキャンする。
\r
126 /// ウイルススキャンの実装によるが、ウイルス発見時にはダイアログが開く。
\r
127 /// ウイルスの処理はユーザに委ねられるので、それの制御は一切できない。
\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
138 if (scanners.Count <= 0) {
\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
150 foreach (IOfficeAntiVirus i in scanners) {
\r
151 if (! System.IO.File.Exists(path)) break;
\r