2006年05月02日

/*
//Program: 利用关键代码段(临界区)实现线程同步,测试程序  
//Author: Ideal
//Date: 2006/5/2
*/

#include <stdio.h>
#include <string.h>
#include <windows.h>

DWORD WINAPI CalProc(LPVOID lpParameter);

int flag = 1;
CRITICAL_SECTION g_cs;

void main()
{
 int i=0;
 HANDLE hThread;
 hThread = CreateThread(NULL, 0, CalProc, NULL, 0, NULL);
 CloseHandle(hThread);
 
 //initializes a critical section object
 InitializeCriticalSection(&g_cs);
 
 while(flag)
 {
  //waits for ownership of the specified critical section object
  EnterCriticalSection(&g_cs);
  
  printf("计算中,请耐心等待.");
  printf("\n");
  
  for(i=0; i<6; i++)
  {   
   printf(".");
   Sleep(500);   
  }
  printf("\r");
 
  system("cls");
  printf("\r"); 
  
  //releases ownership of the specified critical section object
  LeaveCriticalSection(&g_cs);  
 }
 
 //releases all resources used by an unowned critical section object
 DeleteCriticalSection(&g_cs);
 printf("\n");
}

DWORD WINAPI CalProc(LPVOID lpParameter)
{
 
 int i;
 int sum=0;
 for(i=0; i<1000000; i++)
 {
  EnterCriticalSection(&g_cs);
  sum+=i;
  LeaveCriticalSection(&g_cs);
 } 

 printf("计算结果为.\n");
 printf("now sum = %d \n", sum);
 flag = 0;
 return 0;
}

result:
=========
(1)计算中,请耐心等待.
     …
(2)计算中,请耐心等待.
     ……
(3)计算中,请耐心等待.
     ..
(4)计算结果为.
     now sum = 1783293664

2006年04月16日


虚基类: 当基类被继承时,在基类的继承访问控制保留字前面加上关键字virtual来定义.
              重复继承基类在派生类对象实例中只存在一个副本.   
——————————————————
class Base{
 public:
     int i;  
};

//类Base是Base1的虚基类
class Base1 :  virtual public Base{
 public:
      int j;
};

//类Base是Base2的虚基类
class Base2 :  virtual public Base{
 public:
      int k;
};
————————————————————————————————————

虚函数:在一个类中用保留字virtual定义成员函数.
             实现运行时多态类,动态绑定(晚期绑定).
——————————————————
class Member{
  public:
      virtual void answer(){
        cout << "I am a member." <<endl;
      }
};

//一般需要在派生类中重定义(overriding),virtual 关键字可以不要
class Teacher : class Member{
  public:
      virtual void answer(){
        cout << "I am a teacher." <<endl;
      }
};

class Student: class Member{
  public:
      virtual void answer(){
        cout << "I am a studen." <<endl;
      }
};
————————————————————————————————————

纯虚函数: 在基类中声明但在基类中没有定义的虚函数.
                  实现抽象类,抽象类不能创建对象,但可用指向对象的指针支持运行时多态.
                  任何派生类都必须重定义该函数,因为不能直接使用从基类继承下来的纯虚函数.
纯虚函数一般形式: virtual 类型 函数名(参数表)  = 0;
——————————————————
class Figure{
  public:
      virtual void show( ) = 0;
      virtual void hide( ) = 0;
};

class Triangle : public Figure{
  virtual void show(){
     ……
  }
  virtual void hide(){
     ……
  }
};

class Circle : public Figure{
  virtual void show(){
     ……
  }
  virtual void hide(){
    ……
  }
};
————————————————————————————————————

2006年04月15日

SYMPTOMS

When you try to install Microsoft Internet Information Services (IIS) on a computer that is running Microsoft Windows XP Professional with Service Pack 2 (SP2), you may receive one of the following error messages:

Copy error:

Setup cannot copy the file staxmem.dll. Please insert the "Windows XP Professional Service Pack 2 CD".
Setup could not copy one or more files. The specific error code is 0×4b8

However, when you put the Windows XP Professional SP2 CD in your CD drive, Setup cannot find the Staxmem.dll file.


2006年04月13日


