最近项目中需要做一个bs上传整个文件夹的功能,然而只有选择文件的控件,所以需要自己动手写一个activex控件,参考了很多资料,最后终于有了点结果,与大家分享。
[制作axtivex]
第一步:建立vs2005工程,“新建项目”-“类库”。
第二步:添加新“组件”。
第三步:修改assemblyInfo文件,
using System.Security;
// 将 ComVisible 设置为 false 使此程序集中的类型
// 对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型,
// 则将该类型上的 ComVisible 属性设置为 true。
[assembly: ComVisible(true)]
[assembly: AllowPartiallyTrustedCallers()]
// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
//[assembly: Guid("40ec502e-6b66-41f9-860f-ab30339c8e63")]
第四步:将guid复制到类名前,
[Guid("40ec502e-6b66-41f9-860f-ab30339c8e63")]
public partial class dirselect : Component, IObjectSafety
{
第五步:继承IObjectSafety接口
using System.Runtime.InteropServices;
[Guid("CB5BDC81-93C1-11CF-8F20-00805F2CD064"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IObjectSafety
{
[PreserveSig]
void GetInterfaceSafetyOptions(ref Guid riid,
[MarshalAs(UnmanagedType.U4)] ref int pdwSupportedOptions,
[MarshalAs(UnmanagedType.U4)] ref int pdwEnabledOptions);
[PreserveSig()]
void SetInterfaceSafetyOptions(ref Guid riid,
[MarshalAs(UnmanagedType.U4)] int dwOptionSetMask,
[MarshalAs(UnmanagedType.U4)] int dwEnabledOptions);
}
给自定义组件类dirselect 继承接口,并实现接口方法:
public partial class dirselect : Component, IObjectSafety
void IObjectSafety.GetInterfaceSafetyOptions(ref Guid riid, ref int pdwSupportedOptions, ref int pdwEnabledOptions)
{
pdwSupportedOptions = 1;
pdwEnabledOptions = 2;
}
void IObjectSafety.SetInterfaceSafetyOptions(ref Guid riid, int dwOptionSetMask, int dwEnabledOptions)
{
throw new Exception("The method or operation is not implemented.");
}
第六步,编写自己的函数方法。
如我的完整代码如下:
using System;
using System.ComponentModel;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using System.Runtime.InteropServices;
namespace dirselect
{
[Guid("CB5BDC81-93C1-11CF-8F20-00805F2CD064"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IObjectSafety
{
[PreserveSig]
void GetInterfaceSafetyOptions(ref Guid riid,
[MarshalAs(UnmanagedType.U4)] ref int pdwSupportedOptions,
[MarshalAs(UnmanagedType.U4)] ref int pdwEnabledOptions);
[PreserveSig()]
void SetInterfaceSafetyOptions(ref Guid riid,
[MarshalAs(UnmanagedType.U4)] int dwOptionSetMask,
[MarshalAs(UnmanagedType.U4)] int dwEnabledOptions);
}
[Guid("40ec502e-6b66-41f9-860f-ab30339c8e63")]
public partial class dirselect : Component, IObjectSafety
{
private string strSelectedDir = string.Empty;
private string[] strAllFiles = null;
private int iFilesCount = 0;
void IObjectSafety.GetInterfaceSafetyOptions(ref Guid riid, ref int pdwSupportedOptions, ref int pdwEnabledOptions)
{
pdwSupportedOptions = 1;
pdwEnabledOptions = 2;
}
void IObjectSafety.SetInterfaceSafetyOptions(ref Guid riid, int dwOptionSetMask, int dwEnabledOptions)
{
throw new Exception("The method or operation is not implemented.");
}
public dirselect()
{
InitializeComponent();
}
public dirselect(IContainer container)
{
container.Add(this);
InitializeComponent();
}
/// <summary>
/// 选择文件夹
/// </summary>
/// <returns>是否选择了</returns>
public string showDlg()
{
folderBrowserDialog1.Description = "请选择需要上传的文件夹:";
if (folderBrowserDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
strSelectedDir = folderBrowserDialog1.SelectedPath;
strAllFiles = System.IO.Directory.GetFiles(strSelectedDir, "*", System.IO.SearchOption.AllDirectories);
iFilesCount = strAllFiles.Length;
return strSelectedDir;
}
return string.Empty;
}
/// <summary>
/// 返回选择的文件夹
/// </summary>
/// <returns></returns>
public string GetSelctedDir()
{
return strSelectedDir;
}
/// <summary>
/// 返回该文件夹下所有文件数目
/// </summary>
/// <returns></returns>
public int GetFilesCount()
{
return iFilesCount;
}
返回该文件夹下所有文件路径
//public string[] GetFiles()
//{
// string[] FileInfos = System.IO.Directory.GetFiles(strSelectedDir, "*", System.IO.SearchOption.AllDirectories);
// return FileInfos;
//}
//返回该文件夹下所有文件路径中的第ige
public string GetFile(int i)
{
return strAllFiles[i];
}
}
}
最后生成dll。这样acticex就做好了。
测试发布
第一步:新建一个web网站项目,修改项目属性,生成到iis
第二步:在主页中添加html代码
<html xmlns="http://www.w3.org/1999/xhtml" >
<body color = white><hr><font face = arial size = 1>
<OBJECT id = "dirselect1" name = "dirselect1" codebase="setup.exe" classid = "clsid:40ec502e-6b66-41f9-860f-ab30339c8e63" >
</OBJECT>
</font>
<form name = "frm" id = "frm" ><input type = button value = "选择文件夹" onClick ="doScript(); ">
</form>
<hr>
</body>
<script language = "javascript">
function doScript()
{
var t = dirselect1.showDlg();
alert(t);
if(t!="")
{
var i=0;
var cnt = dirselect1.GetFilesCount();
alert(cnt);
var array = new Array(cnt);
for(i;i<3;i++)
{
array[i] = dirselect1.GetFile(i);
alert(array[i]);
}
}
}
</script>
</html>
csid还是那个assemblyInfo文件中的guid,codebase是下面安装程序工程生成的exe文件,注意你必须将他们拷贝到虚拟目录根目录下,和你发布的url一致,意思是当客户端没有安装这个activex控件的时候,就会查找安装程序,并根据你的发布地址去下载安装。
打包发布
(几种方法实验没成功,有的是缺少工具,有的是不想做,有的是没实验成,最后采用vs2005安装程序生成的安装包)
第一步:vs2005新建一个“安装程序”,将其加入到前面那个dll解决方案中
点“应用程序文件夹”-添加-“项目输出”,点击确定就可以了,默认是选择了前面那个dll工程
第二步:配置。项目属性中修改“安装URL”,这个地址应该是你发布的地址。
第三步,生成
这样就得到了安装包setup.exe和相应的msi文件。
测试
浏览器Internet选项中安全级别需要自定义,“对没有标记为安全的...”提示,这样就不会看不到安装程序了。因为有一步数字签名的我没有去弄,所以会提示“未知...”,这个待学习。
费了九牛二虎之力才弄出来,得知如果是用vs2005制作的acticex控件是要安装.net framework才能运行,还是改用vb或者vc制作算了。
给 .cab 文件签名
1. setreg 1 true
2. makecert newCert.cer -sv privatekey.pvk
生成 newCert.cer 和 privatekey.pvk 两个文件
3. Cert2Spc newCert.cer newCert.spc
4. signtool signwizard
有图形界面的签名向导,按提示指定有关文件路径即可,其中的描述是控件的描述。