两篇文件介绍了.NET平台下Drag and Drop操作的原理以及整个拖拽的过程,还分析了拖拽过程中的数据的格式。本篇是这个小系列的最后一篇,主要是通过列子介绍.NET程序如何与Windows Shell之间进行双向的文件传递,以及如何修改拖动时的图标样式。

 

一 Windows Shell

 

可能有点奇怪,介绍Drag and Drop 怎么介绍到Shell上去了。虽然拖拽的数据对象可以是任意格式的,但是我们平时拖拽的最多的还是文件,文件夹这样的对象。打开文件,发送文件,移动文件,这样的操作我们在Windows中使用的太多了。而这些都和Shell有着密切的关系。这里就简单介绍一下,详细可以参见MSDN :Windows Shell

 

1.什么是Shell

 

Shell其实也是一种程序,如果接触过unix或Linux或许比较好理解。准确的说Shell是一个命令解析器,在Windows上我们输入Cmd,在出来的窗体中可以进行一些列的系统操作,启动程序、管理文件、设置系统服务等等;而同样我们也可以在Windows提供的图形界面中操作,比如打开我的电脑管理文件、打开控制面板设置计算机。这就是我们常见的两种Shell:图形界面Shell和命令行Shell。 Shell实际是介于操作系统内核与用户之间的一个接口。

 

 

2.Windwos Shell

 

这里我们主要了解的是图形界面的Shell。Windows UI为用户提供了访问各种对象、运行程序以及管理系统的能力。在访问的众多对象中,我们最熟悉的就是文件和目录,他们都是存放在硬盘上的;但是还有一些并不是真实存在的对象,比如远程打印机和回收站,他们并不是真正的存在于硬盘之上。Shell把这些对象组织为一套层次结构,提供给用户和程序使用和管理。

 

 

3. Shell编程

 

Windows Shell最常见的部分就是桌面和任务栏,Shell所管理的对象我们可以称之为Shell Object。我们前面提到过Shell Object,但是他并不是仅仅包含文件和目录,还包含那些虚拟的对象。桌面是所有Shell Object的根,也就是层次结构中最顶层的。

对于桌面来说,它也是一个窗体,实际就是一个ListView控件,所以在窗口拖动文件,和我们在自己的程序中拖动是没有本质区别的。而资源管理器Explorer也是一个程序,通过API获得Shell 的层次结构并显示,然后提供给用户进行操作。所以我们完全可以通过使用API,在自己的程序中实现简单的Sehll功能。也可以通过对Shell编程,实现自己的功能。

关于Shell编程可以参见:Windows Shell 编程

而在CodeProject上有一个C#实现的资源管理器:http://www.codeproject.com/KB/miscctrl/FileBrowser.aspx

继续阅读

在上一篇文章介绍了在.NET中进行Drag和Drop操作的方法,以及底层的调用实现过程。实际是通过一个DoDragDrop的WIN32 API来监视拖拽过程中的鼠标,根据鼠标的位置获得IDropTraget和IDropSource接口,对拖拽源和目标进行操作。但是拖拽的目的是进行数据的交换,在上一篇文章中对于发送和接受数据都是一笔带过,所以这一篇主要介绍Drag和Drop操作中的数据。

 

 

一 .NET中Drag和Drop时的数据传输

 

 

Drag和Drop的过程其实就是一个数据交换的过程,比如我们把ListView中的一条数据拖放到另一个ListView中;或者是把一个MP3拖放到播放器中;或者是拖动一段文字到输入框;甚至windows的资源管理器中,从C盘拖动一个文件到D盘,其实都是这样一个Drag and Drop的过程。

我们先来看看我们上一篇文章中ListView直接拖动的例子

//ListView1 拖动
private void listView1_ItemDrag(object sender, ItemDragEventArgs e)
        {
            ListViewItem[] itemTo = new ListViewItem[((ListView)sender).SelectedItems.Count];
            for (int i = 0; i < itemTo.Length; i++)
            {
                itemTo[i] = ((ListView)sender).SelectedItems[i];
            }
            ((ListView)(sender)).DoDragDrop(itemTo, DragDropEffects.Copy);
        }


