推荐.NET教程: ASP.NET C# 开发环境 Ajax教程 控件开发 统计报表 数据库 Web服务 安装部署 CommunityServer NHibernate DataGrid/GridView 实用代码 VS2005
posts - 31, comments - 84, trackbacks - 4, articles - 0

在WinForm应用程序中实现自动升级

Posted on 2007-06-14 11:48 伊飏 阅读(6715) 评论(48)  编辑 收藏 网摘 所属分类: 备忘录

这是本人第一次写比较复杂的文章,表达不清之处,请各位见谅。好,闲话少说,入正题。

最近单位开发一个项目,其中需要用到自动升级功能。因为自动升级是一个比较常用的功能,可能会在很多程序中用到,于是,我就想写一个自动升级的组件,在应用程序中,只需要引用这个自动升级组件,并添加少量代码,即可实现自动升级功能。因为我们的程序中可能包含多个exe或者dll文件,所以要支持多文件的更新。

首先,要确定程序应该去哪里下载需要升级的文件。我选择了到指定的网站上去下载,这样比较简单,也通用一些。在这个网站上,需要放置一个当前描述最新文件列表的文件,我们估且叫它服务器配置文件。这个文件保存了当前最新文件的版本号(lastver),大小(size),下载地址(url),本地文件的保存路径(path),还有当更新了这个文件后,程序是否需要重新启动(needRestart)。这个文件大致如下:
updateservice.xml

<?xml version="1.0" encoding="utf-8"?>
<updateFiles>
  
<file path="AutoUpdater.dll"  url="http://update.iyond.com/CompanyClientApplication/AutoUpdater.zip" lastver="1.0.0.0" size="28672" needRestart="true" />
  
<file path="CompanyClient.exe"  url="http://update.iyond.com/CompanyClientApplication/CompanyClient.zip" lastver="1.1.0.0" size="888832 " needRestart="true" />
  
<file path="HappyFenClient.dll"  url="http://update.iyond.com/CompanyClientApplication/HappyFenClient.zip" lastver="1.0.0.0" size="24576" needRestart="true" />
  
<file path="NetworkProvider.dll"  url="http://update.iyond.com/CompanyClientApplication/NetworkProvider.zip" lastver="1.0.0.0" size="32768" needRestart="true" />
  
<file path="Utility.dll"  url="http://update.iyond.com/CompanyClientApplication/Utility.zip" lastver="1.0.0.0" size="20480" needRestart="true" />
  
<file path="Wizard.dll"  url="http://update.iyond.com/CompanyClientApplication/Wizard.zip" lastver="1.0.0.0" size="24576"  needRestart="true" />
</updateFiles>

同时,客户端也保存了一个需要升级的本地文件的列表,形式和服务器配置文件差不多,我们叫它本地配置文件。其中,<Enable>节点表示是否启用自动升级功能,<ServerUrl>表示服务器配置文件的地址。
update.config

<?xml version="1.0" encoding="utf-8"?>
<Config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  
<Enabled>true</Enabled>
  
<ServerUrl>http://update.iyond.com/updateservice.xml</ServerUrl>
  
<UpdateFileList>
      
<LocalFile path="AutoUpdater.dll" lastver="1.0.0.0" size="28672" />
      
<LocalFile path="CompanyClient.exe" lastver="1.1.0.0" size="888832 " />
      
<LocalFile path="HappyFenClient.dll" lastver="1.0.0.0" size="24576" />
      
<LocalFile path="NetworkProvider.dll" lastver="1.0.0.0" size="32768" />
      
<LocalFile path="Utility.dll" lastver="1.0.0.0" size="20480" />
      
<LocalFile path="Wizard.dll" lastver="1.0.0.0" size="24576"  />
  
</UpdateFileList>  
</Config>

使用自动各级组件的程序在启动时,会去检查这个配置文件。如果发现有配置文件中的文件版本和本地配置文件中描述的文件版本不一致,则提示用户下载。同时,如果本地配置文件中某些文件在服务器配置文件的文件列表中不存在,则说明这个文件已经不需要了,需要删除。最后,当升级完成后,会更新本地配置文件。

我们先来看一下如何使用这个组件。
在程序的Program.cs的Main函数中:

