2016/03/29

ATL/WTLのソースを、Visual Studio 2015 でビルドしてWindows xpでエラーにならないようにする

マニアックな需要ですか?(^_^;)
新山(へろぱ)のホームページが、ホスティングしていたプロバイダーの都合で無くなってしまったので、やむなくGoogle siteに自作ソフトウェアを置いているのですが、中のドキュメントとかの見直しをしなければ、と暇なときにドキュメント直したりソースをビルドし直したりしています。

新山(へろぱ)的優先度として、窓の杜様にも転載されているUnAceV2J.DLLのドキュメントを直すとして、せっかくなのでDLL本体もVisual Studio 2015でビルドし直そうと考えた次第です。
 WTLを使用しているので、Visual Studio 2015に対応したWTL待ちでしたが、それもリリースされていますので問題なし。
Visual C/C++ 2015もWindows xpをターゲットとしてコンパイルできるようになっています。

なのに、Windows xpで動作確認すると、オートメーションエラーとかで予期せぬエラーとなり、呼び出したアプリごと終了してしまう。

困ったなぁ~、既存のバージョンのようにVisual Studio 2010でビルドしてお茶を濁すか~とか考えていたところで、こんなサイトを発見!

Visual Studio 2015 cannot produce an ATL Dll that successfully registers on Windows XP

つまり、ビルドオプションに「/Zc:threadSafeInit-」を追加すればOKOK!

2016/03/19

車検、むっちゃ掛かった!

2001年式のニュービートル、今年で15年目。
ついさっき、車検の料金を払ってきたんだけど、むっちゃ高かった。

いや、車検自体の費用はいつもどおりなんだけど、整備費用がむっちゃ高かった。

作業内容・部品名名称 数量 単価 金額 技術料
エンジンオイル 4.0 1,600 6,400
オイルフィルター 1.0 1,700 1,700
ブレーキオイル 1.0 2,000 2,000 1,500
フロントディスクパッド 1.0 10,400 10,400 2,600
ステアリングラッツブーツ 2.0 1,900 3,800 6,100
ブーツバンド1 2.0 540 1,080
ブールバンド2 2.0 230 460
タイロッド 2.0 18,000 36,000 6,100
タイロッドエンド 2.0 7,200 14,400
タイミングベルト 1.0 8,400 8,400 26,800
タイミングテンショナーローラー 1.0 12,500 12,500
ウォーターポンプ 1.0 13,500 13,500
LLC 2.0 900 1,800
ロアアームブッシュ 2.0 4,000 8,000 21,200
ダイナモ(リビルド) 1.0 34,800 34,800 11,800
エアマスセンサー 1.0 8,000 8,000

こんな感じ。
これに、車検費用を含めて、30万円オーバー...。
まぁ、30万円でニュービートルは買えないから仕方が無いんだけど。

でも、クルマの調子は良くなった。
そうそう、新品の頃はこんなにエンジンレスポンス良かった!って思い出したくらい。
ハンドルを切るときに、途中でカクっとする変な感じも無くなっているし。
何よりも、ドアノブ内側の取っ手の取り付け部が折れてブラブラしていたのが、何気に直してくれているし。車内の清掃も完璧に綺麗だし。
これらの分の料金入ってないし。

顧客満足度100%です。素晴らしい!

2015/12/01

.NETのPathTooLongExceptionを克服する

.NET Frameworkのファイルを扱うSystem.IO辺りのクラスのメソッドは、過去の経緯(Windows 9x系をサポートする.NET Framework 1.1からの正常進化のため?)により、MAX_PATH(260)バイト以上のファイルパスが扱えません。

これ、ファイラーや、ファイルを扱うツールとしては、致命的なんじゃないだろうか?
今時の大容量なハードディスクにファイルを保存すると、階層が深くなりがちだし。音楽ファイルなんて、データフォルダパス>ジャンル>アーティスト名>アルバム名>タイトル名なパスになるし。

Microsoftは、.NET Frameworkの中身を、UNICODEバージョンのAPIをコールするように書き換えるべき。 というニーズを汲み取ったライブラリが実は存在します。
AlphaFS

