GIT与SVN的优缺点比较

git_logo
git_logo
sf-logo
sf-logo

GIT与SVN的优缺点比较

1.SVN优缺点
优点:
1、 管理方便,逻辑明确,符合一般人思维习惯。
2、 易于管理,集中式服务器更能保证安全性。
3、 代码一致性非常高。
4、 适合开发人数不多的项目开发。
缺点:
1、 服务器压力太大,数据库容量暴增。
2、 如果不能连接到服务器上,基本上不可以工作,看上面第二步,如果服务器不能连接上,就不能提交,还原,对比等等。
3、 不适合开源开发(开发人数非常非常多,但是Google app engine就是用svn的)。但是一般集中式管理的有非常明确的权限管理机制(例如分支访问限制),可以实现分层管理,从而很好的解决开发人数众多的问题。


2.Git优缺点
优点:
1、适合分布式开发,强调个体。
2、公共服务器压力和数据量都不会太大。
3、速度快、灵活。
4、任意两个开发者之间可以很容易的解决冲突。
5、离线工作。
缺点:
1、学习周期相对而言比较长。
2、不符合常规思维。
3、代码保密性差,一旦开发者把整个库克隆下来就可以完全公开所有代码和版本信息。

C#中用正则表达式取页面下拉菜单(select)中的值

 

给几个在C#中,使用正则表达式取页面下拉菜单(select)中的值示例:

//取html中全部 select 的 name
Regex reg_name = new Regex(@"(?<=<select name=\"").*?(?=\"")");

//取html中全部<select>项的值
Regex reg_select = new Regex("(?is)<select name=*.*?>]*.*?</select>");

//取html中一个 select name 等于"Status"的值
Regex status = new Regex(@"(?is)<select name=\""status\"">]*.*?</select>");

 

一下是一段完整的代码和方法,取html中一个下拉菜单 select name 等于”Status”的中值,添加到DropDownList中:

        string strDoc = (你的html);

        //取html中一个下拉菜单 select name 等于"Status"的中值
        Regex status = new Regex(@"(?is)<select name=\""status\"">]*.*?</select>");
        MatchCollection mc_status = status.Matches(strDoc);
        getSelectOptions(mc_status, cmbStatus);

        /// <summary>
        /// 取select对列表复制
        /// </summary>
        /// <param name="selected"></param>
        /// <param name="cmb"></param>
        void getSelectOptions(MatchCollection selected, ComboBox cmb)
        {
            if (selected.Count < 1)
                return;
            txtValues.Text = "";
            txtValues.Text = selected[0].Value.Replace("</option>", Environment.NewLine);
            string tmpTxt = "";
            foreach (string s in txtValues.Lines)
            {
                if (s == "")
                    continue;
                string a = "";
                a = s.Replace("\"", "").Replace("<option value=\"", "");
                int x = a.LastIndexOf(">");
                tmpTxt += a.Substring(x + 1) + Environment.NewLine;
            }
            txtValues.Text = tmpTxt.Trim();
            cmb.Items.Clear();
            cmb.Items.AddRange(txtValues.Lines);
            cmb.SelectedIndex = 0;
            cmb.Size = cmb.PreferredSize;
        }

 

推荐一个正则表达式测试/验证工具 – http://bohu.net/blog/8814

 

推荐一个正则表达式测试/验证工具

这几天代码里用到很多正则表达式,需要验证,直接在程序里调试太麻烦。

比如:C#中用正则表达式取页面下拉菜单(select)中的值 – http://bohu.net/blog/8815

找到了这个验证工具:

正则表达式测试器 – http://deerchao.net/tools/regex_tester/index.htm
说明:该工具允许你测试和分析正则表达式。

解决 webBrowser DocumentCompleted 的多次调用

winform中使用webBrowser抽取页面中的一些数据。断点“webBrowser1_DocumentCompleted”发现,跑进来了好多次。