[STAThread]
static void Main()
{
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(
false);

    AutoUpdater au 
= new AutoUpdater();
    
try
    {
        au.Update();
    }
    
catch (WebException exp)
    {
        MessageBox.Show(String.Format(
"无法找到指定资源\n\n{0}", exp.Message), "自动升级", MessageBoxButtons.OK, MessageBoxIcon.Error);
    }
    
catch (XmlException exp)
    {
        MessageBox.Show(String.Format(
"下载的升级文件有错误\n\n{0}", exp.Message), "自动升级", MessageBoxButtons.OK, MessageBoxIcon.Error);
    }
    
catch (NotSupportedException exp)
    {
        MessageBox.Show(String.Format(
"升级地址配置错误\n\n{0}", exp.Message), "自动升级", MessageBoxButtons.OK, MessageBoxIcon.Error);
    }
    
catch (ArgumentException exp)
    {
        MessageBox.Show(String.Format(
"下载的升级文件有错误\n\n{0}", exp.Message), "自动升级", MessageBoxButtons.OK, MessageBoxIcon.Error);
    }
    
catch (Exception exp)
    {
        MessageBox.Show(String.Format(
"升级过程中发生错误\n\n{0}", exp.Message), "自动升级", MessageBoxButtons.OK, MessageBoxIcon.Error);
    }

    Application.Run(
new MainUI());
}

如上所示,只需要简单的几行代码,就可以实现自动升级功能了。

软件运行截图:






下面,我们来详细说一下这个自动升级组件的实现。
先看一下类图:

AutoUpdater:自动升级的管理类,负责整体的自动升级功能的实现。
Config:配置类,负责管理本地配置文件。
DownloadConfirm:一个对话框,向用户显示需要升级的文件的列表,并允许用户选择是否马上升级。
DownloadFileInfo:要下载的文件的信息
DownloadProgress:一个对话框,显示下载进度。
DownloadProgress.ExitCallBack,
DownloadProgress.SetProcessBarCallBack,
DownloadProgress.ShowCurrentDownloadFileNameCallBack:由于.NET2.0不允许在一个线程中访问另一个线程的对象,所以需要通过委托来实现。
LocalFile:表示本地配置文件中的一个文件
RemoteFile:表示服务器配置文件中的一个文件。
UpdateFileList:一个集合,从List<LocalFile>继承

我们先整体看一下AutoUpdater.cs:
AutoUpdater.cs

在构造函数中,我们先要加载配置文件:
public AutoUpdater()
{
    config 
= Config.LoadConfig(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, FILENAME));
}

最主要的就是Update()这个函数了。当程序调用au.Update时,首先检查当前是否开户了自动更新:
        if (!config.Enabled)
            
return;

如果启用了自动更新,就需要去下载服务器配置文件了:
        WebClient client = new WebClient();
        
string strXml = client.DownloadString(config.ServerUrl);

然后,解析服务器配置文件到一个Dictionary中:
        Dictionary<string, RemoteFile> listRemotFile = ParseRemoteXml(strXml);

接下来比较服务器配置文件和本地配置文件,找出需要下载的文件和本地需要删除的文件:
        List<DownloadFileInfo> downloadList = new List<DownloadFileInfo>();
        
//某些文件不再需要了,删除
        List<LocalFile> preDeleteFile = new List<LocalFile>();

        
foreach (LocalFile file in config.UpdateFileList)
        
{
            
if (listRemotFile.ContainsKey(file.Path))
            
{
                RemoteFile rf 
= listRemotFile[file.Path];
                
if (rf.LastVer != file.LastVer)
                
{
                    downloadList.Add(
new DownloadFileInfo(rf.Url, file.Path, rf.LastVer, rf.Size));
                    file.LastVer 
= rf.LastVer;
                    file.Size 
= rf.Size;

                    
if (rf.NeedRestart)
                        bNeedRestart 
= true;
                }


                listRemotFile.Remove(file.Path);
            }

            
else
            
{
                preDeleteFile.Add(file);
            }

        }


        
foreach (RemoteFile file in listRemotFile.Values)
        
{
            downloadList.Add(
new DownloadFileInfo(file.Url, file.Path, file.LastVer, file.Size));
            config.UpdateFileList.Add(
new LocalFile(file.Path, file.LastVer, file.Size));

            
if (file.NeedRestart)
                bNeedRestart 
= true;
        }