//ListView2 接收
private void listView2_DragDrop(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(typeof(ListViewItem[])))
            {
                ListViewItem[] files = (ListViewItem[])e.Data.GetData(typeof(ListViewItem[]));
                foreach (ListViewItem s in files)
                {
                    ListViewItem item = s.Clone() as ListViewItem;
                    listView2.Items.Add(item);
                }
            }
        }

我们看到ListView1动数据时,DoDragDrop方法的第一个参数就是一个Object型的,用来传送任何类型的数据;而listView2_DragDrop方法则用来接收数据,我们注意到typeof(ListViewItem[]),接收时指定了要接收的数据类型。可以看到我们例子中,DataSource和DataTarget之间传送和接受的数据时都是Object型。如果我们发送时的原始类型和接收时指定的类型不相符,就无法得到数据。

上面是比较好理解的,和我们定义方法中,使用Object类型传递各种类型的数据,方法中在进行数据类型的转换道理是一样的。不过这只是在我们自己的程序中,我们清楚数据源和数据目标之间要传递的数据类型,所以不存在问题。而对于两个程序之间进行数据交换就没有这么简单了,首先系统并不认识Object这样一个类型,其实就是即便有了一种通用的类型,接收方并不知道传送的数据原始类型,如果对仍和数据都进行转换,并不是一个好的办法。

继续阅读

最近可能有一个和DragDrop有关的项目,目前还没确定用C++还是C#做,我也在进行一些学习调查。所以就边学边写,来谈一谈在C#中的拖拽操作。这篇文章主要是介绍.NET中拖拽的实现。

 

 

 一 C#中Drap and Drop的用法

 

    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            listView1.View = View.List;
            listView2.View = View.List;
        }


        private void listView1_DragEnter(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop))
                e.Effect = DragDropEffects.Copy;
        }

        private void listView1_DragLeave(object sender, EventArgs e)
        {

        }

        private void listView1_DragOver(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop))
                e.Effect = DragDropEffects.Copy;
        }

        private void listView1_DragDrop(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop))
            {
                String[] files = (String[])e.Data.GetData(DataFormats.FileDrop);
                foreach (String s in files)
                {
                    ListViewItem item = new ListViewItem(s);
                    listView1.Items.Add(item);
                }
            }
        }

        private void listView1_ItemDrag(object sender, ItemDragEventArgs e)
        {
            ListViewItem[] itemTo = new ListViewItem[((ListView)sender).SelectedItems.Count];
            for (int i = 0; i < itemTo.Length; i++)
            {
                itemTo[i] = ((ListView)sender).SelectedItems[i];
            }


            //System.Runtime.InteropServices.ComTypes.IDataObject obj;
            //System.Runtime.InteropServices.ComTypes.FORMATETC formatEtc;
            //System.Runtime.InteropServices.ComTypes.STGMEDIUM stgMedium;
            //formatEtc = new System.Runtime.InteropServices.ComTypes.FORMATETC()
            //{
            //    cfFormat = 15,
            //    dwAspect =  System.Runtime.InteropServices.ComTypes.DVASPECT.DVASPECT_CONTENT,
            //    lindex = 1,
            //    ptd = IntPtr.Zero,
            //    tymed = System.Runtime.InteropServices.ComTypes.TYMED.TYMED_HGLOBAL
            //};

            //stgMedium = new System.Runtime.InteropServices.ComTypes.STGMEDIUM()
            //{
            //    pUnkForRelease = null,
            //    tymed = System.Runtime.InteropServices.ComTypes.TYMED.TYMED_HGLOBAL,
            //    unionmember = IntPtr.Zero
            //};
            //obj.SetData(formatEtc, stgMedium, true);
            ((ListView)(sender)).DoDragDrop(itemTo, DragDropEffects.Copy);
        }


        private void listView2_DragEnter(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(typeof(ListViewItem[])))
                e.Effect = DragDropEffects.Copy;
        }

        private void listView2_DragDrop(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(typeof(ListViewItem[])))
            {
                ListViewItem[] files = (ListViewItem[])e.Data.GetData(typeof(ListViewItem[]));
                foreach (ListViewItem s in files)
                {
                    ListViewItem item = s.Clone() as ListViewItem;
                    listView2.Items.Add(item);
                }
            }
        }
    }

