无常

记录无常工作上的点点滴滴
posts - 112, comments - 377, trackbacks - 10, articles - 1

2009年6月14日

一、项目设计目的
       熟悉ELF文件格式,了解GeekOS系统如何将ELF格式的可执行程序装入到内存,建立内核进程并运行的实现技术。
二、项目设计要求
   1、修改/geekos/elf.c文件:在函数Parse_ELF_Executable( )中添加代码,分析ELF格式的可执行文件(包括分析得出ELF文件头、程序头,获取可执行文件长度,代码段、数据段等信息),并填充Exe_Format数据结构中的域值。
  2、在Linux环境下编译系统得到GeekOS镜像文件。
  3、编写一个相应的bochs配置文件。
  4、在bochs中运行GeekOS系统显示结果。


在此项目中,GeekOS需要从磁盘加载一个可执行文件到内存中,并且在内核线程中执行此程序。我们需要做的就是完成/geekos/elf.c中Parse_ELF_Executable函数,把EXE文件的内容填充到指定的Exe_format格式的区域。

/geekos/elf.c中Parse_ELF_Executable函数的定义如下:

int Parse_ELF_Executable(char *exeFileData, ulong_t exeFileLength, struct Exe_Format *exeFormat)


exeFileData为ELF(Executable and Linking Format)格式的可执行文件的内容,exeFileLength为文件的长度,函数就是需要把exeFileData中的数据填充到exeFormat中。


先来分析一下ELF文件内容布局:
image 
文件最开始是ELF文件头结构,跟着是ProgramesHeader表,接下来是各个区段,最后是可选的区段头表。详细的可以参看ELF Specification
在elf.h中可以找到 ELF Header和programHeader的定义:

typedef struct {
    unsigned  char    ident[16];
    unsigned  short   type;
    unsigned  short   machine;
    unsigned  int     version;
    unsigned  int     entry;
    unsigned  int     phoff;
    unsigned  int     sphoff;
    unsigned  int     flags;
    unsigned  short   ehsize;
    unsigned  short   phentsize;
    unsigned  short   phnum;
    unsigned  short   shentsize;
    unsigned  short   shnum;
    unsigned  short   shstrndx;
} ELFHeader;
ELFHEader各字段的含义参看这里ELF Header
typedef struct {
   unsigned  int   type;
   unsigned  int   offset;
   unsigned  int   vaddr;
   unsigned  int   paddr;
   unsigned  int   fileSize;
   unsigned  int   memSize;
   unsigned  int   flags;
   unsigned  int   alignment;
} programHeader;


Exe_Format结构的定义如下:

struct Exe_Format {
    struct Exe_Segment segmentList[EXE_MAX_SEGMENTS]; /* Definition of segments */
    int numSegments;		/* Number of segments contained in the executable */
    ulong_t entryAddr;	 	/* Code entry point address */
};
struct Exe_Segment {
    ulong_t offsetInFile;	 /* Offset of segment in executable file */
    ulong_t lengthInFile;	 /* Length of segment data in executable file */
    ulong_t startAddress;	 /* Start address of segment in user memory */
    ulong_t sizeInMemory;	 /* Size of segment in memory */
    int protFlags;		 /* VM protection flags; combination of VM_READ,VM_WRITE,VM_EXEC */
};

明白了这几个结构后,程序就很容易了:

int Parse_ELF_Executable(char *exeFileData, ulong_t exeFileLength,
    struct Exe_Format *exeFormat)
{
     int i;
    elfHeader *hdr =(elfHeader*) exeFileData;
    programHeader *phdr=(programHeader *)(exeFileData + hdr->phoff);;
    struct Exe_Segment * segment= exeFormat->segmentList ;
    for( i=0; i< hdr->phnum; i++)
    {
        segment->offsetInFile = phdr->offset;
        segment->lengthInFile = phdr->fileSize;
        segment->startAddress = phdr->vaddr;
        segment->sizeInMemory = phdr->memSize;
        phdr++;
        segment++;
    }
    exeFormat->numSegments = hdr->phnum;
    exeFormat->entryAddr = hdr->entry;
    return 0;
}