DocumentCompleted执行多次,跟踪发现ReadyState状态不一样,分别是Intercative和Complete。

而MSDN对这两种状态值的解释是:

  • Complete该控件已完成新文档及其所有内容的加载;
  • Interactive该控件已经加载足够的文档以允许有限的用户交互,比如单击已显示的超链接。

增加判断“ReadyState”之后继续,DocumentCompleted仍然执行了两次,但ReadyState状态一样都是Complete。再查原因。

MSDN对其解释是在多个的帧的情况下DocumentComplete获取触发多次。并非每个框架将触发此事件,但触发DownloadBegin事件的每个框架将触发相应的DocumentComplete事件。

 

最后webBrowser1_DocumentCompleted中的代码是:

private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
        {
            string BrowserUrl = webBrowser1.Url.ToString();

            if (String.IsNullOrEmpty(BrowserUrl)) //检查未赋值或空值
                return;
            if (BrowserUrl.Equals("about:blank")) //是否为空白页
                return;
            if (webBrowser1.ReadyState != WebBrowserReadyState.Complete)  //状态为完成
                return;
            if (e.Url.ToString() != BrowserUrl)  //检查事件url和webBrowser的url
                return;
            if (webBrowser1.DocumentText == "")
                return;

            ... ...
        }

 

还有一点,就是窗体打开就加载webBrowser1,如放在 Form_Load 会使程序界面加载很慢,建议放在 Form_Shown中(每当窗体第一次显示时发生)。

 

CentOS 桌面 + VNC 安装脚本

CentOS下的一段脚本.  直接一起安装桌面,XWindows,VNC远程控制,和支持中文.

#!/bin/bash

yum -y groupinstall "Desktop" #[安装桌面 ]
yum -y groupinstall "X Window System" #[安装XWindows]
yum -y groupinstall "Chinese Support" #[增加中文支持]

#echo 'LANG="zh_CN.UTF-8"' >> /etc/sysconfig/i18n #[设置中文]

startx #[启动XWindows]

#echo 'id:5:initdefault' >> /etc/inittab #[开机自动运行]

yum -y install tigervnc tigervnc-server #[安装VNC远程控制]

echo 'VNCSERVERS="1:root"' >> /etc/sysconfig/vncservers #[设置服务权限]
echo 'VNCSERVERARGS[1]="-geometry 1024x768"' >> /etc/sysconfig/vncservers #[设置服务参数]

vncpasswd #[这一步将会提示你设置VNC的密码]

#service vncserver restart #[重启]
service vncserver start #[启动]
#chkconfig vncserver on #[开机启动]

#后的注释项, 可以自己参考是否使用.  比如是否开机自动启动VNC.

桌面环境相关命令:

# 从命令行切换到桌面环境
startx

# 获取当前启动模式
systemctl get-default

# 修改启动模式为图形化
systemctl set-default graphical.target

# 修改启动模式为命令行
systemctl set-default multi-user.target

默认启动桌面环境后以 root 用户自动登录:

 
# 修改配置文件
vi /etc/gdm/custom.conf


# 增加如下配置
[daemon]
AutomaticLoginEnable=True
AutomaticLogin=root
远程服务设置
# Windows 远程登录需要安装 Xrdp,需要 epel 源
wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo
yum install -y xrdp

# Xrdp 会调用 VNC,安装 tigervnc-server
yum install -y tigervnc-server

# 修改 Xrdp 最大连接数
vim /etc/xrdp/xrdp.ini
max_bpp=32

# 启动 Xrdp 并设置开机启动
systemctl start xrdp
systemctl enable xrdp

# 开放 3389 端口,或者关闭防火墙
firewall-cmd --permanent --zone=public --add-port=3389/tcp
firewall-cmd --reload
# 关闭防火墙
systemctl stop firewalld
# 禁止防火墙开机启动
systemctl disable firewalld
VNC 登录设置