上面是一段使用两个ListView显示信息的代码,其中ListView1接受我们拖动一个文件到他的窗体上,并显示文件路径;而ListView2是接受我们从ListView1中拖动文件路径,显示在自己的view中。程序的运行结果入下。

继续阅读

扯淡

 

WPF是下一代WINDOWS桌面程序开发的主流,而Silverlight也是微软在RIA上的重要一步,而且随着WIN PHONE7一起,也成了以后微软手机开发的主要工具。现在Silverlight也是火的不得了。加上FLEX,HTML5,现在的程序员也是越来越难当,每天都要被新技术,新概念,新名次不断的轰炸。虽然很多东西对于我们这菜鸟级的程序员根本用不上,也没有太多公司会跟风而上。毕竟技术只是为了更好的创造利润。但作为对新鲜事务有着强烈好奇心的我们来说,没空多了解小也是挺好的。

 

WPF/Silverlight已经出了了3年多了,应该说比较成熟了,随着WINDOWS7和.NET4.0的发布,我想以后的桌面应用程序以及WEB程序会想着更绚,更酷,更方便的方向发展。WINDOWS 7的绚丽效果我想用过以后就在也不想换回XP了吧。哈哈。软件已将从如何做软件到如何做好软件,而现在是要到如何做用户喜欢的软件了。我想一个漂亮的等待界面和一个简陋的等待提示相比,用户也不会在乎那1.,2秒的查询速度,而对于WEB软件,能像桌面程序一样操作一直是美好的梦想,随着RIA框架的涌现,现在越来越关注的也是交互和操作了。

 

稍微唠叨了下,WPF/Silverlight 09年就准备开始学习,当时也没什么资料,而且加上工作忙,一出差就给耽误了,不过大致看过一遍SDK的文档,还算有点点基础。现在在一看,3。0,4.0都出来了。而且书籍和相关资料也渐渐多了起来。自己也懒得边学边写,因为网上很多,没有重复的制造轮子啊。 把学习中收集到的一些很好的文章收录在这里,不定期更新:

 

相关资料

 

 

WPF和以往的WINFORM最大的不同就在于它的显示上,WINFORM是使用GDI/GDI+,而WPF则是使用了DirectX,而在WINDOWS7下,系统的图形显示相对于XP也有了很大的改性(其实是VISTA相对XP),在WIN7下有一个DWM(Desktop Windows Manager)。关于DWM的解释可以参见MSDN : http://msdn.microsoft.com/en-us/library/aa969540(VS.85).aspx

下面2个是关于WIN7图形架构和在DWM下GDI和DirectX的工作方式,关于GDI+和DirectX不熟悉的话可以大概了解下,我也只是在上一个项目中有所使用,才有了一定了解。对于学习WPF来说大概了解就行了。

深度解读 – Windows 7核心图形架构细致分析

Redirecting GDI, DirectX, and WPF applications

下面一遍文章介绍了WPF中的图形的呈现过程和内部操作,个人感觉很好,和上面2个文章有一些相关联的东西

一站式WPF–Window(一)

园子里别人写的学习笔记,很全了,快速入门。恩,没有必要在造轮子了。

WPF and Silverlight 学习笔记:索引页

半年没有写东西了。也就出差了半年。半年没有用C#,写了半年VC,呵呵。有时候其实有挺多东西写的,不过一忙起来人就懒了。简单的东西不想写,复杂的又写不了,哈哈。最近不是太忙,大概看了下COM组件模型,然后对DLL工作,库文件有了一些兴趣。因为工作和自己写的程序可以延伸到这些知识上,所以对DLL进行了一定的了解,而且对于直接开始编写C#应用程序的人来说,也很少会去了解这些,所以决定写下来。

 

 

 一 库文件

 

 

