-using System;\r
+/*\r
+ * This code is based on /mozilla/source/toolkit/components/downloads/src/nsDownloadScanner.cpp\r
+ * and sample code at https://bugzilla.mozilla.org/show_bug.cgi?id=103487,\r
+ * created by Rob Arnold.\r
+ */\r
+\r
+using System;\r
using System.Reflection;\r
using System.Collections.Generic;\r
using System.Runtime.InteropServices;\r
\r
namespace NaGet.Net\r
{\r
+ public enum DownloadScannerResult : uint {\r
+ OK = 0, // S_OK\r
+ InfectedAndCleaned = 1, // S_FALSE\r
+ InfectedButNotCleaned = 0x80004005, // E_FAIL\r
+ ErrorNotFound = 2, // ERROR_NOT_FOUND\r
+ \r
+ ScannerNotFound = 0xFFFFFFFF,\r
+ }\r
+ \r
+ /// <summary>\r
+ /// ダウンロードしたファイルをスキャンする\r
+ /// </summary>\r
public class DownloadScanner : IDisposable\r
{\r
#region COMInterop\r
[Guid("56FFCC30-D398-11D0-B2AE-00A0C908FA49")]\r
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]\r
private interface IOfficeAntiVirus {\r
- void Scan(ref MSOAVINFO pmsoavinfo);\r
+ [PreserveSig()]\r
+ uint Scan(ref MSOAVINFO pmsoavinfo);\r
}\r
#endregion\r
\r
/// <summary>\r
/// ウイルススキャナーに渡すプログラム・ホスト名。\r
/// </summary>\r
- public string HostName {\r
+ public static string HostName {\r
get {\r
// 実行アセンブリ名を返す\r
return Assembly.GetExecutingAssembly().GetName().FullName;\r
}\r
\r
private List<IOfficeAntiVirus> scanners;\r
- \r
+\r
+ /// <summary>\r
+ /// コンストラクタ。内部でCOM呼び出し初期化(CoInitialize)されます。\r
+ /// </summary>\r
public DownloadScanner()\r
{\r
- ComDirectAccess.CoInitialize(IntPtr.Zero);\r
+ int result = ComDirectAccess.CoInitialize(IntPtr.Zero);\r
+ if (result == 0) {\r
+ throw new System.ComponentModel.Win32Exception();\r
+ }\r
}\r
\r
+ /// <summary>\r
+ /// 内部でCOM開放(CoUninitialize)します。必ず呼び出す必要があります。\r
+ /// </summary>\r
public void Dispose()\r
{\r
- if ((scanners != null) && (scanners.Count > 0)) {\r
- foreach (IOfficeAntiVirus i in scanners) {\r
- Marshal.ReleaseComObject(i);\r
- }\r
- scanners.Clear();\r
- }\r
- \r
+ Release();\r
ComDirectAccess.CoUninitialize();\r
+ GC.SuppressFinalize(this);\r
}\r
\r
+ /// <summary>\r
+ /// ウイルススキャンがあるかないか\r
+ /// </summary>\r
+ /// <remarks>Init()呼出し後に使える</remarks>\r
public bool HasScanner {\r
get { return scanners.Count > 0; }\r
}\r
\r
+ /// <summary>\r
+ /// 初期化処理としてウイルススキャンを探す。\r
+ /// </summary>\r
public void Init()\r
{\r
scanners = new List<IOfficeAntiVirus>();\r
}\r
}\r
\r
- public bool Scan(string path, string origin)\r
+ /// <summary>\r
+ /// ウイルススキャンのオブジェクトを開放しInitの前の状態に戻す。\r
+ /// </summary>\r
+ public void Release()\r
{\r
- if (scanners.Count <= 0) {\r
- return false;\r
+ if ((scanners != null) && (scanners.Count > 0)) {\r
+ foreach (IOfficeAntiVirus i in scanners) {\r
+ Marshal.ReleaseComObject(i);\r
+ }\r
+ scanners.Clear();\r
}\r
- \r
+ }\r
+ \r
+ /// <summary>\r
+ /// ファイルをスキャンする。ウイルススキャンが複数個見つかっている\r
+ /// ならばそれらすべてでスキャンする。\r
+ /// ウイルススキャンの実装によるが、ウイルス発見時にはダイアログが開く。\r
+ /// ウイルスの処理はユーザに委ねられるので、それの制御は一切できない。\r
+ /// </summary>\r
+ /// <remarks>ウイルスが見つかったか否かは取得できない。</remarks>\r
+ /// <remarks>本メソッド呼び出し後にウイルスが退避されているかもしれないが、ファイルの存在確認でしかそれをチェックできない</remarks>\r
+ /// <param name="path">ファイルのパス</param>\r
+ /// <param name="origin">ファイルをダウンロードしたURL。nullであってはならない</param>\r
+ /// <exception cref="COMException">COMのエラー発生時。たとえば、AVGではウイルスと検出されたのにユーザが「無視」を指定したときにも投げられる。</exception>\r
+ /// <returns>ウイルススキャン結果。</returns>\r
+ /// <remarks>Init()呼出し後に使える</remarks>\r
+ public DownloadScannerResult Scan(string path, string origin)\r
+ {\r
MSOAVINFO info = new MSOAVINFO();\r
info.cbsize = Marshal.SizeOf(info);\r
info.uFlags = MSOAVINFOFLAG.fPath | MSOAVINFOFLAG.fHttpDownload;\r
info.pwzHostName = HostName;\r
info.pwzOrigURL = origin;\r
\r
+ DownloadScannerResult result = DownloadScannerResult.ScannerNotFound;\r
foreach (IOfficeAntiVirus i in scanners) {\r
- i.Scan(ref info);\r
+ if (System.IO.File.Exists(path)) {\r
+ result = (DownloadScannerResult) i.Scan(ref info);\r
+ if (result == DownloadScannerResult.OK && System.IO.File.Exists(path) == false) {\r
+ result = DownloadScannerResult.InfectedAndCleaned;\r
+ }\r
+ } else {\r
+ result = DownloadScannerResult.ErrorNotFound;\r
+ }\r
+ \r
+ if (result != DownloadScannerResult.OK) {\r
+ break;\r
+ }\r
}\r
- return true;\r
+ \r
+ return result;\r
}\r
}\r
}\r