用 VNC 客户端连接登录还需做一些设置

VNC 客户端下载:https://www.realvnc.com/en/connect/download/viewer/

# 为当前用户设置 VNC 密码,不然服务无法启动。此密码和系统密码不一样,这是使用 vnc viewer 登陆时使用的密码
vncpasswd

# 复制服务设置的模板
cp /lib/systemd/system/vncserver@.service /etc/systemd/system/vncserver@:1.service
# 修改配置,以 root 用户为例,每个用户都需要单独设置
vim /etc/systemd/system/vncserver@\:1.service

# 将 <USER> 换成用户名,[Service] 下增加 User=root
[Unit]
Description=Remote desktop service (VNC)
After=syslog.target network.target

[Service]
Type=forking
User=root

# Clean any existing files in /tmp/.X11-unix environment
ExecStartPre=/bin/sh -c '/usr/bin/vncserver -kill %i > /dev/null 2>&1 || :'
ExecStart=/usr/sbin/runuser -l root -c "/usr/bin/vncserver %i"
PIDFile=/root/.vnc/%H%i.pid
ExecStop=/bin/sh -c '/usr/bin/vncserver -kill %i > /dev/null 2>&1 || :'

[Install]
WantedBy=multi-user.target



# 让服务文件修改生效
systemctl daemon-reload

# 启动服务
systemctl start vncserver@:1
# 设为开机启动
systemctl enable vncserver@:1

# 查看服务端口,用于客户端连接地址
netstat -lnpt|grep Xvnc

# 放行连接端口,每个用户端口不同。也可直接关闭防火墙
firewall-cmd --add-port=5901/tcp --permanent
firewall-cmd --reload

多种常见软件系统缩写

BPM(Business Process Management):业务流程管理

也称做商业流程管理。一套达成企业各种业务环节整合的全面管理模式。其中的Business并不局限于商业,它泛指各种组织中的活动:从商业企业到政府机构、非营利团体等等,因此,普遍共识是对应于更加中性的“业务”一词,例如:业务流程管理(Business Process Management, BPM)、业务流程再造(Business Process Reengineering, BPR)等。Business Process Modeling,即业务流程建模,是对业务流程进行表述的方式,它是过程分析与重组的重要基础。

 

CRM(Customer Relationship Management):客户关系管理

是一个不断加强与顾客交流,不断了解顾客需求,并不断对产品及服务进行改进和提高以满足顾客的需求的连续的过程。其内含是企业利用信息技(IT)术和互联网技术实现对客户的整合营销,是以客户为核心的企业营销的技术实现和管理实现。客户关系管理注重的是与客户的交流,企业的经营是以客户为中心,而不是传统的以产品或以市场为中心。为方便与客户的沟通,客户关系管理可以为客户提供多种交流的渠道。

 

CMS(Content Management System):内容管理系统

它具有许多基于模板的优秀设计,可以加快网站开发的速度和减少开发的成本。CMS的功能并不只限于文本处理,它也可以处理图片、Flash动画、声像流、图像甚至电子邮件档案。

 

EIP(Enterprise Information Portal): 企业信息门户

是指在Internet的环境下,把各种应用系统、数据资源和互联网资源统一集成到企业信息门户之下,根据每个用户使用特点和角色的不同,形成个性化的应用界面,并通过对事件和消息的处理、传输把用户有机地联系在一起。

 

ERP(Enterprise Resource Planning):企业资源计划系统