库文件是我们在接触编程时经常听到的词。那么什么是库文件。其实库文件是一种重用的思想。比如我们自己编写C#的程序,可能会把公用的一些方法放在一个名为Common的项目中,然后编译成DLL,其他项目引用这个程序集,就可以调用这个里面的方法,而不用自己去实现。在说的大一点,.NET中提供给我们使用的类,也是存放在.NET库中的。而整个WINDOWS系统,都是建立在库文件基础上的。

实在最初的时候是没有库文件的概念,所有功能都是自己实现的。为了提高效率,减少重复工作,就必须对代码重用。重用方法有很对,比如对于一些通用的方法的实现代码让编译器自己生成,但这个问题是,一旦方法变更会添加,编译器也必须修改了。另一个方法是把常用的方法编译成.obj模块文件。这样在编译的时候,去链接这些模块文件,就能实现代码重用。但是所有方法放到一个obj文件中,文件会很庞大,占用内存;如果为每个方法提供一个obj文件,那又会相当的麻烦。

于是就出现了静态库(static library),静态库是一个或多个.obj文件的集合。使用到这些.obj文件对应的函数时,只需要在连接时提供该静态库,而不需要列举用到的.obj文件。而连接器进行连接的时候,只会将程序中用到的函数对应的.obj文件连接到程序中。静态库的形式就是我们WINDOWS上常见的.lib文件。但静态库的确定是,每个程序使用时都会吧需要的obj文件拷贝到内存中,100个程序就有100个拷贝,这样对内存的浪费很大,而且如果静态库文件更新的话,程序也需要重新编译,进行连接。于是共享库(shared library,也叫做动态连接库)就出现了。首先他是被加载到公用的内存空间中,是所有程序共享的,所以对节省了内存;另外他在编译时没有象静态库那样,把代码直接连接到了程序中,只是插入了动态库的一些信息,供调用时使用。这样,我们就有可能直接修改动态库,而不需要重新编译程序。

动态库当然也有他的问题,比如DLL HELL。DLL Hell 是指当多个应用程序共享一个DLL或COM组件时所引发的一系列问题。比如一个应用程序安装一个新版本DLL,而该DLL与机器上的现有版本不向后兼容。这样就可能导致以前的引用程序引发异常。而.NET的强命名程序集就解决了这个问题,它通过程序集(DLL)名称、语言、版本、KEY来区分DLL,而不仅仅是只通过名字。也就能保证对个版本的DLL同时工作。

 

继续阅读

最近在学习多线程方面的东西,打算在自己的小程序中尝试使用。所以也看了不少文章。关于BackgroundWork,其实去年就用Reflector大概看过,但是没有太懂,呵呵,今天看相关文章正好又碰到,所以就仔细看看。

 

一 异步编程

 

在开始介绍BackgroundWork之前还是废话一下,说说异步编程。异步操作通常用于执行完成时间可能较长的任务,如打开大文件、连接远程计算机或查询数据库。异步操作在主应用程序线程以外的线程中执行。应用程序调用方法异步执行某个操作时,应用程序可在异步方法执行其任务时继续执行。

说到异步编程,就不能不说到多线程,他们之间的关系有时总是让人很迷惑。在学习的初期,你会觉得多线程和异步没有什么区别。我自己开一个新线程去执行一个任务和用异步执行一个任务感觉没什么区别。甚至分不清到底用什么。其实多线程是实现异步编程的一种方式,但不是实现异步编程的唯一方式。