如果发现有需要下载的文件,则向用户显示这些文件,并提示其是否马上更新。如果用户选择了马上更新,则先删除本地不再需要的文件,然后开始下载更新文件。
        if (downloadList.Count > 0)
        
{
            DownloadConfirm dc 
= new DownloadConfirm(downloadList);

            
if (this.OnShow != null)
                
this.OnShow();

            
if (DialogResult.OK == dc.ShowDialog())
            
{
                
foreach (LocalFile file in preDeleteFile)
                
{
                    
string filePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, file.Path);
                    
if (File.Exists(filePath))
                        File.Delete(filePath);

                    config.UpdateFileList.Remove(file);
                }


                StartDownload(downloadList);
            }

        }


我们再来看一下StartDownload函数
    private void StartDownload(List<DownloadFileInfo> downloadList)
    
{
        DownloadProgress dp 
= new DownloadProgress(downloadList);
        
if (dp.ShowDialog() == DialogResult.OK)
        
{
            
//更新成功
            config.SaveConfig(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, FILENAME));

            
if (bNeedRestart)
            
{
                MessageBox.Show(
"程序需要重新启动才能应用更新,请点击确定重新启动程序。""自动更新", MessageBoxButtons.OK, MessageBoxIcon.Information);
                Process.Start(Application.ExecutablePath);
                Environment.Exit(
0);
            }

        }

    }


在这个函数中,先调用DownloadProgress下载所有需要下载的文件,然后更新本地配置文件,最后,如果发现某些更新文件需要重新启动应用程序的话,会提示用户重新启动程序。

至此,AutoUpdater这个类的使命就完成了,其实,整个的升级过程也就完成了。(废话)。

最后,我们来看一下这个组件是如何下载更新文件的
DownloadProgress.cs

在构造函数中,将要下载的文件列表传进来
        public DownloadProgress(List<DownloadFileInfo> downloadFileList)
        
{
            InitializeComponent();

            
this.downloadFileList = downloadFileList;
        }


在Form的Load事件中,启动下载线程,开始下载。
        private void OnFormLoad(object sender, EventArgs e)
        
{
            evtDownload 
= new ManualResetEvent(true);
            evtDownload.Reset();
            Thread t 
= new Thread(new ThreadStart(ProcDownload));
            t.Name 
= "download";
            t.Start();
        }


下载线程没什么特殊的,使用了WebClient的异步下载文件函数DownloadFileAsync,并且注册了两个事件,分别负责下载进度显示和下载完成后的处理:
                clientDownload.DownloadProgressChanged += new DownloadProgressChangedEventHandler(OnDownloadProgressChanged);
                clientDownload.DownloadFileCompleted 
+= new AsyncCompletedEventHandler(OnDownloadFileCompleted);

大家看一下就明白了。
        private void ProcDownload()
        
{
            evtPerDonwload 
= new ManualResetEvent(false);

            
foreach (DownloadFileInfo file in this.downloadFileList)
            
{
                total 
+= file.Size;
            }


            
while (!evtDownload.WaitOne(0false))
            
{
                
if (this.downloadFileList.Count == 0)
                    
break;

                DownloadFileInfo file 
= this.downloadFileList[0];


                
//Debug.WriteLine(String.Format("Start Download:{0}", file.FileName));

                
this.ShowCurrentDownloadFileName(file.FileName);

                
//下载
                clientDownload = new WebClient();

                clientDownload.DownloadProgressChanged 
+= new DownloadProgressChangedEventHandler(OnDownloadProgressChanged);
                clientDownload.DownloadFileCompleted 
+= new AsyncCompletedEventHandler(OnDownloadFileCompleted);

                evtPerDonwload.Reset();

                clientDownload.DownloadFileAsync(
new Uri(file.DownloadUrl), Path.Combine(AppDomain.CurrentDomain.BaseDirectory, file.FileFullName + ".tmp"), file);
                
                
//等待下载完成
                evtPerDonwload.WaitOne();

                clientDownload.Dispose();
                clientDownload 
= null;

                
//移除已下载的文件
                this.downloadFileList.Remove(file);
            }


            
//Debug.WriteLine("All Downloaded");

            
if (this.downloadFileList.Count == 0)
                Exit(
true);
            
else
                Exit(
false);

            evtDownload.Set();
        }


最后,在OnDownloadFileCompleted函数中进行最后的处理。包括备份原文件,替换现有文件等。
        void OnDownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
        