又译企业资源规划,简单地说,ERP是“一个大型模块化、集成性的流程导向系统,集成企业内部财务会计、制造、进销存等信息流,快速提供决策信息,提升企业的营运绩效与快速反应能力。”它是e化企业的后台心脏与骨干。任何前台的应用系统包括EC、CRM、SCM等都以它为基础。
一般ERP软件强调如下之系统集成。
ERP主要的模块有:
生产管理:工程、材料清单(Bill Of Material)、调度、产能、工作流管理、质量控制、成本管理、生产过程、生产工程、生产流程、生产配置
进销存货管理:库存、订单输入、采购、供应商调度、货物检查、付款请求处理、佣金计算
财务管理及会计项目:总帐、现金管理、应付帐款管理、应收帐款管理、票据资金管理、固定资产管理
成本管理:账单、时间和支出、活动管理
人力资源管理:人力资源、薪金名册、培训管理、员工班别和出勤管理、津贴、劳健保、绩效考核
供应链管理:和客户、供应商、员工之间的各种自服务接口

 

GIS(Geographic Information System):地理信息系统

又称为“地学信息系统”。它是一种特定的十分重要的空间信息系统。它是在计算机硬、软件系统支持下,对整个或部分地球表层(包括大气层)空间中的有关地理分布数据进行采集、储存、管理、运算、分析、显示和描述的技术系统。

 

MIS(Management Information System):管理信息系统

是一个由人、计算机及其他外围设备等组成的能进行信息的收集、传递、存贮、加工、维护和使用的系统。利用现代计算机及网络通讯技术加强企业的信息管理,通过对企业拥有的人力、物力、财力、设备、技术等资源的调查了解,建立正确的数据,加工处理并编制成各种信息资料及时提供给管理人员,以便进行正确的决策,不断提高企业的管理水平和经济效益。

 

OA(Office Automation):办公自动化

是现代利用电脑进行全自动的办公,目的是提高效率。

 

SCM(Supply Chain Management):供应链管理

把公司的制造过程、库存系统和供应商产生的数据合并在一起,从一个统一的视角展示产品建造过程的各种影响因素。对整个供应链(从供货商,制造商,分销商到消费者)的各个环节进行综合管理,例如从采购、物料管理、生产、配送、营销到消费者的整个供应链的货物流、信息流和资金流,把物流与库存成本降到最小。供应链是企业赖以生存的商业循环系统,是企业电子商务管理中最重要的课题。

 

WfMS(Workflow Management System):工作流管理系统

工作流(Workflow),是对工作流程及其各操作步骤之间业务规则的抽象、概括、描述。工作流建模,即将工作流程中的工作如何前后组织在一起的逻辑和规则在计算机中以恰当的模型进行表示并对其实施计算。工作流要解决的主要问题是:为实现某个业务目标,在多个参与者之间,利用计算机,按某种预定规则自动传递文档、信息或者任务。工作流管理系统(Workflow Management System, WfMS)的主要功能是通过计算机技术的支持去定义、执行和管理工作流,协调工作流执行过程中工作之间以及群体成员之间的信息交互。工作流需要依靠工作流管理系统来实现。

 

WMS(Warehouse Management System):仓储管理系统

对物料存放空间进行管理的软件,区别于库存管理。其功能主要有两方面,一为通过在系统中设定一定的仓库仓位结构对物料具体空间位置的定位,二为通过在系统中设定一些策略对物料入库\出库\库内等作业流程进行指导。有利于仓库资源使用。

 

Arch (及衍生版Gentoo,Manjaro) 中使用pacman更新的相关命令

在 Arch/ArchBang/Gentoo 中使用的 pacman 更新时如果报错,一般都是gpg签名不可信的问题.

需要选初始化gpg keys. 已经初始化过签名key的, 直接更新就可以了.

  1. 初始化 key:
    pacman-key --init

    验证已存档使用的 keys:

    pacman-key --populate archlinux

     

  2. 软件版本更新:
    pacman -Syy

     

    内核版本更新:

    pacman -Su
    pacman -Suy

     

    缓存中移除所有其他包吗?

    pacman -Syc

C# 多线程操作整理 (System.Threading)

Thread 类

创建并控制线程,设置其优先级并获取其状态。

命名空间:System.Threading 程序集:mscorlib(在 mscorlib.dll 中)

概述与概念