程序自我删除,在很多情况下都可能用到,比如程序反安装就是一个典型的自我删除的过程,当然更多的应该是用在木马、病毒安装自动删除上等…
实现程序自我删除的方法应该有很多种,线程插入权限提升法就算是比较热门了,当然还有一些其它的.
网上也看到了类似用批处理来实现自我删除的代码,但是很奇怪,当把程序放在桌面上时,运行并不能删除自己,而放在其它地方则可以实现自我删除,因为它们都是采用下面提到的bat2.bat类式的写法.
对此,百思不得其解,如果你知道为什么希望告知,谢谢.

一个有趣的现象(XP SP2 CHN):
桌面上分别建立以下两个批处理文件bat1.bat,bat2.bat.
—————————————————————————————–
bat1.bat中的内容:
cd C:\Documents and Settings\Administrator\桌面
del bat1.bat
—————
bat2.bat中的内容:
del C:\Documents and Settings\Administrator\桌面\bat2.bat
—————————————————————————————–
分别运行很惊奇发现bat1.bat可以顺利除自己,而bat2.bat则不能…提示的错误是:系统找不到指定的路径。无语ing…

好了,根据bat1.bat分别提取程序所在路径和文件名然后进行相应处理,就可以实现能真正能删除自己的程序了…

新建一个Win32 Console Application,并且支持MFC工程,代码如下..

——————————————————————————————————-

/*
//Progaram: Delete itself
//Author: Ideal
//Date: 2006/4/13
*/

// DelSelf.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "DelSelf.h"
#include <process.h>

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// The one and only application object

CWinApp theApp;

using namespace std;

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
 int nRetCode = 0;

 // initialize MFC and print and error on failure
 if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
 {
  // TODO: change error code to suit your needs
  cerr << _T("Fatal Error: MFC initialization failed") << endl;
  nRetCode = 1;
 }
 else
 {
  // TODO: code your application’s behavior here.

  char moduleName[MAX_PATH];
  char batFile[MAX_PATH];
  LPSTR tempDir;
  char Buf[MAX_PATH];
  
  GetModuleFileName(NULL, moduleName, MAX_PATH);
  tempDir = ((GetEnvironmentVariable(TEXT("TEMP"),Buf,MAX_PATH)>0) ? Buf : NULL);
  strcpy(batFile, tempDir);
  strcat(batFile, "\\");
  strcat(batFile, "delself.bat");
  
  CString fileAll;
  fileAll = moduleName;


  //split path and name
  CString fileName = fileAll.Mid(fileAll.ReverseFind(‘\\’) + 1);
  CString filePath = fileAll.Mid(0, fileAll.ReverseFind(‘\\’));

  char* pFileName = batFile;
  CStdioFile file;
  file.Open(pFileName, CFile::modeCreate|CFile::modeReadWrite);
  file.WriteString("@echo off\n:try \n");
  file.WriteString("cd ");
  file.WriteString(filePath);
  file.WriteString("\ndel ");
  file.WriteString(fileName);
  file.WriteString("\nif exist ");
  file.WriteString(moduleName);
  file.WriteString(" goto try \n");
  file.WriteString("del ");
  file.WriteString(batFile);
  file.Close();
  
  Sleep(3000);
  WinExec(batFile, SW_HIDE);
 } 
 return nRetCode;
}

——————————————————————————————————-

2006年03月28日


重复继承(repeated inheritance):一个派生类多次继承同一个基类.
但C++并不允许一个派生类直接继承同一个基类两次或以上.

重复继承的两个种类:复制继承和共享继承

重复继承中的共享继承:通过使用虚基类,使重复基类在派生对象实例中只存储一个副本.

涉及到共享继承的派生类对象的初始化次序规则
① 最先调用虚基类的构造函数.
② 其次调用普通基类的构造函数,多个基类则按派生类声明时列出的次序从左到右.
③ 再次调用对象成员的构造函数,按类声明中对象成员出现的次序调用.
④ 最后执行派生类的构造函数.

析构函数执行次序与其初始化顺序相反.

例:
/*
//Program: repeated inheritance, virtual base class test
//Author: Ideal
//Date: 2006/3/28
*/

#include <iostream.h>

class baseA
{
public:
 baseA()
 {
  cout << "BaseA class. " << endl;
 }
};

class baseB
{
public:
 baseB()
 {
  cout << "BaseB class. " << endl; 
 }
};

class derivedA:public baseB, virtual public baseA
{
public:
 derivedA()
 {
  cout << "DerivedA class. " << endl;
 }
};