{
            DownloadFileInfo file 
= e.UserState as DownloadFileInfo;
            nDownloadedTotal 
+= file.Size;
            
this.SetProcessBar(0, (int)(nDownloadedTotal * 100 / total));
            
//Debug.WriteLine(String.Format("Finish Download:{0}", file.FileName));
            
//替换现有文件
            string filePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, file.FileFullName);
            
if (File.Exists(filePath))
            
{
                
if (File.Exists(filePath + ".old"))
                    File.Delete(filePath 
+ ".old");

                File.Move(filePath, filePath 
+ ".old");
            }


            File.Move(filePath 
+ ".tmp", filePath);
            
//继续下载其它文件
            evtPerDonwload.Set();
        }


其它的函数只是一些显示进度条和下载信息的,这里就不再详细介绍了。大家可以下载源码看一下。

最后说一下,由于个人能力和时间的问题,这个组件还有一些不完善的地方,比如配置文件比较复杂等,如果您对这个组件有什么改进的话,请务必发给我一份,我的邮件是:iyondkoo@gmail.com.谢谢。


再做个广告:VS2005专业教程站是小弟最近做的一个网站,主要是提供VS2005、ASP.NET相关教程,希望大家有什么问题可以去看一下,同时给我提些建议。谢谢大家啦。

源码下载

Feedback

#1楼   回复  引用    

2007-06-14 12:43 by abc[未注册用户]
赞一个!

#2楼   回复  引用  查看    

2007-06-14 12:46 by 无意      
mark 以后有用

#3楼   回复  引用    

2007-06-14 12:52 by 匿名用户[未注册用户]
winform为什么不用clickone?

#4楼   回复  引用    

2007-06-14 12:54 by hotsource[未注册用户]
顶你……

#5楼   回复  引用  查看    

2007-06-14 13:45 by 肥仔鱼      
不错,值得好好研究一下,这种直接升级的套件,我在Delphi下用过;这样比clickone的好处就是不需要安装,而且可以做到部分升级

#6楼   回复  引用  查看    

2007-06-14 14:17 by 东吴居士      
看了下,写的不错,学习了下。但和一个很专一的自动更新组件差距还很大。。例如支持更新文件CRC校验,防止恶意文件。还有就是用更新组件可以更新自己(更新组件)等。。。
  有个问题,你比较了版本号,并没有比较谁新谁旧,只要不同就下载。那还不如比较文件二进制,这个连版本号都不用设置,呵呵

#7楼[楼主]   回复  引用  查看    

2007-06-14 14:32 by 伊飏      
嗯,我上面也说了,由于个人能力和时间的问题,这个组件还不是很完善,楼上说的支持更新文件CRC校验,防止恶意文件确实是不错的功能。以后有时间的话,一定会加上的。

版本号的问题我是这样考虑的:自动升级的前提是-服务器配置文件上的文件是最新的,客户端不可能有比服务器上还要新的程序。所以,只要本地配置文件的版本号和服务器配置文件的版本号不一样,肯定是服务器上的是正确的。

不比较新旧的另一个好处是:如果某一次发布的更新中有比较大的BUG的话,可以使用上一个版本替换新的版本,如果客户端已经下载了含有BUG的新版本,软件再次启动时,会自动下载上一个版本,而不会因为它的时间比较旧而不下载。

另外说明一下,目前这个组件可以更新自己:)

#8楼   回复  引用    

2007-06-14 14:38 by 加大码[未注册用户]
不知道可不可以压缩下载,如果更新的文件比较大的话,下载会很慢。

#9楼   回复  引用  查看    

2007-06-14 15:01 by 东吴居士      
呵呵,你的解释是合理的。不检测是合理的,当然如果完整的产品或许可以给他很多选项,比如比较日期,binary,versioNO等。。
  刚看了下你的代码,你的确可以实现更新自己,可能要改下代码。。你是先copy到temp下然后再move过去。不过好像需要设置needrestart =true..需要退出更新程序然后启动后在move过去
还有 DownloadFileInfo file = this.downloadFileList[0];
这个是为了防止别人盗版你的代码还是示范一下还是我没看懂,那里是不是要放个循环download的或者类似dowload Thread pool的? :)

#10楼   回复  引用  查看    

2007-06-14 15:03 by 钱彦云      
先收藏一下,以后看