C#支持通过多线程并行地执行代码,一个线程有它独立的执行路径,能够与其它的线程同时地运行。一个C#程序开始于一个单线程,这个单线程是被CLR和操作系统(也称为“主线程”)自动创建的,并具有多线程创建额外的线程。

1.使用线程的情况

  • ①.程序需要执行和两个和多个任务
  • ②.程序要等待某事件的发生:例如用户输入、文件操作、网络操作和搜索
  • ③.后台程序

2.多线程的并发执行 如果有多个线程在执行,单CPU只有一个,到底执行的哪个?

  • ①.如果一个线程连续占用CPU资源时间过长,其它的资源得不到执行,      则系统会强制的切换执行其它线程。(强制剥夺)
  • ②.如果一个线程没事可做、CPU可执行其它线程。(主动放弃)
  • ③.这是由操作系统的调度机制决定的,不同的操作系统调度机制不一样。    一般无法精确的预料多线程的执行顺序,在程序设计的时候应特别注意

3.创建并启动线程

ThreadStart 线程启动委托名=new ThreadStart(方法名);

Thread 线程实例名=new Thread(线程启动委托名); 线程实例名.Start();

4.终止线程

  • ①.线程实例名.Abort();用此方法的后果是不可恢复的终止线程。
  • ②.线程实例名.Interrupt();中断后可恢复

5.休眠线程

  • ①.线程实例名.Sleep();     当线程Sleep时,系统就立即退出执行队列一段时间,当睡眠结束时,系统会产生一个时钟中断,从而     使线程回到执行队列中,从而恢复线程的执行。

6.挂起/恢复线程

  • ①.线程实例名.Suspend();挂起     与线程休眠不同,线程的挂起不会使线程立即停止执行,直到线程到达安全点之后它才可以将该线程挂起,如果线程尚未启动或已经停止,则它将不能挂起。
  • ②.线程实例名.Resume();恢复      将使一个线程跳出挂起状态并使该线程继续执行。     一个线程不能对另一个线程调用Sleep() ,但是一个线程可以对另一个线程调用Suspend()。     还可以使用许多其它的方式来阻塞线程。例如,可以通过调用 Thread.Join 使一个线程等待另一个线程 (子线程)停止。使用Monitor.Wait使一个线程等待访问一个同步对象。

7.串行化线程

  • ①.线程实例名.jion();     例如在主线程中插入t.jion();      主线程执行到这条语句后,主线程(当前线程)立即进入阻塞状态.直到t运行完后阻塞状态才解除。相当于把t的任务插入或串联到主线程中,把两条线索串联成一条线索

8.线程的锁定机制 线程的锁定机制可以保证每次只有一个线程可以访问共享资源。 使用关键字lock

  • ①.lock语句的语法      lock(对象引用)语句块;
  • ②.lock语句的功能      当对象被lock 锁定时,访问该线程的其它线程会进入等待的状态。
  • ③.对象锁机制保证了对象访问的完整性:只有一个线程完成操作后,其它的线程才能进行操作。
  • ④.一般情况下,当一个线程写某个变量,而同时可能有其它的线程读或写这个变量时,为了保持数据的一 致性应该使用锁定机制。
  • ⑤.线程的安全性      线程安全性就是保护的类的成员和代码的安全,从而使他们不会同时被几个线程中断,使用锁定机制。
  • ⑥.多线程公用一个对象时,就不应该使用lock关键字了,这里Monitor,Monitor提供了使线程共享资源的方 案。 Monitor类可以锁定一个对象,一个线程只有得到这把锁才可以对该对象进行操作。 如: Monitor.Enter(obj);
    Monitor.Exit(obj);
  • ⑦.临界区和锁 当谈论多线程应用程序的时候,首先应该想到的就是并发性问题。尽管这对于同时执行多个任务的程序是很有用的,但通常都是危险的。为了解决这个问题,在C#中提出了临界区和锁的概念。在程序设计中,临界区是一块在任何时候只能有一个进程进入的区域。在C#中通过语句lock来声明临界区。lock声明后面的代码,不管是以行还是一块代码,在同一时间最多只能有一个进程执行。