编译成功后执行结果如下:
image

此项目中执行的是 src/user/a.c编译后的a.exe程序,如果想修改显示信息的可以打开此文件修改。

此项目执行的程序放在disk.img磁盘映像中,和project0稍有不同,所以要修改下.bochsrc文件,参考配置如下:

config_interface: textconfig
romimage: file=/usr/share/bochs/BIOS-bochs-latest
megs: 8
vgaromimage: file=/usr/share/vgabios/vgabios.bin
floppya: 1_44=./fd.img, status=inserted
ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14
ata1: enabled=0, ioaddr1=0x170, ioaddr2=0x370, irq=15
#ata2: enabled=0, ioaddr1=0x1e8, ioaddr2=0x3e0, irq=11
#ata3: enabled=0, ioaddr1=0x168, ioaddr2=0x360, irq=9
ata0-master: type=disk, path="diskc.img", mode=flat, cylinders=40, heads=8, spt=64
#ata0-slave: type=cdrom, path="/dev/cdrom", status=inserted
boot: a
ips: 1000000
log:./bochs.out
vga_update_interval: 300000
keyboard_serial_delay: 250
keyboard_paste_delay: 100000
private_colormap: enabled=0

 

出处:http://wuchang.cnblos.com

20090614

posted @ 2009-06-14 14:14 无常 阅读(41) | 评论 (0)编辑

2009年6月2日

一、项目设计目的

熟悉GeekOS的项目编译、调试和运行环境,掌握GeekOS运行工作过程。

二、项目设计要求

1、搭建GeekOS的编译和调试平台,掌握GeekOS的内核进程工作原理。

2、熟悉键盘操作函数,编程实现一个内核进程。该进程的功能是:接收键盘输入的字符并显示到屏幕上,当输入ctrl+d时,结束进程的运行。

三、项目0的实现主要由以下步骤完成(在项目0的/src/geekos/main.c中完成):

1.编写一个C语言函数,函数功能是:接收键盘输入的按键,并将键值在显示器显示出来,当输入ctrl+d就退出;

2.在Main函数体内调用Start_Kernel_Thread函数,将步骤1编写的函数地址传递给参数startFunc,利用Setup_Kernel_Thread函数建立一个待运行的线程。

3.在Linux环境下编译系统得到GeekOS镜像文件。

4.编写一个相应的bochs配置文件。

5.在bochs中运行GeekOS系统显示结果。


上一篇博文中已经介绍了如何搭建开发环境,现在来开始第一个实验。

首先需要了解一下将要用到的二个函数:

Read_Key()、Start_Kernel_Thread();

Read_Key 是键盘相关的函数,在keyboard.h中定义,project0的main.c文件中已经包含有了此头文件。

一、函数介绍

1.Read_Key()

定义:bool Read_Key(Keycode *keycode);

作用:轮查键盘事,如果捕获到键盘事件,则返回true,并且将按键码保存到参数 keycode地址中。

函数返回数据类型都是16位的Keycode类型,定义如下:

typedef ushort_t Keycode

在keyboard.h中还定义了一系列的键盘码常量。

Keycode的高8位为标志位。
如果第8位为0,则keycode的低8位为按键的ASCII码,
如果第8位为1,表示按下的是F1-12系列或其ctrl\shift\alt等特殊键。
其它常用的几个标志位:
第12位:SHIFT_FLAG,为1表示shift键处于按下状态
第13位:ALT_FLAG,为1表示alt键处于按下状态
第14位:CTRL_FLAG,为1表示Ctrl键处于按下状态
第15位:RELEASE_FLAG,为1是释放事件,为0是按下事件,就是 windows编程中常用的keyup和keydown。