#11楼   回复  引用  查看    

2007-06-14 15:05 by 东吴居士      
加大码 :
他的文件已经zip了,dll,exe可以压缩的,不过有些文件好像压缩了也没变小多少。。
伊飏 :
 你可以写个工具,选中多个要更新的文件,批量压缩批量上传(ftp) 到server上,包括server 配置的xml

#12楼[楼主]   回复  引用  查看    

2007-06-14 15:19 by 伊飏      
这个组件并没有实现压缩传输。服务器配置文件里的文件扩展名是zip,只是简单的将扩展名从exe改成了zip,完全是为了下载方便,并不是真正的压缩。

#13楼[楼主]   回复  引用  查看    

2007-06-14 15:21 by 伊飏      
DownloadFileInfo file = this.downloadFileList[0];
这一句是从当前要下载的队列中得到第一个文件,没有其它的用处。

#14楼   回复  引用  查看    

2007-06-14 21:03 by YAO.NET℡      
今天怎么这么多说自动升级的
http://www.cnblogs.com/gofixiao/archive/2007/06/14/782972.html" target="_new">http://www.cnblogs.com/gofixiao/archive/2007/06/14/782972.html


#15楼   回复  引用    

2007-06-15 08:12 by finesite
看你的 vs2005.com 怎么和51aspx.com相似的呢? 先收藏

#16楼   回复  引用  查看    

2007-06-15 08:31 by 小隐任行      
不过我不知道
updateservice.xml
这个文件是从哪里来的?
手工自己写嘛?那就我狂晕...

#17楼   回复  引用  查看    

2007-06-15 08:49 by 怀念家驹      
最好每个组件或总体加上升级引起的变更内容的说明提示给客户端,让用户知道升级了哪些功能,修正了哪些bug。

#18楼[楼主]   回复  引用  查看    

2007-06-15 08:50 by 伊飏      
finesite:和51aspx的站长比较熟,直接用了他的界面,呵呵。
小隐任行:目前是直接写的。如果文件不多的话,还是可以忍受的吧。如果文件太多的话,可以写一个自动发布工具,包括FTP上传并且更新服务器配置文件。

#19楼   回复  引用    

2007-06-15 17:32 by linqingfeng[未注册用户]
加上文件的hash码的效验会不会好点
毕竟远程传输有时后会出毛病 :)

#20楼   回复  引用    

2007-06-15 21:20 by zz[未注册用户]
很好!!!,
Hash码是对的,有传输问题 好办

#21楼   回复  引用    

2007-06-27 11:26 by 珊瑚
mark

#22楼   回复  引用    

2007-09-12 11:15 by 孙廷历[未注册用户]
用2005实现了一下,可以很顺利的运行,可是在2003下不能用同样的方法来实现,因为1.0的类库中,WebClient 没有这两个事件:
clientDownload.DownloadProgressChanged += new DownloadProgressChangedEventHandler(OnDownloadProgressChanged);
clientDownload.DownloadFileCompleted += new AsyncCompletedEventHandler(OnDownloadFileCompleted);
没有这两个相应的事件,我在2003下很难按你的思路来实现升级,
楼主,如果用VS 2003来实现的话,可以吗,如果行的话,能不能发一个2003版本的自动升级的这样的组件给我一下,不胜感激,我的邮箱:stl_1983@163.com
谢谢!

#23楼   回复  引用    

2007-10-17 17:23 by magicblack[未注册用户]
这个源码怎么在其他程序中调用呢? 急。。。

#24楼   回复  引用    

2007-12-21 15:07 by qj[未注册用户]
請問運行時提示Data at the root levelis invalid.Line1,position 1.
是什么原因?

#25楼   回复  引用    

2007-12-26 16:08 by 风声边界[未注册用户]
楼上的问题我也遇见了,这个是在服务器端读取updateservice.xml时出现的问题,调试时document.LoadXml(xml)里的xml值有问题,如果你选择用文本可视化工具查看的时候会发现第一行的开头会莫名其妙多出来一个空格,还无法去掉。如果在本地读取这个xml文件就不会有这个问题。我也不知道该如何解决。

顺便再问一个问题,如果我想实现能下载文件夹,如何实现?

#26楼[楼主]   回复  引用  查看    

2008-01-30 11:39 by 伊飏      
qj:你这个是XML文件编码的问题,写XML文件时,使用Utf-8,并且不添加UTF8标记。