9.线程的优先级具有不可靠性,就是说不能用优先级来控制线程的执行顺序。

10.后台线程

  • ①.什么是后台线程?比起应用程序的主图形用户界面(GUI)线程来说,这些线程以较低的优先权在不同的过程中运行着。对于不能立即执行结束, 又不想一直等待的任务,后台线程能很好的胜任。在C#中,把线程对象的  IsBackground属性设为true,该线程即为后台线程。    后台线程跟前台线程只有一个区别,那就是后台线程不妨碍程序的终止。一旦一个进程所有的前台线程都终止后,CLR将通过调用任意一个存活中的后台进程的Abort()方法来彻底终止进程。注意:后台线程不能直接操作所在进程之外的数据引用。
  • ②.怎样与后台线程通讯?运用MethodInvoker委派实体。也可在初始化(构造函数)中加入下面一句即可实现通讯:

Control.CheckForIllegalCrossThreadCalls = False;

要使用MethodInvoker委派,需要三个条件:

  •   a.一个创建委派的后台线程
Thread thread=new Thread(new ThreadStart(Run));

thread.IsBackground=true;  //把Thread设为后台线程

thread.Start();
  •   b.一个用作后台线程与前台可视化单元的接口的类级方法
 public void Run()
        {
            int count = 0;
            try
            {
                MethodInvoker mi = new MethodInvoker(this.UpdateLabel);
                //创建一个委托,UpdateLabel是该委托所托管的代码,必须是声明为void 且不接受任何参数的任何方法。
                while (true)
                {
                    count++;
                    //this.Invoke(mi);//同步执行委托
                    this.BeginInvoke(mi);//异步执行委托
                    Thread.Sleep(500);
                }
            }
            catch (ThreadInterruptedException e)
            {
                Console.WriteLine("Interruption Exception in Thread:{0}", e);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Exception in Thread:{0}", ex);
            }
        }
  •   c.一个应用程序中可以更新的可视化单元
public void UpdateLabel()
{     
    label1.Text=count.ToString();   
}

如何判断一个应用程序是 控制台(console)程序还是 GUI 程序

2012年2月6日作者:enet

 

Article ID: 90493 – Last Review: November 21, 2006 – Revision: 3.2

HOWTO: How To Determine Whether an Application is Console or GUI

This article was previously published under Q90493
————————————————————–

若要确定应用程序是否为控制台或 GUI,您必须分析该 EXEheader。标头包含一个称为子系统的字段。此字段确定是要在其下运行的应用程序子系统和它需要的接口的类型。值组成:

IMAGE_SUBSYSTEM_NATIVE               1
IMAGE_SUBSYSTEM_WINDOWS_GUI          2
IMAGE_SUBSYSTEM_WINDOWS_CUI          3
IMAGE_SUBSYSTEM_OS2_CUI              5
IMAGE_SUBSYSTEM_POSIX_CUI            7
IMAGE_SUBSYSTEM_NATIVE_WINDOWS       8
IMAGE_SUBSYSTEM_WINDOWS_CE_GUI       9

示例代码

#include <windows.h>
#include <winnt.h>

VOID  main(int, char **);
DWORD AbsoluteSeek(HANDLE, DWORD);
VOID  ReadBytes(HANDLE, LPVOID, DWORD);
VOID  WriteBytes(HANDLE, LPVOID, DWORD);
VOID  CopySection(HANDLE, HANDLE, DWORD);

#define XFER_BUFFER_SIZE 2048

