using system;
using system.drawing;
using system.collections;
using system.componentmodel;
using system.windows.forms;
namespace msdnout
{
/// <summary>
/// 反編譯微軟msdn2003文檔并保存到數據庫的程序主窗體
/// </summary>
public class dlgmsdnout : system.windows.forms.form
{
/******************************************************************************************
聲明:本程序只是研究性的程序,沒有損害微軟對msdn的版權的意圖,并承認
微軟對 msdn , microsoft help 2.0 sdk , hxs文件格式,msde 等版權所有權
本程序能反編譯微軟msdn2003的幫助文檔,并將反編譯結果保存到一個sqlserver數據庫中
本文件為一個獨立的c#代碼文件,不需要依賴任何其他文件,使用vs.net建立一個
c#的默認名稱空間為msdnout的windows應用程序后將該文件內容覆蓋掉系統自動生成
的form1.cs文件內容即可編譯通過并執行,本程序在微軟.net框架1.1簡體中文版的
windows2000server環境下測試通過, mdac版本2.7,數據庫服務器為msde,版本8.00.760(sp3)
本程序假定你將msdn2003安裝在 c:/program files/msdn/2003feb/2052
還假定安裝了 microsoft help 2.0 sdk , 并假定安裝在目錄
"c:/program files/microsoft help 2.0 sdk" , 該sdk安裝文件可在微軟網站下載
本程序長時間頻繁的讀寫臨時文件,因此可以使用一個虛擬硬盤工具在
物理內存中虛擬一個磁盤,這樣可以大大加快程序的運行速度
可在 http://down1.tech.sina.com.cn/cgi-bin/download/download.cgi?s_id=3761&num=1
下載一個虛擬硬盤工具
程序使用的數據庫為mssqlserver,在此使用了msde,由于msde的單個數據庫
大小限制在2gb內,而msdn文件總共超過了2gb,因此程序運行時還根據需要
切換數據庫,本程序使用的數據庫文件保存在 f:/db 下面
使用前請執行以下sql語句來初始化數據庫
create database msdn1 on (name = msdn1, filename = f:/db/msdn1.mdf )";
create table [msdnfilelist] (
[mfileid] [int] not null ,
[mfilename] [varchar] (200) collate chinese_prc_ci_as not null ,
[mdbname] [varchar] (10) collate chinese_prc_ci_as null ,
[mfilelength] [int] null ,
constraint [pk_msdnfilelist] primary key clustered
(
[mfilename]
) on [primary]
) on [primary]
go
create table [msdnfile] (
[mfileid] [int] not null ,
[mfilecontent] [image] null ,
constraint [pk_msdnfile] primary key clustered
(
[mfileid]
) on [primary]
) on [primary] textimage_on [primary]
*****************************************************************************************/
/// <summary>
/// 取消操作標記
/// </summary>
private bool bolcancel = false ;
/// <summary>
/// 暫停操作標記
/// </summary>
private bool bolpause = false ;
/// <summary>
/// 主數據庫連接字符串
/// </summary>
private system.data.sqlclient.sqlconnection mainconn = null;
/// <summary>
/// 文檔數據庫連接字符串
/// </summary>
private system.data.sqlclient.sqlconnection dataconn = null;
/// <summary>
/// 插入文檔列表的命令對象
/// </summary>
private system.data.sqlclient.sqlcommand insertnamecmd = null;
/// <summary>
/// 查詢文檔內容的命令對象
/// </summary>
private system.data.sqlclient.sqlcommand insertcmd = null;
/// <summary>
/// 保存文檔數據的數據庫名稱
/// </summary>
private string currentdbname = "msdn1" ;
/// <summary>
/// 進行數據處理的線程對象
/// </summary>
private system.threading.thread mythread = null;
/// <summary>
/// 初始化數據庫連接
/// </summary>
private void initdb()
{
if( mainconn != null)
{
mainconn.dispose();
dataconn.dispose();
insertnamecmd.dispose();
}
// 打開數據庫連接
mainconn = new system.data.sqlclient.sqlconnection();
dataconn = new system.data.sqlclient.sqlconnection();
mainconn.connectionstring = "integrated security=sspi;persist security info=false;initial catalog=msdn1;data source=(local)";
dataconn.connectionstring = "integrated security=sspi;persist security info=false;initial catalog=" + currentdbname + ";data source=(local)";
mainconn.open();
dataconn.open();
insertnamecmd = mainconn.createcommand();
insertnamecmd.commandtext = "insert into msdnfilelist(mfileid, mfilename, mdbname, mfilelength) values (@mfileid, @mfilename, @mdbname, @mfilelength) ";
insertnamecmd.parameters.add(new system.data.sqlclient.sqlparameter("@mfileid", system.data.sqldbtype.int, 4, "mfileid"));
insertnamecmd.parameters.add(new system.data.sqlclient.sqlparameter("@mfilename", system.data.sqldbtype.varchar, 200, "mfilename"));
insertnamecmd.parameters.add(new system.data.sqlclient.sqlparameter("@mdbname", system.data.sqldbtype.varchar, 10, "mdbname"));
insertnamecmd.parameters.add(new system.data.sqlclient.sqlparameter("@mfilelength", system.data.sqldbtype.int, 4, "mfilelength"));
initinsertcmd();
}
/// <summary>
/// 初始化插入數據內容的命令對象
/// </summary>
private void initinsertcmd()
{
if( insertcmd != null)
insertcmd.dispose();
insertcmd = dataconn.createcommand();
insertcmd.commandtext = "insert into msdnfile(mfileid, mfilecontent) values (@mfileid, @mfilecontent)";
insertcmd.parameters.add(new system.data.sqlclient.sqlparameter("@mfileid", system.data.sqldbtype.int, 4, "mfileid"));
insertcmd.parameters.add(new system.data.sqlclient.sqlparameter("@mfilecontent", system.data.sqldbtype.varbinary, 2147483647, "mfilecontent"));
}
/// <summary>
/// 反編譯msdn文檔的主程序
/// </summary>
private void msdnout()
{
try
{
// 檢查msdn安裝目錄
string strmsdndir [email protected]"c:/program files/msdn/2003feb/2052";
if( system.io.directory.exists( strmsdndir) == false)
return ;
// 檢查反編譯器程序
string strexefile = @"c:/program files/microsoft help 2.0 sdk/hxcomp.exe";
if( system.io.file.exists( strexefile ) == false)
return ;
// 準備臨時文件目錄
string stroutdir = this.txtoutpath.text ;
if( stroutdir == null || stroutdir.trim().length == 0)
return ;
stroutdir = stroutdir.trim();
if( system.io.directory.exists( stroutdir ) == false)
system.io.directory.createdirectory( stroutdir );
string strtemppath = system.io.path.combine( stroutdir , "temp");
if( system.io.directory.exists( strtemppath ) == false)
system.io.directory.createdirectory( strtemppath );
bolcancel = false;
bolpause = false;
initdb();
using(system.data.sqlclient.sqlcommand mycmd = mainconn.createcommand())
{
mycmd.commandtext = "delete from msdnfile";
mycmd.executenonquery();
mycmd.commandtext = "delete from msdnfilelist";
mycmd.executenonquery();
}
int dbcount = 1 ;
long filesizecount = 0 ;
long totalfilesize = 0 ;
int filecount = 0 ;
string[] strfilenames = system.io.directory.getfiles( strmsdndir , "*.hxs");
this.invokesetlabeltext( this.lbldb , "當前數據庫:" + currentdbname );
invokesetprogress( this.mainprogress , strfilenames.length , 0 );
long hxsfilesize = 0 ;
// 計算所有要處理的文件的長度
foreach( string strfilename in strfilenames)
{
system.io.fileinfo myinfo = new system.io.fileinfo( strfilename );
hxsfilesize += myinfo.length ;
}
long hxfilesizecount = 0 ;
// 計算單個數據庫所能保存的數據大小,在此設置為1000mb
int dbmaxsize = 1000 * 1024 * 1024 ;
// 分別處理單個hxs文檔
for(int hxsfilecount = 0 ; hxsfilecount < strfilenames.length ; hxsfilecount ++ )
{
if( bolcancel ) break;
string strfilename = ( string ) strfilenames[ hxsfilecount ];
system.io.fileinfo myinfo = new system.io.fileinfo( strfilename );
hxfilesizecount += myinfo.length ;
invokesetprogress( this.mainprogress , (int)(hxsfilesize >> 5) , (int)( hxfilesizecount >> 5 ) );
string strmodlename = system.io.path.getfilenamewithoutextension( strfilename ) + "//" ;
invokesetlabeltext( lblfile , "正在處理第 " + hxsfilecount + " 個文件 " + system.io.path.getfilename( strfilename ) + " " + myinfo.length + " 字節 ..." );
invokesetlabeltext( lblstate ,"正在反編譯..." );
string stroutsubdir = system.io.path.combine( stroutdir ,"temp");
if( system.io.directory.exists( stroutsubdir) == false)
system.io.directory.createdirectory( stroutsubdir );
int basepathlength = ( stroutsubdir.endswith("//") ? stroutsubdir.length : stroutsubdir.length + 1 ) ;
// 執行命令行程序來反編譯hxs文檔
string strcmd = " -d " + stroutsubdir + " -u /"" + strfilename + "/" -i -e -w -q";
system.diagnostics.processstartinfo mypinfo = new system.diagnostics.processstartinfo( strexefile , strcmd );
mypinfo.createnowindow = true;
mypinfo.useshellexecute = false;
system.diagnostics.process myprocess = system.diagnostics.process.start( mypinfo );
myprocess.waitforexit();
if( bolcancel ) break;
// 找到所有反編譯所得的文件
system.collections.arraylist mynames = getfilenames( stroutsubdir );
invokesetlabeltext(lblstate , "正在導入到數據庫,共 " + mynames.count + " 個文件 ..." );
for( int icount = 0 ; icount < mynames.count ; icount ++ )
{
try
{
if( bolpause ) mythread.suspend();
bolpause = false;
invokesetprogress( this.myprogress , mynames.count , icount );
if( bolcancel ) break;
// 讀取臨時文件數據
string strtempfilename = (string)mynames[icount];
system.io.fileinfo mytempinfo = new system.io.fileinfo( strtempfilename );
byte[] bytdata = new byte[ (int)mytempinfo.length ];
system.io.filestream myfile = new system.io.filestream( strtempfilename , system.io.filemode.open );
myfile.read( bytdata , 0 , bytdata.length );
myfile.close();
insertnamecmd.parameters[0].value = filecount;
insertnamecmd.parameters[1].value = strmodlename + strtempfilename.substring( basepathlength );
insertnamecmd.parameters[2].value = currentdbname ;
insertnamecmd.parameters[3].value = bytdata.length ;
insertcmd.parameters[0].value = filecount ;
insertcmd.parameters[1].value = bytdata ;
if( bolcancel ) break;
insertnamecmd.executenonquery();
insertcmd.executenonquery();
filesizecount += bytdata.length ;
totalfilesize += bytdata.length ;
filecount ++ ;
// 更換數據庫
if( filesizecount > dbmaxsize )
{
dbcount ++ ;
currentdbname = "msdn" + dbcount.tostring();
invokesetlabeltext( lblstate , "更換數據庫為 " + currentdbname );
insertcmd.dispose();
using( system.data.sqlclient.sqlcommand mycmd = mainconn.createcommand())
{
mycmd.commandtext ="create database " + currentdbname + " on (name = " + currentdbname + ", filename = f://db//" + currentdbname + ".mdf )";
mycmd.executenonquery();
}
insertcmd.dispose();
dataconn.changedatabase( currentdbname );
using( system.data.sqlclient.sqlcommand mycmd = dataconn.createcommand())
{
mycmd.commandtext = @"
create table [msdnfile] (
[mfileid] [int] not null ,
[mfilecontent] [image] null ,
constraint [pk_msdnfile] primary key clustered
(
[mfileid]
) on [primary]
) on [primary] textimage_on [primary]
";
mycmd.executenonquery();
}//using
invokesetlabeltext(lbldb , "當前數據庫:" + currentdbname );
initinsertcmd();
filesizecount = 0 ;
}//if
}//try
catch(exception ext)
{
system.windows.forms.messagebox.show( ext.tostring());
initdb();
filecount ++ ;
}
}//for
invokesetprogress( this.myprogress , mynames.count , 0 );
invokesetlabeltext( lblstate , "正在刪除臨時文件..." );
system.io.directory.delete( stroutsubdir , true );
invokesetlabeltext( lblstate , "操作完畢");
}//for
string strdir2 = system.io.path.combine( stroutdir ,"temp");
if( system.io.directory.exists( strdir2 ))
system.io.directory.delete( strdir2 , true );
insertnamecmd.dispose();
insertcmd.dispose();
invokesetprogress( this.mainprogress ,1 , 0 );
}//try
catch(exception ext)
{
system.windows.forms.messagebox.show( ext.tostring());
}
this.begininvoke( new system.eventhandler( this.endprocess) , new object[]{null,null});
mainconn.close();
mainconn.dispose();
dataconn.close();
dataconn.dispose();
}//public void msdnout()
/// <summary>
/// 獲得指定目錄及下層目錄下所有的文件的絕對路徑文件名
/// </summary>
/// <param name="strrootdir">根目錄</param>
/// <returns>保存文件名的列表對象</returns>
public system.collections.arraylist getfilenames( string strrootdir)
{
system.collections.arraylist mylist = new system.collections.arraylist();
string[] strnames = system.io.directory.getfiles( strrootdir , "*.*");
if( strnames != null && strnames.length > 0 )
{
mylist.addrange( strnames );
}
strnames = system.io.directory.getdirectories( strrootdir , "*.*");
if( strnames != null && strnames.length > 0 )
{
foreach( string strdir in strnames )
{
mylist.addrange( getfilenames ( strdir ));
}
}
return mylist ;
}//public getfilenames()
#region 處理用戶界面的代碼群 **************************************************************
public delegate void setlabeltexthandler( system.windows.forms.label lbl , string text );
public delegate void setprogressbarhandler( system.windows.forms.progressbar pb , int vmaxvalue , int vvalue);
private void invokesetprogress( system.windows.forms.progressbar pb , int vmaxvalue , int vvalue)
{
this.invoke( new setprogressbarhandler( this.setprogressbar ) , new object[]{ pb , vmaxvalue , vvalue });
}
private void invokesetlabeltext( system.windows.forms.label lbl , string text )
{
this.invoke( new setlabeltexthandler( this.setlabeltext ) , new object[]{ lbl , text });
}
private void setlabeltext( system.windows.forms.label lbl , string text )
{
lbl.text = text ;
lbl.refresh();
}
private void setprogressbar ( system.windows.forms.progressbar pb , int vmaxvalue , int vvalue)
{
if( pb.maximum != vmaxvalue )
pb.maximum = vmaxvalue ;
if( vvalue >= 0 && vvalue <= vmaxvalue )
pb.value = vvalue ;
}
private void endprocess( object sender , system.eventargs e )
{
txtoutpath.enabled = true;
cmdstart.enabled = true;
cmdstop.enabled = false;
cmdpose.enabled = false;
}
private void cmdstart_click(object sender, system.eventargs e)
{
cmdstart.enabled = false;
txtoutpath.enabled = false;
cmdstop.enabled = true;
cmdpose.enabled = true;
system.threading.threadstart st = new system.threading.threadstart( this.msdnout );
mythread = new system.threading.thread(st);
mythread.start();
}
private void cmdstop_click(object sender, system.eventargs e)
{
bolcancel = true;
}
private void cmdpose_click(object sender, system.eventargs e)
{
bolpause = true;
system.windows.forms.messagebox.show("正在暫停");
bolpause = false;
mythread.resume();
}
#endregion
#region 系統自動生成的代碼 ****************************************************************
private system.windows.forms.label label1;
private system.windows.forms.textbox txtoutpath;
private system.windows.forms.label lblfile;
private system.windows.forms.button cmdstart;
private system.windows.forms.button cmdstop;
private system.windows.forms.label lbldb;
private system.windows.forms.label lblstate;
private system.windows.forms.progressbar myprogress;
private system.windows.forms.progressbar mainprogress;
private system.windows.forms.button cmdpose;
/// <summary>
/// 必需的設計器變量。
/// </summary>
private system.componentmodel.container components = null;
public dlgmsdnout()
{
//
// windows 窗體設計器支持所必需的
//
initializecomponent();
//
// todo: 在 initializecomponent 調用后添加任何構造函數代碼
//
}
/// <summary>
/// 清理所有正在使用的資源。
/// </summary>
protected override void dispose( bool disposing )
{
if( disposing )
{
if(components != null)
{
components.dispose();
}
}
base.dispose( disposing );
}
/// <summary>
/// 應用程序的主入口點。
/// </summary>
[stathread]
static void main(string[] args)
{
system.windows.forms.application.run( new dlgmsdnout());
}//main
#endregion
#region windows 窗體設計器生成的代碼 ******************************************************
/// <summary>
/// 設計器支持所需的方法 - 不要使用代碼編輯器修改
/// 此方法的內容。
/// </summary>
private void initializecomponent()
{
this.label1 = new system.windows.forms.label();
this.txtoutpath = new system.windows.forms.textbox();
this.lblfile = new system.windows.forms.label();
this.cmdstart = new system.windows.forms.button();
this.cmdstop = new system.windows.forms.button();
this.lbldb = new system.windows.forms.label();
this.lblstate = new system.windows.forms.label();
this.myprogress = new system.windows.forms.progressbar();
this.mainprogress = new system.windows.forms.progressbar();
this.cmdpose = new system.windows.forms.button();
this.suspendlayout();
//
// label1
//
this.label1.autosize = true;
this.label1.location = new system.drawing.point(16, 16);
this.label1.name = "label1";
this.label1.size = new system.drawing.size(72, 17);
this.label1.tabindex = 0;
this.label1.text = "臨時文件夾:";
//
// txtoutpath
//
this.txtoutpath.location = new system.drawing.point(96, 16);
this.txtoutpath.name = "txtoutpath";
this.txtoutpath.size = new system.drawing.size(352, 21);
this.txtoutpath.tabindex = 1;
this.txtoutpath.text = "c://msdnout";
//
// lblfile
//
this.lblfile.autosize = true;
this.lblfile.location = new system.drawing.point(16, 168);
this.lblfile.name = "lblfile";
this.lblfile.size = new system.drawing.size(91, 17);
this.lblfile.tabindex = 2;
this.lblfile.text = "當前處理的文件";
//
// cmdstart
//
this.cmdstart.location = new system.drawing.point(16, 48);
this.cmdstart.name = "cmdstart";
this.cmdstart.tabindex = 3;
this.cmdstart.text = "開始";
this.cmdstart.click += new system.eventhandler(this.cmdstart_click);
//
// cmdstop
//
this.cmdstop.location = new system.drawing.point(96, 48);
this.cmdstop.name = "cmdstop";
this.cmdstop.tabindex = 4;
this.cmdstop.text = "結束";
this.cmdstop.click += new system.eventhandler(this.cmdstop_click);
//
// lbldb
//
this.lbldb.autosize = true;
this.lbldb.location = new system.drawing.point(16, 88);
this.lbldb.name = "lbldb";
this.lbldb.size = new system.drawing.size(66, 17);
this.lbldb.tabindex = 5;
this.lbldb.text = "當前數據庫";
//
// lblstate
//
this.lblstate.autosize = true;
this.lblstate.location = new system.drawing.point(16, 112);
this.lblstate.name = "lblstate";
this.lblstate.size = new system.drawing.size(29, 17);
this.lblstate.tabindex = 6;
this.lblstate.text = "狀態";
//
// myprogress
//
this.myprogress.location = new system.drawing.point(16, 136);
this.myprogress.name = "myprogress";
this.myprogress.size = new system.drawing.size(432, 23);
this.myprogress.tabindex = 7;
//
// mainprogress
//
this.mainprogress.location = new system.drawing.point(16, 192);
this.mainprogress.name = "mainprogress";
this.mainprogress.size = new system.drawing.size(432, 23);
this.mainprogress.tabindex = 8;
//
// cmdpose
//
this.cmdpose.enabled = false;
this.cmdpose.location = new system.drawing.point(176, 48);
this.cmdpose.name = "cmdpose";
this.cmdpose.tabindex = 9;
this.cmdpose.text = "暫停";
this.cmdpose.click += new system.eventhandler(this.cmdpose_click);
//
// dlgmsdnout
//
this.autoscalebasesize = new system.drawing.size(6, 14);
this.clientsize = new system.drawing.size(466, 223);
this.controls.add(this.cmdpose);
this.controls.add(this.mainprogress);
this.controls.add(this.myprogress);
this.controls.add(this.lblstate);
this.controls.add(this.lbldb);
this.controls.add(this.lblfile);
this.controls.add(this.txtoutpath);
this.controls.add(this.label1);
this.controls.add(this.cmdstop);
this.controls.add(this.cmdstart);
this.formborderstyle = system.windows.forms.formborderstyle.fixeddialog;
this.maximizebox = false;
this.name = "dlgmsdnout";
this.startposition = system.windows.forms.formstartposition.centerscreen;
this.text = "導出msdn";
this.resumelayout(false);
}
#endregion
}//public class dlgmsdnout
}