如果学习过计算机体系结构就应该知道,CPU和外设之间通信有三种方式。比如请求打印机,当打印机没有准备好,这个时候就等待,直到打印机准备好,在执行操作,这个叫程序查询方式。但因为外设速度慢,浪费CPU时间;后来出现了硬件中断。在等待打印机的过程中,CPU分配给其他进程,当打印机准备好了,则发一个硬件中断,通知CPU打印。这样有效的提高了CPU的效率,但是频繁的中断和进程的切换,也降低了效率;于是就出现了DAM(Direct Memory Access),DMA最明显的一个特点是它不是用软件而是采用一个专门的控制器来控制内存与外设之间的数据交流,无须CPU介入,大大提高CPU的工作效率。在进行DMA数据传送之前,DMA控制器会向CPU申请总线控制权,CPU如果允许,则将控制权交出,因此,在数据交换时,总线控制权由DMA控制器掌握,在传输结束后,DMA控制器将总线控制权交还给CPU。

所以我们有多种实现异步的方式:利用多线程;IOCP 等,而IOCP就是使用了硬件的功能,虽然我们多起了一个线程,但是线程那I/O请求交给硬件驱动后就空闲了,回到线程池被其他调用。比如读取文件使用异步处理,需要把流修改为异步,并且调用Read的异步方法,这时候,线程把请求交给I/O就被回收了,流返回后在使用一个线程进行处理;如果只调用 Read异步方法,而流不支持异步,实际上是在内部用一个线程模拟了所谓的异步;最后就是流使支持异步,但使用同步的read方法,这个时候线程采用轮询的方法,等待操作完成。

继续阅读

在上一篇文章中介绍了.NET下使用Oracle数据提供程序访问Oracle的方法以及较老的数据库访问方式 ,ODBC,DAO,RDO等。总的说ODBC的出现使得程序员不必在关注与特定的数据库接口进行编程。而是利用数 据库驱动来隐藏了不同数据库的差异,提供了统一的数据库编程接口。但是ODBC是C语言风格的接口,对 于VB,ASP等程序无法直接使用,于是出现了DAO.RDO等面向对象的接口供程序员使用。

 

一 OLE DB

 

ODBC,DAO的表现在关系型数据库上已经很好了,但是随着数据的发展,非关系行的数据Excel,XML, 邮件等的出现,使得ODBC无法对这些数据进行访问。而随着COM的发展,组件模型的思想也进入了数据库 中,于是出现了OLE DB。全名是Object Linking and Embedding DataBase。对象连接与嵌入,简称OLE技 术。OLE 不仅是桌面应用程序集成,而且还定义和实现了一种允许应用程序作为软件“对象 ”(数据集合和操作数据的函数)彼此进行“连接”的机制,这种连接机制和协议称为部 件对象模型。

 

OLEDB      OLEDB

OLE DB 建立于 ODBC 之上,并将此技术扩展为提供更高级数据访问接口的组件结构。此结构对企业中 及 Internet 上的 SQL、非 SQL 和非结构化数据源提供一致的访问。OLE DB 由三个组件构成:数据使用者(例如,一个应用程序);包 含并公开数据的数据提供程序以及处理并传输数据的服务组件(例如,查询处理器、游标引擎)。OLE DB 是一个针对 SQL 数据源和非 SQL 数据源(例如,邮件和目录)进行操作的基于COM的 API。

OLEDB的特点是他的多层组件结构,而最重要的就是她的数据提供程序,正式他隐藏了数据源的不同特 征,使得应用程序可以访问关系和非关系型数据库。而各层之间通过Com通信。

继续阅读

最近做一个ASP.NET性能优化的小项目,目前还是在搭建测试环境,服务器使用WINDOWS2008,有2台AP server ,通过双网卡进行NLB组成集群,一台DB服务器,使用的是ORACLE 11g,然后客户还指出要使用ODP.NET。因为大多是使用的是SQL SERVER数据库,而以前接触ORACLE9i,10G时都是在Linux环境下,所以不太了解这个ODP.NET是个什么。 然后就查了查,发现好多东西都了解的不是很清楚,所以写篇文章吧了解到的写下来,可能有点杂碎吧。关于集群方面的等搭建完了在介绍介绍。

一 ODP.NET

 

ODP.NET全名是Oracle Data Provider,是Oracle发布的供.NET程序访问Oracle数据库的ADO.NET组件,比微软自带的Oracle组件性能好,更可以访问UDT(User Defined Type)类型,Procedure,REF等等高级Oracle特性。目前最新的版本是11g。在Oracle的官方网站可以下载。不过我都是跟随ODAC包一起下载下来的,关于ODAC后面介绍吧。