これをプロジェクトからの参照設定に加えるだけで、System.IO以下のクラス・メソッド類を置き換えることができるようになります。
VBなら、Importsをコンパイルスイッチで切り替えてやれば。

#If UseAlphFS Then
Imports Alphaleonis.Win32.Filesystem
#Else
Imports System.IO
#End If

こんな感じで。

2015/11/30

.NET から IFileOperation を使う

IFileOperation インターフェースとは?

コピー、移動、名前の変更、作成、および進捗状況とエラーダイアログを提供するために、シェルの項目と同様の方法を公開したインターフェース。
従来の Windows API の SHFileOperation の機能を置き換えたもので、Windows Vista から実装されている機能だそうです。(https://msdn.microsoft.com/ja-jp/library/windows/desktop/bb775771%28v=vs.85%29.aspx)

SHFileOperation については、.NET Framework では Microsoft.VisualBasic.dll でラップされていて、Visual Basic では、My.Computew.FileSystem から呼び出すことができます。
しかし、SHFileOperation のすべての機能が使えるわけでもないし、痒い所に手が届かない感じ。

アンマネージドなコードで再実装するにしても、今さら Vista 以前の OS なんてサポートする必要なんてないから、IFileOperation で実装したほうが良いじゃん!

とか思って調べてみても、なかなか情報が集まらないが、やっと見つけたのでメモ。

MSDN マガジンのバックナンバーとダウンロード

2007年12月(December 2007)をクリックして MSDNMagazine2007_12ja-jp.chm をダウンロードします。

「MSDN Magazine December 2007」のコンパイルされたHTML ヘルプ ファイルを開いて、中身が見られない場合は、Explorer からのマウス右クリックによるファイルのプロパティ「全体」タブの下部の「セキュリティ:このファイルは他のコンピュータから取得したものです。~」の「ブロックの解除」ボタンを押下して解除すると中身は読むことができます。

その記事の「.NET の問題: Windows Vista での IFileOperation:」に記事があります。

その記事中の「コードのダウンロード」をクリックすると、サンプルのソースもダウンロードできます。

2015/11/27

Visual Studio 2015に対応したWTLがリリースされてますね

待ちに待ったVisual Studio 2015に対応したWTLがリリースされているのに、今日気が付きました。
Windows Template Library (WTL)
これで、既存のVisual Studio 2010で作成されたあれやこれやのソースも、Visual Studio 2015でビルドできるかも!

2015/11/26

C#で書かれたソースをVBに書き直す(またはその逆の)方法

二つの言語ともに精通しているなら、何も迷うこともなく移植できると思うんだけど、「あれっ?VBではどう書くんだっけ?」って手が止まる場合は、逆コンパイラを使うと良いかもね。

元のソースが、C#であろうとも、VBであろうとも、コンパイルされたものはアセンブリなので、大抵の逆コンパイラで、VBかC#なソースとして見ることができるはず。
では、逆コンパイルなツールの紹介。

古い記事なので、紹介文よりはマシになっているかも。

2015/11/20

消費者にとっての本当の幸せ

ここの記事(既にリンク消失)より
市販されている缶チューハイは、ジュースより安い。なので、未成年の飲酒や飲酒運転を助長するから何とかしないとね。という記事なのですが、記事の一番最後で、
NPO「アルコール薬物問題全国市民協会」の今成知美代表は「飲酒運転や依存症患者が社会問題になっている。消費者にとっての本当の幸せは、価格が安いことではない。増税やテレビCM禁止などの規制強化が必要だ」と話している。
というフレーズがとても気になる。
消費者にとっての本当の幸せは、ジュースの値段が缶チューハイよりも安くなることなんじゃないのだろうか?
増税をされて幸せだと思う消費者はいないと思う。
飲酒運転を防止するための施策を実施するために増税が必要って意味なら分かるんだけどね。言葉足らずなだけなんだろうか?

(2006/10/05の旧ブロク掲載の記事を転載)

2015/11/19

宇宙の孤児

電車通勤中に小説を読むので、過去に買って読んだものの、すっかり内容を忘れているSF小説を、本棚から引っ張り出して読み直しています。結構というか本当にすっかり忘れていたり、読みながら思い出したものの、当時は感じなかった事を感じたり、数百円の本で10年以上楽しめるなんて、なんてお得な性格なんだ、俺!

タイトルの「宇宙の孤児」はハインラインの初期の作品で、ケンタウリ遠征隊の大宇宙船が遠征中に一部の反乱者によって大きなダメージを受けてしまい、中の住民がケンタウリへ向かう大宇宙船の中であることさえ忘れてしまっている時代の話です。
巨大なスペースコロニーのような宇宙船で、生命維持装置は辛うじて稼動しているものの、宇宙船をシールドする装置は既に停まっていて、生まれてくる20人に1人の割合で奇形児が生まれてくる。そういったミューティーが支配する上層区画からの侵略行為を防ぎながら<船長>の政治の元で、下層の重力地帯で中世時代レベルの生活をしている<船員>たち。
賢く思考能力のあると思われる者は、<科学者>という身分で残された「本」を読み、伝承される知識を受け継ぐことができる。
主人公のヒョウは、新米の<科学者>だが、ミューティーとの争いで、ミューティーの1グループのリーダーであるジョウ=ジムに捕虜にされる。馬鹿ではなかったので、食われずにジョウ=ジムの話し相手かボードゲームの対戦相手になったりしていたが、ある時、無重力地域の「操縦室」や「船長の部屋」へ連れて行かれ、<船>が伝承の<遥かなるケンタウリ>へ動いている宇宙船だということに気が付く。

なんか基本設定は、メガゾーン23に似ていますね。(^_^;)宇宙の孤児には、ロボットも出ないし、1980年代の東京じゃなく、デザルグとも闘わないし、ナイフとパチンコしか武器の無い中世時代のような世界ですが...。

ミューティーという設定が、発表当時のベトナム戦争の枯葉作戦での被害となった奇形児の影響を受けているようだし、明らかに女性蔑視な世界だったり、現在で出版されるには、差別用語の壁が立ちはだかって難しいような感じで、そういった面からも古典SFなんだと感じるストーリーでもあります。

しかし、登場人物が当然と思っている大宇宙船内の話なので、当初読者は説明不足的な世界観に、「?」と思いながら読み進め、主人公ヒョウとともに事実(この物語の世界観)を知っていくという疑似体験をできる点は、最初読んだときに鮮烈でした。
続けて2回目、3回目と読むと、設定の緻密さにも感心するという、何度も楽しめる本でした。
(2006/01/18 旧ブログ掲載の記事を転載)

旧ブログ時のコメント

    単二
    URL: http://blog.goo.ne.jp/linkerbell/
    DATE: 01/06/2007 12:27:42 PM
    こんにちは。(^^)
    本作の原典は1941初出との由。
    http://www.inawara.com/SF/H071.html
    ベトナム戦の影響ではないようですね。
    ですが、これ、私にとってもなぜか心に残る作品です。
    いいものを思い出させてくれてありがとう。

2015/11/18

MFCで作成されたWin32 DLLをATL/WTL DLLに移植する

始めに
Visual Studio 2010でMFCをスタティックリンクするDLLを作成すると、巨大なDLLになってしまう。UnAceV2J.DLLはVisual Studio 2005と(ほとんど)同じソースをビルドするだけなのに、1.5MBを超えるようなサイズです。目を疑わんばかりの巨大さだ。昔だったら「フロッピーディスクに入りません。」と阿鼻叫喚の地獄絵図だ。(^_^;)
Microsoft Office級のアプリケーションなら許されても、ちょっとしたAPIを提供するだけのWin32 DLLとしてのこのファイルサイズは許しがたいものがある。
そこで、MFCよりもWindows APIの薄いラッパであるATL/WTLを使うようにソースを書き換えようという欲求が発生することと思う。
ただ、MFCのDLLをATL/WTLに移植するための方法がネットでなかなか発見できず、自分以外にもきっと困っている人がいるだろうという事で、ここにメモをする。
上記で触れた通り、きっかけはUnAceV2J.DLLなので、例としてUnAceV2J.DLLのソースを使用する。

作成方法のとっかかり
WTLはオープンソースであるので、ネット上から手に入れて開発環境にインストールしておく必要がある。
ATLも使用するので、Visual StudioはStandard Edition以上。筆者の環境はVisual Studio 2010 Professional Editionである。

DLLの初っ端であるDllMainについて
MFCは、グローバルなクラスとしてCWinAppのサブクラスを作成して、そのCWinAppクラスのInitInstance(), ExitInstance()などをオーバーライドしてDllMainの代わりとする。
ATL/WTLではWTL::CAppModuleクラスのサブクラスを作成してそのクラスをグローバルなクラスとして使用する。

(例)

// UnAceV2JModule.h
#pragma once

#include "atlapp.h"

class CUnAceV2JModule :
   public WTL::CAppModule
{
public:
   // DLL内のグローバルで使用する変数の宣言
   BOOL g_Running;
   HWND g_ParenthWnd;

};
 
WTL::CAppModuleクラスには、MFCのようなInitInstance(), ExitInstance()は無く、DllMain関数で定型的な処理もされないため、自分でDllMain()を実装する必要がある。
Visual Studio 2010の「新しいプロジェクト」でWin32の「Win32 プロジェクト」を選択し、ウィザードでDLLを選ぶとひな形のソースが作成されるが、dllmain.cpp内にDllMain()が作成されている。そこにWTLを使用するためのお約束事なコードを追加する。

(例)

// dllmain.cpp : DLL アプリケーションのエントリ ポイントを定義します。
#include "stdafx.h"

CUnAceV2JModule _Module;

BEGIN_OBJECT_MAP(ObjectMap)
END_OBJECT_MAP()

BOOL APIENTRY DllMain( HMODULE hModule,
                      DWORD  ul_reason_for_call,
                      LPVOID lpReserved
                    )
{
   switch (ul_reason_for_call)
   {
   case DLL_PROCESS_ATTACH:
       _Module.Init(ObjectMap, hModule, NULL);
       DisableThreadLibraryCalls(hModule);

       break;
   case DLL_THREAD_ATTACH:
   case DLL_THREAD_DETACH:
       break;
   case DLL_PROCESS_DETACH:
       _Module.Term();
       break;
   }
   return TRUE;
}

stdafx.hについて
stdafx.hには、ATL/WTLで使用するためのヘッダファイル群を定義しておき、各ヘッダファイルの先頭で必ずstdafx.hをインクルードしておく。

(例)

// stdafx.h : 標準のシステム インクルード ファイルのインクルード ファイル、または
// 参照回数が多く、かつあまり変更されない、プロジェクト専用のインクルード ファイル
// を記述します。
//

#pragma once

#include "targetver.h"

#define WIN32_LEAN_AND_MEAN             // Windows ヘッダーから使用されていない部分を除外します。

// TODO: プログラムに必要な追加ヘッダーをここで参照してください。
#define _ATL_APARTMENT_THREADED
#define _WTL_NO_AUTOMATIC_NAMESPACE 1
#define _SECURE_ATL 1
#include < atlbase.h>

#include < atlwin.h>       // ATL

#include < atlapp.h>       // WTL
#include < atlframe.h>     // WTL
#include < atlctrls.h>     // WTL
#include < atlctrlw.h>     // WTL
#include < atlmisc.h>      // WTL
#include < atlgdi.h>       // WTL
#include < atlcrack.h>
#include < atlddx.h>       // DDX/DDVを使用するため
#include < ATLComTime.h>
#include < atlcoll.h>
#include "UnAceV2JModule.h"

//extern WTL::CAppModule _Module;
extern CUnAceV2JModule _Module;  // グローバル変数を保持したいので、
                                // CAppModuleを継承したサブクラスを_Moduleとして使用する。

#include < windows.h>
ライブラリクラスの移植
MFCに存在するがATL/WTLには存在しないクラスを何とか移植しなければならない。
過去にも書いたが、CStringListは以下のマクロで対処できるみたい。

(例)

typedef CAtlList< CString, CStringElementTraits< CString > > CStringList;
例にしているUnAceV2J.DLLでは、CObListに圧縮ファイル内のファイル情報を保持する「CArchiveFileInfoクラスのポインタ」を格納して、FindFirst(), FindNext()メソッド内で参照している。hArcはCObList内に保持しているポインタなんですね~!(^^ゞ
ATL/MFCでは、CObListは存在しないが、CArchiveFileInfoのポインタを格納するCAtlListとしてテンプレート定義をすれば、既存のソースがほぼ使えるようだ。

(例)


// CObList m_list;
CAtlList< CArchiveFileInfo *> m_list;
CStdioFileクラスはないので頑張って書き換えるしかない。
AfxMessageBoxは::MessageBox関数に置き換えるが、オミットしていた親ウィンドウハンドルやタイトルを呼び出し元から調達してこなければならない。

モーダル・ダイアログ表示について
WTLのセオリ通り、ATL::CDialogImplのテンプレートとして継承したクラスを使用する。また、DDXを利用するためにWTL::CWinDataExchangeのテンプレートとして継承したクラスも使用する。

(例)
// ConfigDlg.h
#pragma once

#include "stdafx.h"
#include "resource.h"

class CConfigDlg : public CDialogImpl< CConfigDlg>, public
WTL::CWinDataExchange< CConfigDlg>
{
public:
   enum { IDD = IDD_CONFIG };

   WTL::CString m_Version;
   WTL::CString m_Copyright;

   BEGIN_DDX_MAP(CConfigDlg)
       DDX_TEXT(IDC_VERSION, m_Version)
       DDX_TEXT(IDC_COPYRIGHT, m_Copyright)
   END_DDX_MAP()

   BEGIN_MSG_MAP(CConfigDlg)
       MSG_WM_INITDIALOG(OnInitDialog)
       COMMAND_ID_HANDLER_EX(IDOK, OnOK)
       COMMAND_ID_HANDLER_EX(IDCANCEL, OnCancel)
   END_MSG_MAP()

   CConfigDlg(void);
   ~CConfigDlg(void);

   BOOL OnInitDialog(ATL::CWindow wndFocus, LPARAM lInitParam);

   void OnOK(UINT uNotifyCode, int nID, ATL::CWindow wndCtl);

   void OnCancel(UINT uNotifyCode, int nID, ATL::CWindow wndCtl);

};
例での通り、CStringはデフォルトでATL::CStringを使用するが一部WTL::CStringを使用しなければならないことがある。
ATL::CStringとWTL::CStringの間のやり取りは普通に代入で済むが、ここ何とかならないのだろうか?
MFCでは、OnOk()やOnCancel()では、自動的にダイアログのクローズ処理を行ってくれるが、ATL/WTLでは明示的に書いてやらなければ、ボタンを押しても何も起こらないので、DLLを使用するアプリケーションを強制終了する羽目になる。
またBEGIN_DDX_MAP, BEGIN_MSG_MAPマクロの引数のクラス名、コピペで作成すると別のクラスを設定していて、実行してみるとちゃんと動かない!って事になりがちなので注意。(^_^;)

(例)

// ConfigDlg.cpp
#include "StdAfx.h"
#include "ConfigDlg.h"

CConfigDlg::CConfigDlg(void)
   : m_Version(_T(""))
   , m_Copyright(_T(""))
{
}

CConfigDlg::~CConfigDlg(void)
{
}

BOOL CConfigDlg::OnInitDialog(CWindow wndFocus, LPARAM lInitParam){
   // スクリーンの中央に配置
   CenterWindow();

   // コントロール設定
   DoDataExchange(FALSE);

   return TRUE;
}

void CConfigDlg::OnOK(UINT uNotifyCode, int nID, CWindow wndCtl){
   EndDialog(nID);
}

void CConfigDlg::OnCancel(UINT uNotifyCode, int nID, CWindow wndCtl){
   EndDialog(nID);
}
上記のように定義したダイアログのクラスを以下のようにして呼ぶ。
ちなみに、MFCと違い、OnOK()やOnCancel()には引数がある。

(例)

BOOL WINAPI UnAceConfigDialog(const HWND _hwnd, LPSTR _szOptionBuffer,
const int _iMode)
{
   if (UnAceGetRunning())
       return FALSE;
   CConfigDlg dlg;
   CString s;
   s.Format("UnAceV2J.DLL Version %d.%.2d.%.2d.%.2d",
                   UnAceGetVersion() / 100,
                   UnAceGetVersion() % 100,
                   UnAceGetSubVersion() / 100,
                   UnAceGetSubVersion() % 100);
   dlg.m_Version = s;
   dlg.m_Copyright = "Copyright (C) 2004-2010 Niiyama(HEROPA)";
   return (dlg.DoModal() == IDOK);
}

MFCを使用した場合と全く同じで、このメソッド内は修正不要だった。

モードレス・ダイアログについて
モードレスダイアログも上記のモーダルダイアログと同じ感じに実装したクラスをMFCの時と同じように呼べばよい。
ただし、引数に親ウィンドウハンドルが必要で、NULLで済ませていた場合は、::GetDesktopWindow()の戻り値をセットする。
(例)

       if (m_ShowDlg) {
           if (_Module.g_ParenthWnd == NULL) {
               _Module.g_ParenthWnd = ::GetDesktopWindow();
           }
           // 状況表示ダイアログのモードレス表示
           m_ProgressDlg.Create(_Module.g_ParenthWnd);
           // モードレスは、これがないと親ウィンドウ中央に表示されない。
           m_ProgressDlg.CenterWindow(_Module.g_ParenthWnd);
           // SW_SHOWNA以外だとウィンドウが閉じた後にフォーカスが変わってアプリが困る。
           m_ProgressDlg.ShowWindow(SW_SHOWNA);
       }
(例)
       if (m_ShowDlg) {
           m_ProgressDlg.DestroyWindow();
       }

 
終わりに
というわけで、知ってしまえば僅かな手間でMFCからATL/WTLを使用したDLLに書き換えることができるはず。
作成されたバイナリファイルを比較すると
UnAceV2J.DLL 0.06 Visual Studio 2005でのMFC DLL 282,112バイト
UnAceV2J.DLL 0.07 Visual Studio 2010でのMFC DLL 1,651,712バイト
UnAceV2J.DLL 0.08(試作) Visual Studio 2010でのATL/WTL DLL 188,928バイト
てな具合で、ファイルサイズの問題が解決できるというだけでも、ATL/WTLで書き直すメリットはあるのではないかと思った。

(2010/07/26 旧ブログ掲載分を転載)

2015/11/17

SevenZipLibで、書庫ファイル(圧縮ファイル)の情報を取得する

やはり、CodePlexにあるプロジェクトで、SevenZipLibがあるので、こちらでも試してみる。 こちらは、SevenZipLib.DLLが存在するディレクトリに、7z86.DLLまたは7z64.DLLがないとダメな仕様らしい。

Imports SevenZipLib

Public Class Form1

    Private WithEvents archive As SevenZipArchive

    Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click

        Dim fileName As String = "C:\Users\heropa\Downloads\SevenZipLib_9.13.2.zip"

        archive = New SevenZipArchive(fileName)
        Try

            Debug.Print("SevenZipArchive:FilesCount:{0}", archive.Count)
            Debug.Print("SevenZipArchive:FileName:{0}", archive.FileName)
            Debug.Print("SevenZipArchive:Format:{0}", archive.Format)
            Debug.Print("SevenZipArchive:HasSubArchive:{0}", archive.HasSubArchive)
            Debug.Print("SevenZipArchive:IsClosed:{0}", archive.IsClosed)
            Debug.Print("SevenZipArchive:IsEncrypted:{0}", archive.IsEncrypted)
            Debug.Print("SevenZipArchive:IsReadOnly:{0}", archive.IsReadOnly)
            Debug.Print("SevenZipArchive:PackedSize:{0}", archive.PackedSize)
            Debug.Print("SevenZipArchive:Password:{0}", archive.Password)
            Debug.Print("SevenZipArchive:UnpackedSize:{0}", archive.UnPackedSize)

            For Each aprop As ArchiveProperty In archive.Properties
                Debug.Print("ArchiveProperty:{0}:{1}", aprop.PropertyName, aprop.Value)
            Next

            For Each entry As ArchiveEntry In archive

                Debug.Print("ArchiveEntry:FileName:{0}", entry.FileName)
                Debug.Print("ArchiveEntry:IsDirectory:{0}", entry.IsDirectory)
                Debug.Print("ArchiveEntry:IsEncrypted:{0}", entry.IsEncrypted)
                Debug.Print("ArchiveEntry:Size:{0}", entry.Size)
                Debug.Print("ArchiveEntry:Attributes:{0}", ToStringFromFileAttributes(entry.Attributes))
                Debug.Print("ArchiveEntry:Comment:{0}", entry.Comment)
                Debug.Print("ArchiveEntry:Crc:{0}", entry.Crc)
                Debug.Print("ArchiveEntry:CreationTime:{0}", entry.CreationTime)
                Debug.Print("ArchiveEntry:LastWriteTime:{0}", entry.LastWriteTime)
                Debug.Print("ArchiveEntry:LastAccessTime:{0}", entry.LastAccessTime)

            Next

        Catch ex As Exception

        Finally

            archive.Dispose()

        End Try

    End Sub

    Private Function ToStringFromFileAttributes(ByVal attr As System.IO.FileAttributes?) As String

        Dim result As New List(Of String)()

        If (attr And IO.FileAttributes.Archive) = IO.FileAttributes.Archive Then result.Add("Archive")
        If (attr And IO.FileAttributes.Compressed) = IO.FileAttributes.Compressed Then result.Add("Compressed")
        If (attr And IO.FileAttributes.Device) = IO.FileAttributes.Device Then result.Add("Device")
        If (attr And IO.FileAttributes.Directory) = IO.FileAttributes.Directory Then result.Add("Directory")
        If (attr And IO.FileAttributes.Encrypted) = IO.FileAttributes.Encrypted Then result.Add("Encrypted")
        If (attr And IO.FileAttributes.Hidden) = IO.FileAttributes.Hidden Then result.Add("Hidden")
        If (attr And IO.FileAttributes.Normal) = IO.FileAttributes.Normal Then result.Add("Normal")
        If (attr And IO.FileAttributes.NotContentIndexed) = IO.FileAttributes.NotContentIndexed Then result.Add("NotContentIndexed")
        If (attr And IO.FileAttributes.Offline) = IO.FileAttributes.Offline Then result.Add("Offline")
        If (attr And IO.FileAttributes.ReadOnly) = IO.FileAttributes.ReadOnly Then result.Add("ReadOnly")
        If (attr And IO.FileAttributes.ReparsePoint) = IO.FileAttributes.ReparsePoint Then result.Add("ReparsePoint")
        If (attr And IO.FileAttributes.SparseFile) = IO.FileAttributes.SparseFile Then result.Add("SparseFile")
        If (attr And IO.FileAttributes.System) = IO.FileAttributes.System Then result.Add("System")
        If (attr And IO.FileAttributes.Temporary) = IO.FileAttributes.Temporary Then result.Add("Temporary ")

        Return String.Join(",", result.ToArray())

    End Function

End Class
う〜ん...。Attributesがちゃんと取れない...。SevenZipSharpと同じ7-zipのDLLを呼んでいるようなので、SevenZipSharpのやり方が正しいんだろうな...。
取得できる項目も、SevenZipSharpとほとんど変わらない。ソースを見ると、圧縮後のファイルサイズや、メソッド(Zipファイルなら、Deflateとかの文字列)も取れる。
SevenZipLib自体を修正して使うか?
それなら、ソースごとプロジェクトに取り込んでしまえば良いような気がするが、SevenZipLibはC#で書かれているので取り込めない。
ライセンスの問題もあるだろうし。(SevenZipLibは、LGPL)

2015/11/16

SevenZipSharpで、書庫ファイル(圧縮ファイル)の情報を取得する

次期VB De FilMtnで、書庫ファイル(圧縮ファイル)を扱うために、何か無いかと物色中。
統合アーカイバプロジェクトは、x64に対応していないものがほとんどなので...。
CodePlexで、比較的RATINGが高いSevenZipSharpを検討してみます。

Imports SevenZip

Public Class Form1

    Private WithEvents extractor As SevenZipExtractor

    Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) 
                                                           Handles Button1.Click

        Dim archiveFile As String = "C:\SevenZipSharp\files\SevenZipSharp.7z"
        Dim libraryPath As String = System.IO.
                Path.Combine(System.IO.Path.GetDirectoryName(
                        Application.ExecutablePath), 
                        "SevenZipSharp\7z.dll")
        SevenZipExtractor.SetLibraryPath(libraryPath)
        extractor = New SevenZipExtractor(archiveFile)
        Try

            Debug.Print("SevenZipExtractor:FileName:{0}", extractor.FileName)
            Debug.Print("SevenZipExtractor:FilesCount:{0}", extractor.FilesCount)
            Debug.Print("SevenZipExtractor:IsSolid:{0}", extractor.IsSolid)
            Debug.Print("SevenZipExtractor:PackedSize:{0}", extractor.PackedSize)
            Debug.Print("SevenZipExtractor:Password:{0}", extractor.Password)
            Debug.Print("SevenZipExtractor:UnpackedSize:{0}", extractor.UnpackedSize)
            Debug.Print("SevenZipExtractor:Format:{0}", extractor.Format)

            For Each aprop As ArchiveProperty In extractor.ArchiveProperties
                Debug.Print("ArchiveProperty:{0}:{1}", aprop.Name, aprop.Value)
            Next

            For Each info As ArchiveFileInfo In extractor.ArchiveFileData()

                Debug.Print("ArchiveFileInfo:FileName:{0}", info.FileName)
                Debug.Print("ArchiveFileInfo:Index:{0}", info.Index)
                Debug.Print("ArchiveFileInfo:IsDirectory:{0}", info.IsDirectory)
                Debug.Print("ArchiveFileInfo:Size:{0}", info.Size)
                Debug.Print("ArchiveFileInfo:Attributes:{0}", info.Attributes)
                Debug.Print("ArchiveFileInfo:Comment:{0}", info.Comment)
                Debug.Print("ArchiveFileInfo:Crc:{0}", info.Crc)
                Debug.Print("ArchiveFileInfo:CreationTime:{0}", info.CreationTime)
                Debug.Print("ArchiveFileInfo:LastWriteTime:{0}", info.LastWriteTime)
                Debug.Print("ArchiveFileInfo:LastAccessTime:{0}", info.LastAccessTime)

            Next

        Catch ex As Exception

        Finally

            extractor.Dispose()

        End Try

    End Sub

End Class

こんな感じ。
SetLibraryPathメソッドで、7zファイルを指定するのがミソっぽい。
残念なことに、圧縮後のサイズを取得するプロパティが実装されていない。
ソースを追いかけると、ただ実装されていないだけ。LHMTNな表示をするためには、圧縮後のサイズがないと、Rateも表示できないし。
不採用だな。

2015/11/15

何故に「新山(へろぱ)」なのか?

昔々、パソコン通信の時代にVisual Basicのプログラミング情報を手に入れたくて、友人に薦められるがまま、Nifty-Serveに入会した。
しばらく、本名にてフォーラムを徘徊していたが、FBOCというフォーラムのシスオペであったCYBORG氏に、「ハンドル名をつけてよ。」と要請された。
で、NIfty-Serveのハンドル名のお手本の表記方法というのが、「本名(ハンドル名)」だった。
なので、オフミーティングとかでは、「へろぱさん」とか「へろぱ」とか呼ばれていた。
時は流れて、インターネットになった今でも、その表記を変えずに現在に至っている。
「で、『へろぱ』というのは、どういう意味?」と良く聞かれるのですが、大した意味は無いんです。
学生時代に、ファミコンのドラゴンクエスト3(だったと思う)の勇者の名前を決める時に、先輩が先輩
地震自身の名前を入力しようとして、
カーソルの位置を間違え、「ひ」の代わりに「へ」、「ろ」と入力したところで、間違いに気づき、修正しようとして「は」、自暴自棄になって「○」を追加して、「ぱ」と「決定」、勇者の名前は「へろぱ」となった。
それ以降、どんなゲームの名前も「へろぱ」を使用するのが慣例となった。
その事を思い出して、ハンドル名に「へろぱ」を使った次第です。
だから、「へろぱ」自体には何の意味もないのですが、Googleで「heropa」で海外のサイトを検索すると、そんな名前の外人が居るみたいですね。
念の為に言っておきますが、そのheropaさんとは、無関係で親戚でも何でもありません。
(2004/11/05 旧へろぱ的ブログ初出)
(2007/01/13 CYBORG氏の指摘により誤変換修正)
(2015/11/15 OCNブログサービスの終了により、旧へろぱ的ブログが消滅したので、こちらに転載)