class derivedB:public baseB, virtual public baseA
{
public:
 derivedB()
 {
  cout << "DerivedB class. " << endl;
 }
};

class Derived:public derivedA, virtual public derivedB
{
public:
 Derived()
 {
  cout << "Derived class. " << endl;
 }
};

void main()
{
 Derived obj;
 cout << endl;
}

result:
=========
BaseA class.
BaseB class.
DerivedB class.
BaseB class.
DerivedA class.
Derived class.

————————————————————————————————————————
分析:各类的类层次结构关系为
①Derived从derivedA和虚基类derivedB共同派生而来
②derivedA从baseB和虚基类baseA派生而来, derivedB从baseB和虚基类baseA派生而来

执行顺序(构造函数)
由第①层关系,根据规则可得顺序为derivedB,derivedA,Derived.

然后,对于derivedB,同样根据规则更深入分析得到的顺序是baseA,baseB,derivedB.

对于derivedA,值得注意的是derivedA和derivedB都经过虚基类baseA的派生,所以根据只存储一个副本的处理方法,

由于baseA在derivedB中已经被初始化过,derivedA中将不必再进行初始化,所以执行的将是baseB, derivedA.

最后就是Derived了.

综合可得对应构造函数顺序: baseA(), baseB(), derivedB(); baseB(), derivedA(); Derived();  

2006年03月23日

/*
//Program: 利用自动重置事件对象实现线程同步,测试程序  
//Author: Ideal
//Date: 2006/3/23
*/

#include <stdio.h>
#include <string.h>
#include <windows.h>

DWORD WINAPI CalProc(LPVOID lpParameter);
DWORD WINAPI Print(LPVOID lpParameter);

HANDLE g_hEvent;
int flag = 1;

void main()
{
 HANDLE hThreadC;
 HANDLE hThreadP;
 hThreadC = CreateThread(NULL, 0, CalProc, NULL, 0, NULL);
 hThreadP = CreateThread(NULL, 0, Print, NULL, 0, NULL);
 CloseHandle(hThreadC);
 CloseHandle(hThreadP);
 
 //creates an auto-reset event object, nonsignaled, without a name
 //then sets the specified event object to the signaled state
 g_hEvent=CreateEvent(NULL,FALSE,FALSE,NULL);
 SetEvent(g_hEvent);

 Sleep(30000);
 CloseHandle(g_hEvent);
 
 printf("\n");
}

DWORD WINAPI Print(LPVOID lpParameter)
{
 int i=0;
 while(flag)
 { 
  //WaitForSingleObject function returns
  //object’s state is nonsignaled
  WaitForSingleObject(g_hEvent,INFINITE);

  printf("计算中,请耐心等待.");
  printf("\n");
  i=0;
  for(i; i<6; i++)
  {  
   printf(".");
   Sleep(500);  
  }
  printf("\r");
  system("cls");
  printf("\r");
  

  //sets the specified event object to the signaled state
  SetEvent(g_hEvent);
 }
 exit(0);
 return 0;
}

DWORD WINAPI CalProc(LPVOID lpParameter)
{
 int i;
 int sum=0;
 for(i=0; i<100; i++)
 {
  WaitForSingleObject(g_hEvent,INFINITE);
  sum+=i;
  SetEvent(g_hEvent);
 }
 printf("计算结果为.\n");
 printf("now sum = %d \n", sum);
 flag = 0;
 return 0;
}


result:
=========
(1)计算中,请耐心等待.
     …
(2)计算中,请耐心等待.
     ……
(3)计算中,请耐心等待.
     ..
(4)计算结果为.
     now sum = 4950

2006年03月19日


说明: 以下"========"分隔线之间内容选自Adam’s Assembler Tutorial 1.0.
Adam’s Assembler Tutorial is COPYRIGHT, and all rights are reserved by the author.

========

   ■ AX   – the accumulator.  Comprises AH and AL, the high and low bytes
            of AX.  Commonly used in mathematical and I/O operations.
 
   ■ BX   – the base.  Comprises BH and BL.  Commonly used as a base or
            pointer register.
 
   ■ CX   – the counter.  Comprises CH and CL.  Used often in loops.
 
   ■ DX   – the displacement, similar to the base register.  Comprises DH and
            DL.  I think you’re getting the pattern now.