VOID
main(int argc, char *argv[])
{
HANDLE hImage;

DWORD  bytes;
DWORD  iSection;
DWORD  SectionOffset;
DWORD  CoffHeaderOffset;
DWORD  MoreDosHeader[16];

ULONG  ntSignature;

IMAGE_DOS_HEADER      image_dos_header;
IMAGE_FILE_HEADER     image_file_header;
IMAGE_OPTIONAL_HEADER image_optional_header;
IMAGE_SECTION_HEADER  image_section_header;

if (argc != 2)
{
printf("USAGE: %s program_file_name\n", argv[1]);
exit(1);
}

/*
*  Open the reference file.
*/
hImage = CreateFile(argv[1],
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);

if (INVALID_HANDLE_VALUE == hImage)
{
printf("Could not open %s, error %lu\n", argv[1], GetLastError());
exit(1);
}

/*
*  Read the MS-DOS image header.
*/
ReadBytes(hImage,
&image_dos_header,
sizeof(IMAGE_DOS_HEADER));

if (IMAGE_DOS_SIGNATURE != image_dos_header.e_magic)
{
printf("Sorry, I do not understand this file.\n");
exit(1);
}

/*
*  Read more MS-DOS header.       */
ReadBytes(hImage,
MoreDosHeader,
sizeof(MoreDosHeader));

/*
*  Get actual COFF header.
*/
CoffHeaderOffset = AbsoluteSeek(hImage, image_dos_header.e_lfanew) +
sizeof(ULONG);

ReadBytes (hImage, &ntSignature, sizeof(ULONG));

if (IMAGE_NT_SIGNATURE != ntSignature)
{
printf("Missing NT signature. Unknown file type.\n");
exit(1);
}

SectionOffset = CoffHeaderOffset + IMAGE_SIZEOF_FILE_HEADER +
IMAGE_SIZEOF_NT_OPTIONAL_HEADER;

ReadBytes(hImage,
&image_file_header,
IMAGE_SIZEOF_FILE_HEADER);

/*
*  Read optional header.
*/
ReadBytes(hImage,
&image_optional_header,
IMAGE_SIZEOF_NT_OPTIONAL_HEADER);

switch (image_optional_header.Subsystem)
{
case IMAGE_SUBSYSTEM_UNKNOWN:
printf("Type is unknown.\n");
break;

case IMAGE_SUBSYSTEM_NATIVE:
printf("Type is native.\n");
break;

case IMAGE_SUBSYSTEM_WINDOWS_GUI:
printf("Type is Windows GUI.\n");
break;

case IMAGE_SUBSYSTEM_WINDOWS_CUI:
printf("Type is Windows CUI.\n");
break;

case IMAGE_SUBSYSTEM_OS2_CUI:
printf("Type is OS/2 CUI.\n");
break;

case IMAGE_SUBSYSTEM_POSIX_CUI:
printf("Type is POSIX CUI.\n");
break;

case IMAGE_SUBSYSTEM_NATIVE_WINDOWS:
printf("Type is native Win9x driver.\n");
break;

case IMAGE_SUBSYSTEM_WINDOWS_CE_GUI:
printf("Type is Windows CE.\n");
break;

default:
printf("Unknown type %u.\n", image_optional_header.Subsystem);
break;
}
}

DWORD
AbsoluteSeek(HANDLE hFile,
DWORD  offset)
{
DWORD newOffset;

if ((newOffset = SetFilePointer(hFile,
offset,
NULL,
FILE_BEGIN)) == 0xFFFFFFFF)
{
printf("SetFilePointer failed, error %lu.\n", GetLastError());
exit(1);
}

return newOffset;
}

VOID
ReadBytes(HANDLE hFile,
LPVOID buffer,
DWORD  size)
{
DWORD bytes;

if (!ReadFile(hFile,
buffer,
size,
&bytes,
NULL))
{
printf("ReadFile failed, error %lu.\n", GetLastError());
exit(1);
}
else if (size != bytes)
{
printf("Read the wrong number of bytes, expected %lu, got %lu.\n",
size, bytes);
exit(1);
}
}