使用过.NET连接Oracle的都知道。一般都是使用OLEDB或者是.NET中提供的OracleClient来进行连接。我记得在.NET1.0中好像是没有包含OracleClient,需要单独下载,然后1.1中就有了,记得当时MSDN上有写。而微软也宣称,从.NET4.0开始放弃对OracleClient的支持,但不会删除,标记为不建议使用。 所以可以使用ORACLE提供的ADO.NET访问组件ODP.NET,组件的名字为OracleDataAccess.dll,oracle的使用和OracleClient完全一样,在程序中添加DLL引用就可以使用:

            using (OracleConnection conn = new OracleConnection(WebConfigurationManager.ConnectionStrings["oracleODP"].ConnectionString))
            {
                using (OracleCommand cmd = conn.CreateCommand())
                {
                    cmd.CommandText = "select username, tel from demobs.test where username = '" + TextBox1.Text + "'";
                    conn.Open();
                    OracleDataReader reader = cmd.ExecuteReader();
                    if (reader.Read())
                    {
                        TextBox1.Text = reader.GetString(1);
                    }
                }
            }

上面一段代码,无论你使用OracleDataAccess.dll还是OracleClient.dll她都能正常工作,唯一不同可能是连接字符串的一点点区别了。

继续阅读

很久都没写BLGO了,关于多态的第3篇文章一晃就1年了才写。有时比较迷茫,感觉太多东西都要学,什么都想学,却找不清方向了。呵呵,看着好多牛人的BLOG觉得自己水平实在是太差了。呵呵。有时甚至觉得自己写的东西太低级了。呵呵,或许是自己抱怨太多了,还是静下心来慢慢学习吧。以后一定多写一些东西,自己经常看看还是挺有帮助的。

如果大家对多态的机制还不了解,可以先查看上面这2篇文章。本篇本打算使用一些例子说话,但是实际大家明白了方法表的布局结构。其实是根本不需要任何实例去讲解了。所以这一篇主要算是查缺补漏吧。

 

 

一 多态的例子

 

class Program
    {
        static void Main(string[] args)
        {
            Cpu c1 = new Cpu();
            c1.fun();
            Cpu c2 = new IntelCpu();
            c2.fun();
            Cpu c3_1 = new NewCpu();
            c3_1.fun();
            NewCpu c3_2 = new NewCpu();
            c3_2.fun();
            Console.ReadKey();
        }
    }
    class Cpu
    {
        public virtual void fun()
        {
            Console.WriteLine("This is Cpu");
        }
    }
    class IntelCpu : Cpu
    {
        public override void fun()
        {
            Console.WriteLine("This is IntelCpu");
        }
    }
    class NewCpu : Cpu
    {
        public new void fun()
        {
            Console.WriteLine("This is NewCpu");
        }
    }

这个例子,主要是为了解释上一篇中遗留的new关键字时候的问题。我们主要从两个方面来讲解这个列子:

继续阅读

 一 流的概念

 

在.NET中Stream 是所有流的抽象基类。流是字节序列的抽象概念,或者说是计算机在处理文件或数据时产生的二进制序列。例如文件、输入/输出设备、内部进程通信管道或者 TCP/IP 套接字。Stream 类及其派生类提供这些不同类型的输入和输出的一般视图,使程序员不必了解操作系统和基础设备的具体细节。简单的说流提供了不同介质之间的数据交互功能。

在.NET中常用的流有BufferedStream 、FileStream、MemoryStream和NetworkStream,他们都是位于System.IO和System.Net命名空间下。流涉及三个基本操作: 读取,写入和查找。根据基础数据源或储存库,流可能只支持这些功能中的一部分。有些流实现执行基础数据的本地缓冲以提高性能。对于这样的流,Flush 方法可用于清除所有内部缓冲区并确保将所有数据写入基础数据源或储存库。

 

 

继续阅读