———

   ■ CS – the code segment.  The block of memory where the code is stored.
          DON’T fool around with this one unless you know what you are doing.
          I’m not all that sure that you can actually change it – I’ve never
          tried.
 
   ■ DS – the data segment.  The area in memory where the data is stored.
          During block operations when vast blocks of data are moved, this is
          the segment which the CPU commonly refers to.
 
   ■ ES – the extra segment.  Just another data segment, but this one is
          commonly used when accessing the video.
 
   ■ SS – no, not the German army.  This is the stack segment, in which the
          CPU stores return addresses from subroutines.  Take care with this
          one.  :)

——–

   ■ SI – the source index.  Often used in conjuction with block move
          instructions.  This is a pointer within a segment, usually DS, that
          is read from by the CPU.
 
   ■ DI – the destination index.  Again, you’ll use it a lot.  Another pointer
          within a segment, often ES, that is written to by the CPU.
 
   ■ BP – the base pointer, used in conjunction with the stack segment.  We
          won’t be using it a lot.
 
   ■ SP – the stack pointer, commonly used with the stack segment.  DON’T fool
          around with this one until you are sure you know what you are doing.

========

2006年03月18日

一:分析
signed int 与 unsigned int在占用字节数是一样的.
不同的是signed int 有一个位用来表示符号位,以来区分数的正负,而unsigned int 没有这一符号位.至少从
表面上我们可以这样认为.
假设int占用n个字节,那么signed int 表示数的范围是(sMin — sMax): 即-2的(n-1)次方 到 2的(n-1)次方
减1; 而unsigned int表示的范围是(uMin — uMax): 即0 到 2的n次方减1;
一个变量只要数据类型确实,它的表示范围也就确定了.

问题可以作如下描述:
假设用一个X代替signed 或 unsigned.
那么一个整型变量num可定义为 X int num; 也就是说,X现在对我们来说是透明的,可能为signed,也可能为unsigned.
现在要做的是,判断此时的num变量为signed int 还是unsigned int;

很明显,如果给num赋一足够大的值,就可以做到使signed int溢出,而unsigned int正常.此时如果取(sMax+1)到uMax之间(包括sMax+1,uMax)的数就可以做到,假设在期间取出一个值为va.然后将va赋值给num,此时如果
X int num;为signed int num;则产生溢出;若此时X int num为 unsigned int num;则正常.

值得注意的是并不能用va溢出后的值来与原va值来作相等与否判断,来判断溢出后的值与原va值不等,然后判
定其为一signed int型变量.因为,其实在内存中溢出前与溢出后两者的表示是一样.以int为四个字节为例,数
值为4294967295,其在内存中表示为FF FF FF FF,而当把它赋给unsigned int变量,溢出后数值为-1,但内存中
的表示仍然为FF FF FF FF,如果此时进行比较操作,此时-1==4294967295 而不是!=
正确的方法是判断va经赋值给num后判断num与0的关系.如果num<0成立则知signed int,否则usigned int;

二:实现程序
/*
//Program: judge a integer variable signed or unsigned
//Author: Ideal
//Date: 2006/3/18
*/

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

void main()
{
 signed int sNum; //a signed integer
 unsigned int uNum; //a unsigned integer
 unsigned int uMax; //maximal value of integer
 uMax = (int)pow(2, sizeof(int)*8)-1;
 sNum = uMax;
 uNum = uMax;
 
 //compare with zero
 //not judge sNum equal uMax or not

 if(sNum < 0)
  printf("sNum is signed int variable. \n");
 else
  printf("sNum is unsigned int variable. \n");

 if(uNum < 0)
  printf("uNum is signed int variable. \n");
 else
  printf("uNum is unsigned int variable. \n");
}

result:
=========
sNum is signed int variable.
uNum is unsigned int variable.

2006年03月16日

/*
//Program: 多线程程序的编写,互斥对象来实现多线程的同步,测试程序  
//Author: Ideal
//Date: 2006/3/15
*/

#include <stdio.h>
#include <string.h>
#include <windows.h>

DWORD WINAPI CalProc(LPVOID lpParameter);

int flag = 1;
HANDLE hMutex;