2.Start_Kernel_Thread();
定义:
void Init_Scheduler(void);
struct Kernel_Thread* Start_Kernel_Thread(
    Thread_Start_Func startFunc,  //线程函数地址
    ulong_t arg, //线程函数参数
    int priority, //优先级
    bool detached  //线程属性,false为内核线程,true为用户线程
);

作用:创建并启动一个线程
此函数返回的是Kernel_Thread结构体类型数据,在这里我们不对此结构体作深入介绍。

二、编码

在main.c中新加个函数,命名为projecto,函数的代码如下:

void project0()
{
    Print("To Exit hit Ctrl + d.\n");

    Keycode keycode;
    while(1)
    {
        if( Read_Key(&keycode) )    //读取键盘按键状态
        {
            if(!( (keycode & KEY_SPECIAL_FLAG) || (keycode & KEY_RELEASE_FLAG)) ) //只处理非特殊按键的按下事件
            {                
                 int asciiCode = keycode &  0xff;    //低8位为Ascii码

                if( (keycode & KEY_CTRL_FLAG)==KEY_CTRL_FLAG  &&  asciiCode=='d')    //按下Ctrl键
                {
                    Print("\n---------BYE!--------\n");
                    Exit(1);                      
                }else
                {
                    Print("%c",(asciiCode=='\r') ? '\n' : asciiCode);
                }
            } 
        }
    }
}

