小李菜刀

沉迷于程序开发中....

博客园 首页 新随笔 联系 订阅 管理
  6 Posts :: 0 Stories :: 21 Comments :: 3 Trackbacks

发一篇以前写的一个旧文,申请Blog好久了,要是再不发东西可就被Kill了。
      在.net中使用Com对象大家第一个反应就是在工程中引用Com对象,让vs.net自动生成一个包装过的.net类库。这种方法虽然方便,但是有很明显的缺点,最致命的就是开发的机器上安装的Com对象的版本比客户机器上安装的高,开发的程序无法正确的运行。如开发机器安装的是office 2003,而客户机器上的安装的确是office 2000、office xp甚至还有安装的是Office97,这种情况我想大家都深有体会吧?    
      在非托管语言如Delphi中可以通过CreateComObject来生成一个Com对象,然后再使用Variant对象去调用Com对象的属性、方法。可因C#是一种强类型的语言,他没有象Delphi中的Variant这中可变类型,因此只能通过反射去完成。
      晚上心血来潮就封装了一个Variant对象来模拟一下Delphi中的Variant。

 示例代码:

            //生成Excel对象
            using (Variant excel = Variant.CreateComInstance("Excel.Application"))
            
{
                
//显示Excel界面
                excel["Visible"= true;
                
//获取workBooks对象
                using (Variant workBooks = Variant.CreateInstance(excel["Workbooks"]))
                
{
                    
//建立一个Workbook
                    using (Variant workBook = Variant.CreateInstance(workBooks.InvokeMethod("Add")))
                    
{

                        
for (int i = 1; i < 10; i++)
                        
{
                            
for (int j = 1; j < 10; j++)
                            
{
                                
//根据指定的索引获得一个单元格
                                using (Variant cell = Variant.CreateInstance(excel["Cells", i, j]))
                                
{
                                    
//设置单元格的值
                                    cell["Value"= i * j;
                                    Console.WriteLine(cell[
"Value"]);
                                }

                            }

                        }

                    }

                }

                
//excel.InvokeMethod("Quit");
            }


这样的方式是不是爽多了?那些讨厌的可选参数终于不用再写了!

 

Variant类源码:

 

Using directives

class Variant : IDisposable        
{
    Variant() 
{ }
    
object _obj;
    Type _objType;
    
bool _isComObj = false;

    
public static Variant CreateComInstance(string progID)
    
{
        Variant variant 
= new Variant();
        variant._objType 
= Type.GetTypeFromProgID(progID);
        variant._obj 
= Activator.CreateInstance(variant._objType);
        
        variant._isComObj 
= true;
        
return variant;
    }

    
public static Variant CreateInstance(string objectTypeName)
    
{
        Variant variant 
= new Variant();
        variant._objType 
= Type.GetType(objectTypeName);
        variant._obj 
= Activator.CreateInstance(variant._objType);
        
return variant;
    }

    
public static Variant CreateInstance(object obj)
    
{
        Variant variant 
= new Variant();
        variant._objType 
= obj.GetType();
        variant._obj 
= obj;
        variant._isComObj 
= obj.GetType().ToString() == "System.__ComObject";
        
return variant;
    }

    
public int ReleaseComObject()
    
{
        
try
        
{
            
if (_isComObj)
                
return Marshal.ReleaseComObject(_obj);
            
else
                
throw new Exception("_obj is not com Object");
        }

        
catch
        
{
            
throw;
        }

    }

    
public object InvokeMethod(string methodName,params object[] parameters)
    
{
        
try
        
{
            
return _objType.InvokeMember(methodName,
                BindingFlags.InvokeMethod,
                
null, _obj, parameters);
        }

        
catch
        
{
            
throw;
        }

    }


    
    
public object GetPropertyValue(string propertyName, params object[] parameters)
    
{
        
try
        
{
            
return _objType.InvokeMember(propertyName,
                BindingFlags.GetProperty,
                
null, _obj, parameters);
        }

        
catch
        
{
            
throw;
        }

    }

    
public void SetPropertyValue(string propertyName, object value, params object[] parameters)
    
{
        
if (value as DBNull != null)
            value 
= null;
        
string s = value as string;
        
if (s != null && s.Length == 0)
            value 
= null;

        
if (_isComObj)
        
{
            
try
            
{
                
object[] args = new object[parameters.Length + 1];
                Array.Copy(parameters, 
0, args, 1, parameters.Length);
                args[
0= value;
                _objType.InvokeMember(propertyName,
                    BindingFlags.SetProperty,
                    
null, _obj, args);
            }

            
catch
            
{
                
throw;
            }

            
return;
        }


        PropertyInfo pi 
= _objType.GetProperty(propertyName);

        
if (pi != null)
        
{
            
if (pi.CanWrite)
            
{
                
try
                
{
                    pi.SetValue(_obj, 
null == value ?
                        
null :
                        (pi.PropertyType.IsInterface 
?
                            value :
                            Convert.ChangeType(value, pi.PropertyType)
                        ),
                        parameters);
                }

                
catch (Exception E)
                
{
                    
throw new Exception(String.Format("设置属性{0}时出错!属性的类型是{1}值的类型是{2} 错误信息:{3}", pi.Name, pi.PropertyType.FullName, value.GetType().FullName, null == E.InnerException ? E.Message : E.InnerException.Message));
                }

            }

            
else
                
throw new Exception(pi.PropertyType.ToString());
        }

        
else
            
throw new Exception(String.Format("{0}属性未在{1}中定义!", pi.Name, _obj.GetType().FullName));
    }


    
public object this[string propertyName, params object[] parameters]
    
{
        
get return GetPropertyValue(propertyName, parameters); }
        
set { SetPropertyValue(propertyName, value, parameters); }
    }


    
IDisposable Members
}

 

其实Varaint类不光可以调用Com对象,对于托管对象也可以动态的创建和调用。

欢迎大家斧正!

posted on 2004-09-17 22:12 小李菜刀 阅读(4487) 评论(8) 编辑 收藏

Feedback

#1楼 2004-09-17 23:44 Yu      
hi,小李菜刀

看到一个让人感觉亲切的名字。:-)

你不是Mack.Z?

前一阵子就看到这篇文章发到了博客园。可惜作者不是你。hoho...我第一次看到是小李菜刀发在了微软中国新闻组...记得当时我应该有回邮件,只是说了什么就记不清了。。:P

地址:
http://www.mscommunity.com/article/article.asp?old=0&id=1311

不知道你是不是Mack.Z,如果不是的话,那么下面的这位朋友可能抄袭了你的文章?你们是朋友?:)

地址:
http://www.cnblogs.com/mack/articles/35714.aspx

 回复 引用 查看   

#2楼 2004-09-18 09:14 小李菜刀
我在网上就用一个名字就是小李菜刀(英文caidaoli),不管是在新闻组还在其它地方,这篇文章我最早发在微软的新闻组中。希望转载的朋友不要忘记把作者小李菜刀放上去。
 回复 引用   

#3楼 2004-09-18 13:04 Mack.Z      
小李兄..我已在引用你的文章中加上你的大名了!:)
http://www.cnblogs.com/mack/articles/35714.aspx

 回复 引用 查看   

#4楼 2004-09-18 14:50 hBifTs      
不错啊:)
 回复 引用 查看   

#5楼 2004-09-18 20:01 Yu
hi, Mack.Z

早在接近一个月前我就有提醒过你,现在才加?
真不想说这种行为叫做剽窃。:-) 以后注意点吧。拿来主义不是这样子的,请尊重别人的付出。

 回复 引用   

#6楼 2004-10-11 23:45 steve      
Ping Back
 回复 引用 查看   

#7楼 2007-07-09 14:32 Tom[未注册用户]
菜刀大哥,反射Excel的事件怎么反射的啊?
 回复 引用