void main()
{
 int i=0;
 HANDLE hThread;
 hThread = CreateThread(NULL, 0, CalProc, NULL, 0, NULL);
 CloseHandle(hThread);
//没有谁拥有权,有信号状态
 hMutex = CreateMutex(NULL, FALSE, NULL); 

 while(flag)
 {
  //有信号,所以拥有权产生,改变为无信号
  WaitForSingleObject(hMutex,INFINITE); 

  printf("计算中,请耐心等待.");
  printf("\n");
  i=0;
  for(i; i<6; i++)
  {  
   printf(".");
   Sleep(500);  
  }
  printf("\r");
  system("cls");
  printf("\r"); 
 
  ReleaseMutex(hMutex);
 

 }
 printf("\n");
}

DWORD WINAPI CalProc(LPVOID lpParameter)
{
 int i;
 int sum=0;
 for(i=0; i<100; i++)
 {
  WaitForSingleObject(hMutex, INFINITE);
  sum+=i;
  ReleaseMutex(hMutex);
 }
 printf("计算结果为.\n");
 printf("now sum = %d \n", sum);
 flag = 0;
 return 0;
}

result:
=========
(1)计算中,请耐心等待.
     …
(2)计算中,请耐心等待.
     ……
(3)计算中,请耐心等待.
     ..
(4)计算结果为.
     now sum = 4950
 


 




2006年03月15日

一:服务器端(UDP)
Header: Declared in Winsock2.h.
Library: Use Ws2_32.lib.

1.加载套接字库
int WSAStartup(
  WORD wVersionRequested,
  LPWSADATA lpWSAData // [out]
);
利用WORD MAKEWORD(BYTE bLow, BYTE bHigh);得到wVersionRequested参数信息.
利用BYTE LOBYTE(WORD wValue); BYTE HIBYTE(WORD wValue);取得低位和高位字节.
利用int WSACleanup(void);终止对socket的使用.

2.创建套接字
SOCKET socket(
  int af,
  int type,
  int protocol
);
3.绑定套接字
int bind(
  SOCKET s,
  const struct sockaddr* name,
  int namelen
);

struct sockaddr {
   unsigned short sa_family;
   char sa_data[14];
};

struct sockaddr_in{
   short sin_family;
   unsigned short sin_port;
   struct in_addr sin_addr;
   char sin_zero[8];
};

struct in_addr { 
union {   
struct { u_char s_b1,s_b2,s_b3,s_b4;} S_un_b;   
struct { u_short s_w1,s_w2;} S_un_w;   
u_long S_addr;
} S_un;
};
利用u_long htonl(u_long hostlong);将主机字节序转换为TCP/IP网络字节序.
利用u_short htons(u_short hostshort);将主机字节序转换为TCP/IP网络字节序.
指定端口号时用大于1024的数值.

sizeof(SOCKADDR)得到namelen参数值.

4.接收数据
int recvfrom(
  SOCKET s,
  char* buf, [out]
  int len,
  int flags,
  struct sockaddr* from, [out]
  int* fromlen [in, out]
);

5.关闭套接字,终止套接字库的使用
int closesocket(
  SOCKET s
);

int WSACleanup(void);

二:客户端(UDP)
Header: Declared in Winsock2.h.
Library: Use Ws2_32.lib.

1.加载套接字库
int WSAStartup(
  WORD wVersionRequested,
  LPWSADATA lpWSAData // [out]
);
利用WORD MAKEWORD(BYTE bLow, BYTE bHigh);得到wVersionRequested参数信息.
利用BYTE LOBYTE(WORD wValue); BYTE HIBYTE(WORD wValue);取得低位和高位字节.
利用int WSACleanup(void);终止对socket的使用.

2.创建套接字
SOCKET socket(
  int af,
  int type,
  int protocol
);

3.发送数据
int sendto(
  SOCKET s,
  const char* buf,
  int len,
  int flags,
  const struct sockaddr* to,
  int tolen
);
struct sockaddr {
   unsigned short sa_family;
   char sa_data[14];
};

struct sockaddr_in{
   short sin_family;
   unsigned short sin_port;
   struct in_addr sin_addr;
   char sin_zero[8];
};

struct in_addr { 
union {   
struct { u_char s_b1,s_b2,s_b3,s_b4;} S_un_b;   
struct { u_short s_w1,s_w2;} S_un_w;   
u_long S_addr;
} S_un;
};
利用unsigned long inet_addr(const char* cp);将点分十进制格式IP地址转换为u_long类型

5.关闭套接字,终止套接字库的使用
int closesocket(
  SOCKET s
);

int WSACleanup(void);