再修改Main函数,将TODO(“…..这一行替换为以下代码:

    struct Kernel_Thread *thread;
    thread = Start_Kernel_Thread(&project0,0,PRIORITY_NORMAL,false);

保存代码,按上一篇文章中的方法编译,并在bochs中引导系统。
运行效果如下图所示:

image


首发:http://wuchang.cnblogs.com/

2009-06-02

posted @ 2009-06-02 18:23 无常 阅读(99) | 评论 (0)编辑

2009年5月5日

 

一、安装Ubuntu9(略)

二、下载Geekos

1.Ubuntu内置了Firefox3浏览器,打开网址 geekos.sourceforge.net,下载GeekOS 0.3到本地。

解压到 /home/[username]/geekos-0.3.0目录。

三、安装c/c++编译环境

1.修改使用国内镜像更新源,在这里(http://hi.baidu.com/xbourn/blog/item/b38a4ab7c9df73fc31add1eb.html)选择个国内比较快的源,网易或电子科技大学的速度都挺快。修改的方法可以在Synaptic  Package Manager图形界面中设置,或者在命令行终端中输入sudo gedit /etc/apt/sources.list,使用文本编辑器编辑源列表。

在Synaptic  Package Manager中reload或终端中输入sudo apt-get update 重新获取软件包列表。

2.输入 sudo apt-get intall build-essential 下载安装 build-essential包。

3.Ubuntu默认安装的gcc4.3.3,geekos 0.3会有一大堆错误。这里建议使用 gcc 3.3来编译。

执行 sudo apt-get install gcc-3.4

4.修改gcc连接

安装好gcc3.4包之后,输入

ls /usr/bin/gcc* –l

可以看到如下所示的信息

image

说明系统中安装有3.4和4.3版本的gcc。

删除原有gcc连接

sudo rm gcc

创建新的gcc连接

sudo ln –s gcc-3.4 gcc

再输入ls /usr/bin/gcc* –l,如下图所示则说明创建成功

image

四、安装NASM

执行 sudo apt-get install nasm

五、安装Bochs

执行 sudo apt-get install bochs

执行 sudo apt-get install bochs-x

六、编译GeekOS

1.进入geekos-0.3.0/src/project0/build目录

执行 make depend

执行 make

成功之后在build 目录下生成fd.img文件。

七、配置启动Bochs

1.创建boches配置文件

输入 gedit bochsrc

在编辑器中输入以下配置内容

config_interface: textconfig
romimage: file=/usr/share/bochs/BIOS-bochs-latest
megs: 8
vgaromimage: file=/usr/share/vgabios/vgabios.bin
floppya: 1_44=./fd.img, status=inserted
boot: a
ips: 1000000
log:./bochs.out
vga_update_interval: 300000
keyboard_serial_delay: 250
keyboard_paste_delay: 100000
private_colormap: enabled=0

保存,退出 gedit

2.启动bochs

在build目录中执行

bochs –f bochsrc

启动成功后界面如下:

image 

全文完.

始发于:http://wuchang.cnblogs.com

posted @ 2009-05-05 23:33 无常 阅读(156) | 评论 (0)编辑

2009年4月6日

之前在一个使用SqlServer数据库的项目中使用过SubSonic,感觉挺好,没遇到什么问题。

于是在上一个网站毫不犹豫的也选择了Subsonic2.1,可这次很失望。SubSonic2.1 to Oracle11并不像对SqlServer的支持那么好,很多时间,忙于给Subsonic补漏。

这次,想改用ADO.NET EF + EFOracleProvider。

关于EFOracleProvider的使用介绍可以参考一下这里:

1.ADO.NET Entity Framework支持多Provider

2.Using EF Oracle Sample Provider with EDM Designer

可是刚开始就遇到问题,在使用Edmgen.exe生成模型时,提示char和timestamp(x)类型不支持!

image

无奈,要动刀了。

还好,EfOracleProvider的代码不多,不用多久就找到了阵眼。

EfOracleProvider/Resources/EFOracleProviderManifest.xml,在这个文件中声明了Oracle字段和.net数据类型的映射关系。

打开此文件,添加一段:

    <Type Name="char" PrimitiveTypeKind="String">
     <FacetDescriptions>
        <MaxLength Minimum="1" Maximum="4000" DefaultValue="4000" Constant="false" />
        <Unicode DefaultValue="false" Constant="true" />
        <FixedLength DefaultValue="true" Constant="true" />
     </FacetDescriptions>
    </Type>

重新编译,能识别char字段了。

如果数据库中有timsstamp(x)类型的字段,得继续..

在xml文件中再增加类似这样的:

    <Type Name="timestamp(6)" PrimitiveTypeKind="DateTimeOffset">
     <FacetDescriptions>
        <Precision Minimum="0" Maximum="6" DefaultValue="6" Constant="false" />
     </FacetDescriptions>
    </Type>
    <Type Name="timestamp(3)" PrimitiveTypeKind="DateTimeOffset">
     <FacetDescriptions>
        <Precision Minimum="0" Maximum="3" DefaultValue="3" Constant="false" />
     </FacetDescriptions>
    </Type>

如果还有其它长度的timestamp类型,按此法一一添加。

其后打开EFOracleProviderManifest.cs,找到public override TypeUsage GetEdmType(TypeUsage storeType)函数,

在switch (storeTypeName)这行之前添加

if (storeTypeName.StartsWith("timestamp"))
{
    return TypeUsage.CreateDateTimeTypeUsage(PrimitiveType.GetEdmPrimitiveType(
                                         PrimitiveTypeKind.DateTime), null);
}

把所有 timestamp类型都映射到DateTime类。

如果还有其它未知数据类型,也参照此方法添加。

from:wuchang.cnblogs.com

posted @ 2009-04-06 16:08 无常 阅读(1183) | 评论 (5)编辑

2009年4月2日

好久没更新自己的blog了,说忙都只是借口罢了~

今天进来看到访问计数器已经过了十万了,还有不少欧美的访客,呵呵。

截个计数器的图纪念一下。

image

新版的Live Writer使用又方便了不少,还可以插入个地图,试一下

地图图片

MS的街道地图还是没有google的细呀,桂林市区的街道图都没有,卫星图倒是可以,学校前停的公车都能看清楚。

posted @ 2009-04-02 17:22 无常 阅读(108) | 评论 (1)编辑

看Oxite的源码时遇到个很困惑的问题,在Oxite的Controller中,很多Action返回值不是我们常见的ActionResult类型,比如说这里:

    public class PageController : Controller
    {
        //....
        public virtual OxiteModelItem<Page> Item(string pagePath)
        {
            Page page = pageService.GetPage(pagePath);
            if (page == null) return null;
            return new OxiteModelItem<Page>
            {
                Item = page
            };
        }
        //.....
    }

OxiteModeItem是何许人也?起初以为是ActionResult的派生类,是这样吗?到Oxite.ViewModels中我们可以看个究竟,

    public class OxiteModel
    {
        public INamedEntity Container { get; set; }
        public SiteViewModel Site { get; set; }
        public UserViewModel User { get; set; }
        private readonly Dictionary<Type, object> modelItems = new Dictionary<Type, object>();
        public void AddModelItem<T>(T modelItem) where T : class
        {
            modelItems[typeof(T)] = modelItem;
        }
        public T GetModelItem<T>() where T : class
        {
            if (modelItems.ContainsKey(typeof(T)))
                return modelItems[typeof(T)] as T;
            return null;
        }
        //....
    }

并非如我所想,在这个目录中还有几个它儿子,继承层次如下

image

竟然不是派生于ActionResult,只是下原汁原味的Model,纳闷了,MVC中的V到哪里去了?

如果之前没接触过IOC,看Oxite的代码时确实是有点头晕,好不容易才把OxiteControllerActionInvoker翻出来了。先来看下它的代码

namespace Oxite.Infrastructure
{
    public class OxiteControllerActionInvoker : ControllerActionInvoker
    {
        private readonly IFilterRegistry filterRegistry;
        public OxiteControllerActionInvoker(IFilterRegistry filterRegistry)
        {
            this.filterRegistry = filterRegistry;
        }
        protected override ActionResult CreateActionResult(ControllerContext controllerContext, ActionDescriptor actionDescriptor, object actionReturnValue)
        {
            if (actionReturnValue == null)
            {
                controllerContext.Controller.ViewData.Model = new OxiteModel { Container = new NotFoundPageContainer() };
                return new NotFoundResult();
            }
            if (typeof(ActionResult).IsAssignableFrom(actionReturnValue.GetType()))
                return actionReturnValue as ActionResult;
            controllerContext.Controller.ViewData.Model = actionReturnValue;
            return new ViewResult { ViewData = controllerContext.Controller.ViewData, TempData = controllerContext.Controller.TempData };
        }
        //....
    }
}

在这里可以看到个明白,actionReturnValue就是就是控制器中返回的结果,在这里首先判断是否为空,然后判断返回结果的类型是否从ActionResult派生出来的,如果是,说明是个View,直接交出去了,否则就是Model了。

当然这里还离不开另一个类OxiteControllerFactory:

namespace Oxite.Infrastructure
{
    public class OxiteControllerFactory : DefaultControllerFactory
    {
        private readonly IUnityContainer container;
        public OxiteControllerFactory(IUnityContainer container)
        {
            this.container = container;
        }
        protected override IController GetControllerInstance(Type controllerType)
        {
            IController iController = container.Resolve(controllerType) as IController;
            if (typeof(Controller).IsAssignableFrom(controllerType))
            {
                Controller controller = iController as Controller;
                if (controller != null)
                    controller.ActionInvoker = container.Resolve<IActionInvoker>();
                return iController;
            }
            return iController;
        }
    }
}

ControllerFactory看名字就知道是做什么用的了,在控制器创建了之后,直接指定自己的ActionInvoker。

推荐二篇关于ActionInvoker的文章:

http://lostintangent.com/2008/07/03/aspnet-mvc-controlleractioninvoker-part-1/

http://lostintangent.com/2008/07/07/aspnet-mvc-controlleractioninvoker-part-2/

 

from : wuchang.cnblos.com

posted @ 2009-04-02 17:03 无常 阅读(100) | 评论 (0)编辑

2008年8月13日

花了一天的时间把项目从linq2sql转到ADO.NET Entity Framework。

此项目bs部分工程量不算多,复杂的功能都做在cs部分上,bs只负责基础数据的维护和报表统计,

其实用linq2sql也可以满足了,但是linq2sql designer用得实在太不爽了,表少的时候还能应付,现在表增加到70几个了,找个表得找半天,linq2sql desinger也不提供个搜索功能:(

前天装好vs2008sp1,试了一下EF designer,增加了Overview窗口和Model browser,就为了这个也要换到EF

image

转换过程还算顺利,

1.把代码中linq2sql的DataContext换成EF的ObjectContext,这步可以用find/replace完成大部分工作

2.linq2sql创建新记录时是用DataContext.表名s.InsertOnSubmint(obj),而ef是ObjectContext.AddTo表名(object),提交变更也从DataContext.SubmitChange()改成Object.SaveChanges()

3. DataContext.表名s  =>  ObjectContext.表名,这部分可以replace完成

4.aspx文件中用到的LinqDataSource全部得换成EntitiDataSource,这里只有手工一个一个替换了,没法偷懒。LinqDataSource的查询条件需要手工换成Entity SQL,这部分工作是大头~ 还得学一下Entity SQL

5.如果linq2sql代码用到[].Contains(xx)运算的,参考一下这里的方法解决

6.如果linq2sql中访问数据库时有嵌套访问数据库的,如下面这段代码,在linq2sql中没问题。

image

如果按流程转到EF的话,就会遇到异常

image

image

这是因为EF中foreach读取数据时是采用DataReader在线读取方式,而linq2sql则是采取类似DataSet的先把所有数据从数据库中取出到内存的方式,

所以在EF中需要把外层循环改成

foreach (var depart in ctx.Department.ToList() )

 

转移工作基本就这些了

接下来要实下EntitySQL了~

posted @ 2008-08-13 21:33 无常 阅读(727) | 评论 (4)编辑

2008年8月3日

刚才看到这个POST  中介绍几种在进行耗时的操作时如何更新UI的方法,

如果使用c#的匿名方法来,我们可以让代码更简洁些。

代码如下:

image

运行效果:

posted @ 2008-08-03 21:59 无常 阅读(339) | 评论 (0)编辑

vs2008开发wince5程序,在模拟器中调试成功,连接到设备成功,但程序部署到真实设备时出错:

image

出错信息为:

image

解决办法:

从在

C:\Program Files\Microsoft.NET\SDK\CompactFramework\v3.5\WindowsCE\Diagnostics

把NETCFv35.Messages.zh-CHS.cab直接复制到设备中安装就可以了。

如果程序中用到SqlServer CE,那么同样还会遇到无法部署sqlce.ppc.wce5.armv4i.CAB之类的信息,

这时候可以直接把X:\Program Files\Microsoft SQL Server Compact Edition\v3.5\Devices目录中sql.wce5.armv4i.CAB复制到设备上再手工安装。

posted @ 2008-08-03 09:39 无常 阅读(263) | 评论 (0)编辑

2008年7月4日

Color structure:

Color结构体位于System.Window.Media命名空间中,Color使用3个byte属性分别表示R、G、B三原色的颜色分量。当R=G=B=0时为黑色,当R=G=B=255时为白色。此外,有个byte类型的A属性表示此颜色的“不透明度”,其值为0时表示为全透明,值为255时表示不透明。这些都是有winform System.Drawing命名空间中的Color相同的。

此外,Color还支持表示scRGB(也称为scRGB64,因原色使用64位表达)颜色空间。Color结构还有4个float类型的属性scA、scR、scG、scB来描述scRGB颜色空间,值范围为<=1 && >=0,它们和RGB颜色空间中的A、R、G、B属性相对应。

改变Color对象的sc[ARGB]属性时相应的[ARGB]属性也会被影响,反之亦然。

Colors类封装有一百多种常用的颜色。

 

SolidColorBrush:

最简单的单色画刷,

wuchang.cnblogs.com

窗口背景颜色即改为全红色。

Brushes类定义有141个标准单色画刷,但这些画刷处于“冻结(frozen)”状态,如果尝试修改这些画刷的值时就会抛出异常:

image

但是可以复制一份没有处于冻结状态的画刷副本,如以下代码是允许的:

image

 

LinearGradientBrush 线性渐变画刷:

渐变画刷可以将二种或以上的颜色混合渐变。渐变画刷最简单的使用:

image

运行后的效果:

image

渐变画刷中定义的点是相对于填充区域范围,如(0,0)是填充区域左上角的点,(1,1)为右下角。如将以上创建画笔对象代码改为:

image 

即为垂直方向渐变:

image

 

渐变画刷还可以使用GracientStop类来指定多个“关键颜色”点,如定义彩虹画刷:

image

效果如下:

image

 

RadialGradientBrush 放射状渐变画刷:

与线性画刷不同的是放射状画刷不需要定义起始和终止点,它默认的中心点是(0.5,0.5),即填充区域的中心。

image

效果如下:

image

当然射线中心点和X/Y方向的渐变倍数也是可以任意修改的:

brush.GradientOrigin = new Point(0, 0);
brush.RadiusX = 1.5;

image

出处:http://wuchang.cnblogs.com

posted @ 2008-07-04 00:29 无常 阅读(236) | 评论 (0)编辑

2008年7月1日

System.Windows.Application是WPF应用程序最为重要和常用的类,跟踪着整个应用程序的生命周期。和winform/delphi中的application功能类似。

创建一个应用程序

wuchang.cnblogs.com

运行这个程序后,什么都没有显示。但这个程序一直运行着,没有界面,只能通过任务管理器关闭它。

wuchang.cnblogs.com

 

定义一个Window

 image

修改Main方法为

wuchang.cnblogs.com

再次运行程序,看到一空白的窗口。与Winform窗体不同的是,wpf window默认背景颜色是SystemColors.WindowColor,系统默认是白色。

wuchang.cnblogs.com

这个窗口就是应用程序的主窗口,关闭此窗口后程序结束。

再次修改Main方法:

image

程序运行后有三个窗口了:

 wuchang.cnblogs.com

此时哪个窗口是应用程序的主窗口呢?

回答:标题为“第一个实例”的窗口是应用程序的主窗口,即最先创建的窗口。

 

在winform/delphi中,应用程序的主窗口关闭程序就结束了,而wpf程序则不是这样。

如果关闭了第一个窗口,程序并没有结束,而第二个窗口则接替着成了主窗口,一直要关闭程序中的最后一个窗口后程序才结束,这是wpf默认的方式。

这个行为由Application对象的ShutdownMode属性控制着,

ShutdownMode属性为ShutdownMode 枚举类型,有三种类型可选:

ShutdownMode .OnExplicitShutdown
只有在调用Application.Shutdown()方法才能结束应用程序。

ShutdownMode .OnLastWindowClose
在应用程序最后一个窗口关闭后程序结束。也是默认的处理方式。

ShutdownMode .OnMainWindowClose
在主窗口关闭时结束程序。

此属性一般在Application.Run()前设置,如:

image

其实,你可以在程序运行的任意时间随便修改。

另外,主窗口也可以在任意时间更改,如将Main方法修改为:

wuchang.cnblogs.com

程序运行后第二个窗口即是主窗口,如果在第三个窗口中点击了鼠标,则将其置为主窗口。

出处:http://wuchang.cnblogs.com

posted @ 2008-07-01 00:12 无常 阅读(325) | 评论 (0)编辑

2008年6月11日

之前介绍过一个.NET平台的分布式缓存indeXus.Net Shared Cache ,可是发现它还不是很完善,后来使用Memcached 了。后来收到邮件Shared Cache有新版本发布,整个架构都做了大改,性能应该有比较大的提升,但由于时间的关系,也没再去测试了。

今天在网上游荡看到一POST Velocity: A Distributed In-Memory Cache from Microsoft,MS大叔也开始关注这个领域了。

Memcached一样,Velocity也是一个内存储存的分布式缓存系统,不同的是Velocity是完全基于.NET平台的。看下Velocity的部署图

cc645013_image002

Velocity可以配置成一个缓存群集,可以根据需要通过简单的配置就可以往群集中添加服务器节点。Velocity既可以当作一个独立的缓存服务运行,客户端通过网络来存储数据;同时也支持嵌入到自己的程序中运行。有意思的是Velocity提供有一个ASP.NET session provider,通过它我们可以将ASP.net的session数据都保存到Velocity中,如果你在使用WEB群集,这是个很好的消息。

目前还是CTP1。

 

相关的资源:

http://msdn.microsoft.com/en-us/library/cc645013.aspx MSDN上的一篇文章,比较系统的介绍了Velocity的架构及应用场景。

http://blogs.msdn.com/velocity/default.aspx Velocity的官方BLOG

http://www.25hoursaday.com/weblog/2008/06/06/VelocityADistributedInMemoryCacheFromMicrosoft.aspx 一篇介绍Velocity使用的文章

http://code.msdn.microsoft.com/velocity/Release/ProjectReleases.aspx?ReleaseId=1120 下载地址。这个CTP1的下载压缩包就有12.5M  :(,包里有个asp.net和一个winform的DEMO,还有一个Quick Start .DOC文档,看完这些东东就知道怎么使用了。

posted @ 2008-06-11 01:15 无常 阅读(538) | 评论 (0)编辑

2008年5月29日

今天想在新服务器上配置VPN,在打开“路由和远程访问”控制台的时候出错了,提示“试图连接到数据库存储时出错”,控制左边的“远程访问策略”和“远程访问记录”节点都都有红色出错符号。

image

在系统事件中看到出错的信息为“与 Routing and Remote Access 服务相依的组为 NetBIOSGroup,该组中的组件均未启动。”

image

在百度“知道”找到了答案http://zhidao.baidu.com/question/2576488.html?fr=qrl

出现这个错误的原因:

设置vpn的前提是在"网络连接"属性里至少需要安装两个组件:"Microsofot网络客户端"和"Internet协议(TCP/IP)"。

检查服务器的设置,发现没安装“Microsofot网络客户端”,补上这个服务后就可以使用了。

image

posted @ 2008-05-29 14:53 无常 阅读(1220) | 评论 (2)编辑

2008年5月23日

添加新tag时没有去掉tag前后的空格,导致此tag的链接出错。

如,添加tag

image

注意test后有个空格,提交后文章的tag显示为

image

博客边栏“我的标签”中显示

image

注意这二处地方的tag也都有个空格。对应的链接后有个+号,链接目标错误。

http://www.cnblogs.com/wuchang/tag/test+/

posted @ 2008-05-23 00:03 无常 阅读(224) | 评论 (2)编辑

2008年5月21日

1.数组初始化

大小为10的数组,每个元素值都是-1
int[] a = Enumerable.Repeat(-1, 10).ToArray();

大小为10的数组,从0至9递增

 

int[] b = Enumerable.Range(0, 10).ToArray();

 

大小为10的数组,从100,110,120,...,190

 

int[] c = Enumerable.Range(0, 10).Select(i => 100 + 10 * i).ToArray();

 

2.生成随机数序列

生成10个范围在10-100的随机数

Random rand = new Random();
int [] randomSeq= randomSeq = Enumerable.Repeat(0, 10).Select(i => rand.Next(10,100)).ToArray();

 

3.集合类型转换

int集合转成string集合

List<int> intList = new List<int> { 1, 2, 3, 4, 5, 5 };
List<string> strList = new List<string>(intList.Cast<string>());

反过来,把string集合转成int集合

List<int> a = strList.Select(o => int.Parse(o)).ToList();

4.数组倒序

int [] arr = { 1, 2, 3, 4, 5};
arr.Reverse();

现在arr的元素已经是5,4,3,2,1了

http://wuchang.cnblogs.com

posted @ 2008-05-21 11:44 无常 阅读(300) | 评论 (4)编辑