public void StartTaskSet()\r
{\r
tasksetRunningThread = new Thread(taskSet.Run);\r
+ // スレッドをSTAにしないとCOMアクセスできず、ウイルススキャンができない。\r
+ tasksetRunningThread.SetApartmentState(ApartmentState.STA);\r
tasksetRunningThread.Start();\r
}\r
\r
Console.WriteLine("誰か {0} をスーパー牛さんパワー化してくれ", executeFileName);\r
}\r
\r
+ [STAThread]\r
public static void Main(string[] args)\r
{\r
// アーカイブSYSTEM32をパスに足す\r
--- /dev/null
+using System;\r
+using System.Runtime.InteropServices;\r
+using System.Runtime.InteropServices.ComTypes;\r
+\r
+namespace NaGet.InteropServices\r
+{\r
+ /// <summary>\r
+ /// COMをComInteropを経由せずにいじるための関数集\r
+ /// </summary>\r
+ public sealed class ComDirectAccess\r
+ {\r
+ [DllImport("ole32.dll")]\r
+ public static extern int CoInitialize(IntPtr pvReserved);\r
+ \r
+ [DllImport("ole32.dll")]\r
+ public static extern void CoUninitialize();\r
+ \r
+ [DllImport("ole32.dll", ExactSpelling=true, PreserveSig=false)]\r
+ [return: MarshalAs(UnmanagedType.Interface)]\r
+ static extern object CoCreateInstance(\r
+ [In, MarshalAs(UnmanagedType.LPStruct)] Guid rclsid,\r
+ [MarshalAs(UnmanagedType.IUnknown)] object pUnkOuter,\r
+ CLSCTX dwClsContext,\r
+ [In, MarshalAs(UnmanagedType.LPStruct)] Guid riid);\r
+ \r
+ [Flags()]\r
+ public enum CLSCTX : uint\r
+ {\r
+ CLSCTX_INPROC_SERVER = 0x1,\r
+ CLSCTX_INPROC_HANDLER = 0x2,\r
+ CLSCTX_LOCAL_SERVER = 0x4,\r
+ CLSCTX_INPROC_SERVER16 = 0x8,\r
+ CLSCTX_REMOTE_SERVER = 0x10,\r
+ CLSCTX_INPROC_HANDLER16 = 0x20,\r
+ CLSCTX_RESERVED1 = 0x40,\r
+ CLSCTX_RESERVED2 = 0x80,\r
+ CLSCTX_RESERVED3 = 0x100,\r
+ CLSCTX_RESERVED4 = 0x200,\r
+ CLSCTX_NO_CODE_DOWNLOAD = 0x400,\r
+ CLSCTX_RESERVED5 = 0x800,\r
+ CLSCTX_NO_CUSTOM_MARSHAL = 0x1000,\r
+ CLSCTX_ENABLE_CODE_DOWNLOAD = 0x2000,\r
+ CLSCTX_NO_FAILURE_LOG = 0x4000,\r
+ CLSCTX_DISABLE_AAA = 0x8000,\r
+ CLSCTX_ENABLE_AAA = 0x10000,\r
+ CLSCTX_FROM_DEFAULT_CONTEXT = 0x20000,\r
+ CLSCTX_INPROC = CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER,\r
+ CLSCTX_SERVER = CLSCTX_INPROC_SERVER|CLSCTX_LOCAL_SERVER|CLSCTX_REMOTE_SERVER,\r
+ CLSCTX_ALL = CLSCTX_SERVER|CLSCTX_INPROC_HANDLER,\r
+ }\r
+ \r
+ private ComDirectAccess()\r
+ {\r
+ }\r
+ \r
+ public static object CreateInstance(Guid rclsid, object pUnkOuter, CLSCTX dwClsContext, Guid riid)\r
+ {\r
+ return CoCreateInstance(rclsid, pUnkOuter, dwClsContext, riid);\r
+ }\r
+ \r
+ public static T CreateInstance<T>(Guid clsid, CLSCTX dwClsContext)\r
+ {\r
+ Guid riid = new Guid(((GuidAttribute) Attribute.GetCustomAttribute(typeof(T), typeof(GuidAttribute))).Value);\r
+ return (T) CreateInstance(clsid, null, dwClsContext, riid);\r
+ }\r
+ }\r
+}\r
--- /dev/null
+using System;\r
+using System.Reflection;\r
+using System.Collections.Generic;\r
+using System.Runtime.InteropServices;\r
+using System.Runtime.InteropServices.ComTypes;\r
+using NaGet.InteropServices;\r
+\r
+namespace NaGet.Net\r
+{\r
+ public class DownloadScanner : IDisposable\r
+ {\r
+ #region COMInterop\r
+ [Flags()]\r
+ private enum MSOAVINFOFLAG : uint {\r
+ fPath = 1,\r
+ fReadOnlyRequest = 2,\r
+ fInstalled = 4,\r
+ fHttpDownload = 8,\r
+ }\r
+ \r
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]\r
+ private struct MSOAVINFO {\r
+ public int cbsize;\r
+\r
+ [MarshalAs(UnmanagedType.U4)]\r
+ public MSOAVINFOFLAG uFlags;\r
+ \r
+ public IntPtr hwnd;\r
+\r
+ [MarshalAs(UnmanagedType.LPWStr)]\r
+ public string pwzFullPath;\r
+ [MarshalAs(UnmanagedType.LPWStr)]\r
+ public string pwzHostName;\r
+ [MarshalAs(UnmanagedType.LPWStr)]\r
+ public string pwzOrigURL;\r
+ }\r
+ \r
+ [ComImport()]\r
+ [Guid("56FFCC30-D398-11D0-B2AE-00A0C908FA49")]\r
+ [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]\r
+ private interface IOfficeAntiVirus {\r
+ void Scan(ref MSOAVINFO pmsoavinfo);\r
+ }\r
+ #endregion\r
+ \r
+ /// <summary>\r
+ /// ウイルススキャナーに渡すプログラム・ホスト名。\r
+ /// </summary>\r
+ public string HostName {\r
+ get {\r
+ // 実行アセンブリ名を返す\r
+ return Assembly.GetExecutingAssembly().GetName().FullName;\r
+ }\r
+ }\r
+ \r
+ private List<IOfficeAntiVirus> scanners;\r
+ \r
+ public DownloadScanner()\r
+ {\r
+ ComDirectAccess.CoInitialize(IntPtr.Zero);\r
+ }\r
+ \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
+ ComDirectAccess.CoUninitialize();\r
+ }\r
+ \r
+ public bool HasScanner {\r
+ get { return scanners.Count > 0; }\r
+ }\r
+ \r
+ public void Init()\r
+ {\r
+ scanners = new List<IOfficeAntiVirus>();\r
+ \r
+ Guid IID_MSOfficeAntiVirus = new Guid(((GuidAttribute) Attribute.GetCustomAttribute(typeof(IOfficeAntiVirus), typeof(GuidAttribute))).Value);\r
+ \r
+ using (GuidEnumeratorForCategories guids = new GuidEnumeratorForCategories(IID_MSOfficeAntiVirus)) {\r
+ foreach (Guid guid in guids) {\r
+ IOfficeAntiVirus oav = ComDirectAccess.CreateInstance<IOfficeAntiVirus>(guid, ComDirectAccess.CLSCTX.CLSCTX_INPROC_SERVER);\r
+ \r
+ scanners.Add(oav);\r
+ }\r
+ }\r
+ }\r
+ \r
+ public bool Scan(string path, string origin)\r
+ {\r
+ if (scanners.Count <= 0) {\r
+ return false;\r
+ }\r
+ \r
+ MSOAVINFO info = new MSOAVINFO();\r
+ info.cbsize = Marshal.SizeOf(info);\r
+ info.uFlags = MSOAVINFOFLAG.fPath | MSOAVINFOFLAG.fHttpDownload;\r
+ info.hwnd = IntPtr.Zero;\r
+ info.pwzFullPath = path;\r
+ info.pwzHostName = HostName;\r
+ info.pwzOrigURL = origin;\r
+ \r
+ foreach (IOfficeAntiVirus i in scanners) {\r
+ i.Scan(ref info);\r
+ }\r
+ return true;\r
+ }\r
+ }\r
+}\r
--- /dev/null
+using System;\r
+using System.Collections.Generic;\r
+using Microsoft.Win32;\r
+\r
+namespace NaGet.Net\r
+{\r
+ /// <summary>\r
+ /// ICatManagerの暫定的かつピュアC#実装\r
+ /// </summary>\r
+ class GuidEnumeratorForCategories : IEnumerable<Guid>, IDisposable\r
+ {\r
+ private RegistryKey key;\r
+ \r
+ private string[] subkeys;\r
+ \r
+ private Guid catGuid;\r
+ \r
+ public GuidEnumeratorForCategories(Guid category)\r
+ {\r
+ key = Registry.ClassesRoot.OpenSubKey(@"CLSID", false);\r
+ subkeys = key.GetSubKeyNames();\r
+ catGuid = category;\r
+ }\r
+ \r
+ public void Dispose()\r
+ {\r
+ if (key != null) {\r
+ key.Close();\r
+ }\r
+ }\r
+ \r
+ \r
+ public IEnumerator<Guid> GetEnumerator()\r
+ {\r
+ return _getEnumerator();\r
+ }\r
+ \r
+ System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()\r
+ {\r
+ return _getEnumerator();\r
+ }\r
+ \r
+ private IEnumerator<Guid> _getEnumerator()\r
+ {\r
+ // レジストリ内のImplemented Category内の値と比較する値\r
+ string strCategory = catGuid.ToString("B").ToUpper();\r
+ \r
+ foreach (string subkey in subkeys) {\r
+ // "CLSID"、基本タイプ("...046}")は無視する\r
+ if ((subkey == "CLSID") ||\r
+ subkey.EndsWith("-0000-0000-C000-000000000046}", StringComparison.OrdinalIgnoreCase)) {\r
+ continue;\r
+ }\r
+\r
+ // Implemented Categoryにあれば、subkeyをGUIDに変換して返す\r
+ RegistryKey guidKey = key.OpenSubKey(string.Format(@"{0}\Implemented Categories\{1}", subkey, strCategory), false);\r
+ if (guidKey != null) {\r
+ guidKey.Close();\r
+ yield return new Guid(subkey);\r
+ }\r
+ }\r
+ }\r
+ }\r
+}\r
InstalledPackage = package;\r
}\r
\r
+ /// <summary>\r
+ /// インストーラファイルを取得する\r
+ /// </summary>\r
+ public string InstallerFile {\r
+ get { return installerFile; }\r
+ }\r
+ \r
+ \r
#region インストーラ状態チェック関連\r
\r
/// <summary>\r
}\r
\r
/// <summary>\r
+ /// インストーラファイルをスキャンする\r
+ /// </summary>\r
+ /// <remarks>ウイルスのため退避・削除されたときも例外を投げずにあたかも正常かのように動作しえます。</remarks>\r
+ /// <exception cref="ComException">スキャンで意図せぬ動作があったとき</exception>\r
+ /// <exception cref="FileNotFoundException">スキャン後にインストーラファイルが存在しないとき</exception>\r
+ /// <param name="scanner">スキャナーオブジェクト</param>\r
+ public void ScanInstallerFile(DownloadScanner scanner)\r
+ {\r
+ Exception e = null;\r
+ try {\r
+ scanner.Scan(installerFile, InstalledPackage.Installer[installerIndex].Url.Href);\r
+ } catch (System.Runtime.InteropServices.COMException ex) {\r
+ e = ex;\r
+ }\r
+ \r
+ if (! File.Exists(installerFile)) {\r
+ // ファイルが消されているならばFileNotFoundExceptionを出す\r
+ throw new FileNotFoundException(string.Empty, installerFile, e);\r
+ } else if ( e != null ) {\r
+ // ファイルが消されていないが例外が発生していたときは、その例外を投げる\r
+ throw e;\r
+ }\r
+ }\r
+ \r
+ /// <summary>\r
/// ハッシュ検証のためのハッシュの種類の数を返す\r
/// </summary>\r
/// <returns>ハッシュの個数</returns>\r
\r
for (int i =0; i < Installations.Length; i++) {\r
taskSetNames.Add(string.Format("取得: {0}", Installations[i].ToString()));\r
+ taskSetNames.Add(string.Format("ウイルススキャン: {0}", Installations[i].ToString()));\r
}\r
taskSetNames.Add("インストーラの検証");\r
for (int i =0; i < Installations.Length; i++) {\r
currentTaskSetIndex = 0;\r
packageInstallerDownloaded = false;\r
\r
- runDownloadInstallers();\r
+ runDownloadAndVirusCheckInstallers();\r
if (done) return; // もしrunDownloadInstallers()内でエラー終了していたなら終了\r
\r
packageInstallerDownloaded = true;\r
}\r
\r
foreach (Installation inst in Installations) {\r
- string installTaskMsg = inst.ToString();\r
+ string installTaskMsg = TaskSetNames[currentTaskSetIndex];\r
if (inst.Silent && (!inst.SupportsSilentOnly)) {\r
installTaskMsg += " (サイレントインストール)";\r
}\r
\r
\r
/// <summary>\r
- /// 処理内容のダウンロード部分のサブルーチン\r
+ /// 処理内容のダウンロード・ウイルススキャン部分のサブルーチン\r
/// </summary>\r
- private void runDownloadInstallers()\r
+ private void runDownloadAndVirusCheckInstallers()\r
{\r
+ using (DownloadScanner scanner = new DownloadScanner()) {\r
+ scanner.Init();\r
foreach (Installation inst in Installations) {\r
if (! inst.IsInstallablePackage()) {\r
string msg = string.Format("{0}はインストールすることができません", inst.ToString());\r
return;\r
}\r
\r
- RaiseTaskSetEvent(NaGetTaskSetEventType.STARTED_TASKSET, inst.ToString());\r
+ RaiseTaskSetEvent(NaGetTaskSetEventType.STARTED_TASKSET, TaskSetNames[currentTaskSetIndex]);\r
\r
if (! inst.Downloaded) {\r
try {\r
currentTaskSetIndex ++;\r
\r
if (inst.Downloaded) { // 正常終了\r
- RaiseTaskSetEvent(NaGetTaskSetEventType.COMPLETED_TASKSET, inst.ToString());\r
+ RaiseTaskSetEvent(NaGetTaskSetEventType.COMPLETED_TASKSET, TaskSetNames[currentTaskSetIndex]);\r
} else { // インストールが完了せずに終わった=失敗=エラー\r
RaiseTaskSetEvent(NaGetTaskSetEventType.ERROR, string.Format("{0}のインストーラを正常にダウンロードできませんでした", inst.ToString()));\r
+ done = true;\r
+ return;\r
}\r
+ \r
+ RaiseTaskSetEvent(NaGetTaskSetEventType.STARTED_TASKSET, TaskSetNames[currentTaskSetIndex]);\r
+ if (scanner.HasScanner) {\r
+ try {\r
+ inst.ScanInstallerFile(scanner);\r
+ } catch (System.Runtime.InteropServices.COMException ex) {\r
+ RaiseTaskSetEvent(NaGetTaskSetEventType.WARNING,\r
+ string.Format("{0} (E{1})", ex.Message, ex.ErrorCode));\r
+ } catch (System.IO.FileNotFoundException ex) {\r
+ if (ex.InnerException is System.Runtime.InteropServices.COMException) {\r
+ RaiseTaskSetEvent(NaGetTaskSetEventType.WARNING,\r
+ string.Format("{0} (E{1})", ex.InnerException.Message, ((System.Runtime.InteropServices.COMException) ex.InnerException).ErrorCode));\r
+ }\r
+ RaiseTaskSetEvent(NaGetTaskSetEventType.ERROR, "インストーラがウイルススキャナによって削除されました。");\r
+ done = true;\r
+ return;\r
+ }\r
+ } else {\r
+ RaiseTaskSetEvent(NaGetTaskSetEventType.INFO, string.Format("ダウンロードしたファイルはウイルススキャンされませんでした(ウイルススキャンソフトが検出できませんでした)"));\r
+ }\r
+ RaiseTaskSetEvent(NaGetTaskSetEventType.COMPLETED_TASKSET, TaskSetNames[currentTaskSetIndex]);\r
}\r
}\r
+ }\r
\r
/// <summary>\r
/// ダウンロードしたパッケージが整合したか否かハッシュでチェック\r
</ItemGroup>\r
<ItemGroup>\r
<Compile Include="AssemblyInfo.cs" />\r
+ <Compile Include="NaGet.InteropServices\ComDirectAccess.cs" />\r
<Compile Include="NaGet.InteropServices\CommonArchiverExtracter.cs" />\r
<Compile Include="NaGet.InteropServices\CreateProcessCaller.cs" />\r
<Compile Include="NaGet.InteropServices\DllAccess.cs" />\r
<Compile Include="NaGet.InteropServices\PEFileInfoUtils.cs" />\r
<Compile Include="NaGet.InteropServices\ShellLink.cs" />\r
+ <Compile Include="NaGet.Net\DownloadScanner.cs" />\r
+ <Compile Include="NaGet.Net\GuidEnumeratorForCategories.cs" />\r
<Compile Include="NaGet.Packages.Install\DependeciesResolver.cs" />\r
<Compile Include="NaGet.Packages.Install\InstallationLog.cs" />\r
<Compile Include="NaGet.Packages\PackageListsManager.cs" />\r