#27楼   回复  引用  查看    

2008-02-15 08:42 by noviceliu      
你这个自动升级不错,下载后编译是dll文件.要在主程序里面调用这个dll文件吗?

#28楼   回复  引用    

2008-03-12 14:40 by xinzhu[未注册用户]
不明白,怎么实现自己更新,就是说应用程序正在运行,怎么能把自己删除呢,谢谢

#29楼   回复  引用  查看    

2008-04-27 12:19 by 超晨      
太好了,正想写一个,直接或者再加点就可以用了!谢谢!

#30楼   回复  引用  查看    

2008-06-16 10:26 by 饥饿的狼      
做个记号

#31楼   回复  引用  查看    

2008-06-25 11:05 by 抛物线      
最近有个项目,客户群体不定,所以要自动升级,这几天有可能开始考虑添加自动升级功能,看了文章之后,感觉很不错,没有细看,但是让我心里踏实很多。做的时候可以借鉴,谢谢作者。

#32楼   回复  引用    

2008-06-26 17:10 by martin214[未注册用户]
能实现 AutoUpdater 的自我更新么?????

#33楼   回复  引用    

2008-09-12 11:23 by xhong[未注册用户]
正好用上,谢谢楼主

#34楼   回复  引用  查看    

2008-09-14 13:18 by 置身珠海,学习与奋斗      
调用AutoUpdater的主程序,更新后直接出错。

是不是主程序不可以更新?

#35楼   回复  引用    

2008-12-18 16:28 by hansonsu[未注册用户]
在.net2005中用您的 例子 下载下来的文件什么大小 变成0字节了?

#36楼   回复  引用  查看    

2008-12-22 16:31 by 漠北的天空      
写得不错,刚好用上;在vs2008下也可以

#37楼   回复  引用  查看    

2008-12-28 22:25 by 巴西球星      
楼主,好像不支持文本文件的升级,比如1.txt

#38楼   回复  引用    

2009-01-05 16:23 by 程序新人[未注册用户]
我用了你的控件,"取消"操作不行,正在更新时,点"取消"按钮,弹出窗口后,点"否"后,再点"取消"按钮就没有反应了.问一下博主,这个问题怎么解决呢?谢谢.

#39楼   回复  引用  查看    

2009-02-06 16:32 by poop      
有点看不懂哦 。。

#40楼   回复  引用    

2009-03-09 10:58 by 网友[未注册用户]
十分感谢!
size大小是服务器端文件的真实大小 吗?
我的怎么老师报这个错啊 ?
《“45197”的值对于“Value”无效。“Value”应介于 'minimum' 和 'maximum' 之间。
参数名: Value》

#43楼   回复  引用    

2009-04-06 12:28 by 一个小鸟
请问博主。为什么这个自动更新在vs2005里面。运行没有问题。但是更新完了以后。下载下来的文件就变成了0kb了。非常急。请博主赐教

#44楼   回复  引用    

2009-04-06 12:31 by 一个小鸟
因为更新完了以后客户端的EXE文件变成了0字节。所以也就没有办法再运行客户端程序了。也就是更新完了。客户端的程序也就完了。请问有遇到这个问题的吗。请赐教。

#45楼   回复  引用    

2009-04-27 14:49 by 职业[未注册用户]
请问我把你源代码下下来之后
然后放入vs2005里为什么跑不出来报错
说启动项那个是“0”个加载
谢谢楼主了
急~!!
我邮箱wufan_14245670@163.com
把你完整得源代码
发过来谢谢了啊

#46楼   回复  引用    

2009-04-30 11:10 by unn[未注册用户]
运行到Download的this.objWebResponse = (HttpWebResponse)this.objWebRequest.GetResponse();
时报错:
远程服务器返回错误: (502) 错误的网关。
请问这是什么问题呀?

#47楼   回复  引用    

2009-06-02 11:40 by cdblh[未注册用户]
@martin214
更新自己(autoupdate.dll)如何操作?

#48楼   回复  引用    

2009-06-04 09:12 by yangxq5858
不知上面提出的问题是否已经处理了?



发表评论

昵称: [登录] [注册]

主页:

邮箱:(仅博主可见)

评论内容:

  登录  注册

[使用Ctrl+Enter键快速提交评论]

0 783301




相关文章:

相关链接: