#define MAXNUM 1024
/
// CProcessInfo.h
struct _GET_PROCESS_INFO
{
PROCESSENTRY32 processentry[MAXNUM];
THREADENTRY32 threadentry[MAXNUM];
MODULEENTRY32 moduleentry[MAXNUM];
HEAPLIST32 heaplistentry[MAXNUM];
HEAPENTRY32 heapentry[MAXNUM];
} GET_PROCESS_INFO, *PGET_PROCESS_INFO;
class CProcessInfo
{
public:
CProcessInfo();
~CProcessInfo(){};
//DWORD OnIdle();
BOOL EnableDebugPrivilege(BOOL fEnable);
void GetProcessSnap();
void GetProcessSnapAll(DWORD th32ProcessID);
int Run();
DWORD dlgThreadId;
};
inline CProcessInfo::CProcessInfo(DWORD id)
{
EnableDebugPrivilege(TRUE);
dlgThreadId=id;
}
inline int CProcessInfo::Run()
{
MSG msg;
PeekMessage(&msg, NULL, WM_USER, WM_USER+1000, PM_NOREMOVE);
for (;;)
{
if(!::PeekMessage(&m_msg, NULL, 0, 0, PM_NOREMOVE))
{
PostThreadMessage(dlgThreadId, WM_USER, GetProcessSnap(), 0);
::OutputDebugString(_T("Sleep(444)/r/n"));
Sleep(444);
}
bRet = ::GetMessage(&m_msg, NULL, 0, 0);
}
EnableDebugPrivilege(FALSE);
int nRet = 0;
return nRet;
}
inline BOOL CProcessInfo::EnableDebugPrivilege(BOOL fEnable)
{
BOOL fOk = FALSE;
HANDLE hToken;
if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken))
{
TOKEN_PRIVILEGES tp;
tp.PrivilegeCount = 1;
LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tp.Privileges[0].Luid);
tp.Privileges[0].Attributes = fEnable ? SE_PRIVILEGE_ENABLED : 0;
AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), NULL, NULL);
fOk = (GetLastError() == ERROR_SUCCESS);
CloseHandle(hToken);
}
return(fOk);
}
inline LPVOID CProcessInfo::GetProcessSnap()
{
//列出所有进程
HANDLE snapshothandle=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
PROCESSENTRY32 processentry[MAXNUM];
int i=0;
processentry.dwSize=sizeof(PROCESSENTRY32);
BOOLfinded=Process32First(snapshothandle,&processentry[i]);
while(finded!=NULL)
{
++i;
//processentry中返回进程信息
finded=Process32Next(snapshothandle,&processentry[i]);
}
CloseHandle(snapshothandle);
return processentry;
}
inline LPVOID CProcessInfo::GetProcessAllInfo(DWORD th32ProcessID)
{
PGET_PROCESS_INFO processinfo;
//列出所有信息
HANDLE snapshothandle=CreateToolhelp32Snapshot(TH32CS_SNAPALL,th32ProcessID);
int i=0;
processinfo.threadentry[i].dwSize=sizeof(THREADENTRY32);
BOOLfinded=Thread32First(snapshothandle,&processinfo.threadentry[i]);
while(finded!=NULL)
{
++i;
//threadentry中返回线程信息
finded=Thread32Next(snapshothandle,&processinfo.threadentry[i]);
}
i=0;
processinfo.moduleentry[i].dwSize=sizeof(MODULEENTRY32);
finded=Module32First(snapshothandle,&processinfo.moduleentry[i]);
while(finded!=NULL)
{
++i;
//moduleentry中返回模块信息
finded=Module32Next(snapshothandle,&processinfo.moduleentry[i]);
}
i=0;
//先得到堆表 再列出堆
HANDLE snapshothandle=CreateToolhelp32Snapshot(TH32CS_SNAPHEAPLIST,th32ProcessID);
processinfo.heaplistentry[i].dwSize=sizeof(HEAPLIST32);
finded=Heap32ListFirst(snapshothandle,&processinfo.heaplistentry[i]);
while(finded!=NULL)
{
//heaplistentry中返回堆表信息
//列出堆表中的的堆
processinfo.heapentry[k].dwSize=sizeof(HEAPENTRY32);
int k=0;
//heaplistentry.th32HeapID为堆ID
BOOLfinded2=Heap32First(&processinfo.heapentry[k],th32ProcessID,processinfo.heaplistentry[i].th32HeapID);
while(finded2!=NULL)
{
++k;
//heapentry中返回堆信息
finded2=Heap32Next(&processinfo.heapentry[k]);
}
++i;
finded=Heap32ListNext(snapshothandle,&processinfo.heaplistentry[i]);
}
CloseHandle(snapshothandle);
return processinfo;
}
/
// PEInfo.h
//-------
//NT head
#define NTSIGNATURE(a) ((LPVOID)((BYTE *)a + ((PIMAGE_DOS_HEADER)a)->e_lfanew))
//File head
#define PEFHDROFFSET(a) ((LPVOID)((BYTE *)a + ((PIMAGE_DOS_HEADER)a)->e_lfanew + SIZE_OF_NT_SIGNATURE))
//Optonal head
#define OPTHDROFFSET(a) ((LPVOID)((BYTE *)a + ((PIMAGE_DOS_HEADER)a)->e_lfanew + SIZE_OF_NT_SIGNATURE + sizeof (IMAGE_FILE_HEADER)))
//First Section head
#define SECHDROFFSET(a) ((LPVOID)((BYTE *)a + ((PIMAGE_DOS_HEADER)a)->e_lfanew + SIZE_OF_NT_SIGNATURE + sizeof (IMAGE_FILE_HEADER) + sizeof (IMAGE_OPTIONAL_HEADER)))
//-------
struct _GET_EXPORT_INFO
{
char *Characteristics;
char *TimeDateStamp;
char *MajorVersion;
char *MinorVersion;
char *Base;
char *ModuleName[1];
char *FunctionName[MAXNUM];
char *FunctionAddress[MAXNUM];
char *Ordinals[MAXNUM];
} GET_EXPORT_INFO, *PGET_EXPORT_INFO[MAXNUM];
struct _GET_IMPORT_INFO
{
/*在可执行文件被加载之前,IMAGE_THUNK_DATA结构最高位1,是导入函数的序数 IMAGE_THUNK_DATA.u1.Ordinal
0是导入函数名,(IMAGE_IMPORT_BY_NAME)IMAGE_THUNK_DATA.u1.AddressOfData.Name[1]
CFile PEfile.Read((IMAGE_THUNK_DATA)pid->FirstThunk,1);*/
char *ModuleName[1];
char *FunctionName[MAXNUM];
char *IAT[MAXNUM];
char *TimeDateStamp;
char *ForwarderChain;
} GET_IMPORT_INFO, *PGET_EXPORT_INFO[MAXNUM];
class CPEInfo
{
public:
CPEInfo();
~CPEInfo(){};
DWORD CPEInfo::ImageFileType (LPVOID lpFile);
BOOL CPEInfo::GetSectionHdrByName (LPVOID lpFile, IMAGE_SECTION_HEADER *sh, char *szSection, HANDLE hProcess);
LPVOID CPEInfo::ImageDirectoryOffset (LPVOID lpFile, DWORD dwIMAGE_DIRECTORY, bool bFile);
LPVOID CPEInfo::GetImportTableOfRam (LPVOID lpFile, HANDLE hProcess, PGET_EXPORT_INFO *pImportInfo);
LPVOID CPEInfo::GetExportTableOfRam (LPVOID lpFile, HANDLE hProcess, PGET_EXPORT_INFO *pExportInfo);
LPVOID CPEInfo::GetPEInfoOfRam(HANDLE hProcess, LPVOID PathName);
LPVOID CPEInfo::GetExportTableOfFileMaping (LPVOID lpFile, PGET_EXPORT_INFO *pExportInfo);
LPVOID CPEInfo::GetImportTableOfFileMaping (LPVOID lpFile, PGET_EXPORT_INFO *pImportInfo);
LPVOID CPEInfo::GetPEInfoOfFileMaping(LPVOID PathName);
};
inline DWORD CPEInfo::ImageFileType (LPVOID lpFile)
{
/* DOS文件签名先出现。 */
if (*(USHORT *)lpFile == IMAGE_DOS_SIGNATURE)
{
/* 从DOS头开始确定PE文件头的位置。 */
if (LOWORD (*(DWORD *)NTSIGNATURE (lpFile)) == IMAGE_OS2_SIGNATURE ||
LOWORD (*(DWORD *)NTSIGNATURE (lpFile)) == IMAGE_OS2_SIGNATURE_LE)
{
/* 返回OS头 */
return (DWORD)LOWORD(*(DWORD *)NTSIGNATURE (lpFile));
}
else if (*(DWORD *)NTSIGNATURE (lpFile) == IMAGE_NT_SIGNATURE)
{
/* 返回NT头,只有NT才进行处理 */
return IMAGE_NT_SIGNATURE;
}
else
{
/* 返回DOS头 */
return IMAGE_DOS_SIGNATURE;
}
}
/* 未知的文件类型。 */
else return 0;
}
inline BOOL CPEInfo::GetSectionHdrByName (LPVOID lpFile, IMAGE_SECTION_HEADER *sh, char *szSection, HANDLE hProcess)
{
PIMAGE_SECTION_HEADER psh;
// 取得有多少个节
int nSections = NumOfSections (lpFile);
int i;
// 节头起始地址
if ((psh = (PIMAGE_SECTION_HEADER)SECHDROFFSET (lpFile)) != NULL)
{
/* 按名字循环寻找节 */
for (i=0; i<nSections; i++)
{
if (!strcmp (psh->Name, szSection))
{
/* 将节名相同的节头信息复制到 sh */
ReadProcessMemory(hProcess, psh, &sh, sizeof(IMAGE_SECTION_HEADER), null);
return TRUE;
}
else psh++;
}
}
// 其他节取法相同
return FALSE;
}
inline LPVOID CPEInfo::ImageDirectoryOffset (LPVOID lpFile, DWORD dwIMAGE_DIRECTORY, bool bFile)
{
PIMAGE_OPTIONAL_HEADER poh;
PIMAGE_SECTION_HEADER psh;
int nSections = NumOfSections (lpFile);
int i = 0;
LPVOID VAImageDir;
/* 先验证所求数据目录项的数字 */
if (dwIMAGE_DIRECTORY >= poh->NumberOfRvaAndSizes)
return NULL;
/* 可选头偏移量指针 */
poh = (PIMAGE_OPTIONAL_HEADER)OPTHDROFFSET (lpFile);
/* 节头偏移量指针 */
psh = (PIMAGE_SECTION_HEADER)SECHDROFFSET (lpFile);
/* 定位可选头 数据目录(DataDirectory) 相对虚拟地址。 */
VAImageDir = (LPVOID)poh->DataDirectory[dwIMAGE_DIRECTORY].VirtualAddress;
/* 定位节身 循环n个节身 */
while (i++<nSections)
{
//节身起始位置(相对虚拟地址) <= 数据目录.VirtualAddress < 节身结束位置(相对虚拟地址)
if (psh->VirtualAddress <= (DWORD)VAImageDir && (DWORD)VAImageDir < (psh->VirtualAddress+psh->SizeOfRawData) )
break;
psh++;
}
if (i > nSections)
return NULL;
/*
lpFile + psh->PointerToRawData 可执行文件内存基址 + 文件中节身的偏移量 = 节身在内存中实际地址
如果数据目录的虚拟地址不等于节身的偏移量,就要相减 VAImageDir - psh->VirtualAddress ,得出的差再加上上面“节头在内存中实际地址”
*/
// (内存中 数据目录 RVA) - (内存中 节 起始位置RVA) = (节中 数据目录 RVA) (ps: 数据目录在节中, 文件或内存中这个RVA是固定)
// (节中 数据目录 RVA) + (文件中 节 RVA) = (文件中 数据目录 RVA)
// (文件中 数据目录 RVA) + lpFile = 映像文件输入目录的偏移量????
if (bFile)
return (LPVOID)(((int)lpFile + (int)VAImageDir - psh->VirtualAddress) + (int)psh->PointerToRawData);
else //返回内存中输入目录的偏移量
return (LPVOID)((int)lpFile + (int)VAImageDir - psh->VirtualAddress);
}
inline LPVOID CPEInfo::GetExportTableOfRam (LPVOID lpFile, HANDLE hProcess, PGET_EXPORT_INFO *pExportInfo)
{
PIMAGE_EXPORT_DIRECTORY ped
IMAGE_SECTION_HEADER sh;
int nCnt=0;
/* 取数据目录的指针 */
if ((ped = (PIMAGE_EXPORT_DIRECTORY)ImageDirectoryOffset(lpFile, IMAGE_DIRECTORY_ENTRY_EXPORT, false)) == NULL)
return 0;
/* 取.edata节头 */
if (!GetSectionHdrByName (lpFile, &sh, ".edata"))
return 0;
while (ped->Name)
{
char *addFuns, *addOrds;
char addNames[MAXNUM];
ReadProcessMemory(hProcess, ped->Name, &pExportInfo[nCnt].ModuleName[0], 4, null);
for(int i=0;i<ped.NumberOfFunctions;i++)
{
char *RAVFuns = (char *)((int)ped->AddressOfFunctions + (int)lpFile);
ReadProcessMemory(hProcess, RAVFuns, &pExportInfo[nCnt].function[i], 4, null);
ped->AddressOfFunctions+=4;
}
for(int k=0;k<ped.NumberOfNames;k++)
{
char *RAVNames = (char *)((int)ped->AddressOfNames + (int)lpFile);
ReadProcessMemory(hProcess, RAVNames, &pExportInfo[nCnt].FunctionName[k], 4, null);
ped->AddressOfNames+=4;
char *RAVOrds = (char *)((int)ped->AddressOfOrdinals + (int)lpFile);
ReadProcessMemory(hProcess, RAVOrds, &pExportInfo[nCnt].Ordinals[k], 2, null);
ped->AddressOfOrdinals+=2;
}
++ped;
++nCnt;
}
}
inline LPVOID CPEInfo::GetImportTableOfRam (LPVOID lpFile, HANDLE hProcess, PGET_EXPORT_INFO *pImportInfo)
{
IMAGE_SECTION_HEADER idsh;
PIMAGE_EXPORT_DIRECTORY pid;
int nCnt=0;
/* 取数据目录的指针 */
if ((pid = (PIMAGE_EXPORT_DIRECTORY)ImageDirectoryOffset(lpFile, IMAGE_DIRECTORY_ENTRY_IMPORT, false)) == NULL)
return 0;
/* 取.idata节头 */
if (!GetSectionHdrByName (lpFile, &idsh, ".idata"))
return 0;
/* 提取所有的输入模块,模块名以0结束 */
while (pid->Name)
{
/* pData节身 + (模块名偏移地址 - 节身偏移地址) = 模块名实际内存地址 */
int nNameCut=0, nFuncCut=0;
char *RVAModuleName=(char *)(pid->Name + lpFile);
ReadProcessMemory(hProcess, RVAModuleName, &pImportInfo[nCut].ModuleName[0], 4, null);
while(pid->OriginalFirstThunk.u1.AddressOfData.Name[1])
{
char *RVAFunctionName=(char *)(pid->OriginalFirstThunk.u1.AddressOfData.Name[1] + lpFile);
ReadProcessMemory(hProcess, RVAFunctionName, &pImportInfo[nCut].FunctionName[nNameCut], 4, null);
pid->OriginalFirstThunk+=4;
++nNameCut;
}
while(pid->FirstThunk.u1.Function)
{
char *RVAIAT=(char *)(pid->FirstThunk.u1.Function + lpFile);
ReadProcessMemory(hProcess, RVAIAT, &pImportInfo[nCut].IAT[nFuncCut], 4, null);
pid->FirstThunk+=4;
++nFuncCut;
}
/* 增量到下一个输入目录项。*/
++pid;
++nCnt;
}
}
inline LPVOID CPEInfo::GetPEInfoOfRam(HANDLE hProcess, LPVOID PathName)
{
HMODULE lpFile=GetModuleHandle(PathName);
if(ImageFileType(lpFile) != IMAGE_NT_SIGNATURE)
return 0;
IMAGE_DOS_HEADER dosh;
IMAGE_NT_HEADERS nth; //==NT标志 + IMAGE_FILE_HEADER + IMAGE_OPTIONAL_HEADER
IMAGE_FILE_HEADER fileh;
IMAGE_OPTIONAL_HEADER opth;
IMAGE_SECTION_HEADER sech;
ReadProcessMemory(hProcess, lpFile, &dosh, sizeof(dosh), null);
ReadProcessMemory(hProcess, NTSIGNATURE(lpFile), &nth, sizeof(nth), null);
ReadProcessMemory(hProcess, PEFHDROFFSET(lpFile), &fileh, sizeof(fileh), null);
ReadProcessMemory(hProcess, OPTHDROFFSET(lpFile), &opth, sizeof(opth), null);
ReadProcessMemory(hProcess, SECHDROFFSET(lpFile), &sech, sizeof(sech), null);
//节的总数
fileh.NumberOfSections;
//基址,已经被GetModuleHandle取代,
opth.ImageBase;
//应用程序入口地址,也是输入地址表(Import Address Table,IAT)结束位置 ,因为IAT必定在程序入口地址的前面
opth.AddressOfEntryPoint;
PGET_EXPORT_INFO pExportInfo;
PGET_EXPORT_INFO pImportInfo;
GetExportTableOfRam (lpFile, hProcess, &pExportInfo);
GetImportTableOfRam (lpFile, hProcess, &pImportInfo);
}
//------------------------------------------------ File Maping ------------------------------------------------
inline LPVOID CPEInfo::GetImportTableOfFileMaping (LPVOID lpFile, PGET_EXPORT_INFO *pImportInfo)
{
IMAGE_SECTION_HEADER idsh;
PIMAGE_EXPORT_DIRECTORY pid;
int nCnt=0;
BYTE *pData;
PGET_EXPORT_INFO pImportInfo;
/* 取数据目录的指针 */
if ((pid = (PIMAGE_EXPORT_DIRECTORY)ImageDirectoryOffset(lpFile, IMAGE_DIRECTORY_ENTRY_IMPORT, true)) == NULL)
return 0;
/* 取.idata节头 */
if (!GetSectionHdrByName (lpFile, &idsh, ".idata"))
return 0;
pData = (BYTE *)pid;
/* 提取所有的输入模块,模块名以0结束 */
while (pid->Name)
{
/* pData节身 + (模块名偏移地址 - 节身偏移地址) = 模块名实际内存地址 */
int nNameCut=0; //nFuncCut=0;
char *RVAModuleName=(char *)(pData + (pid->Name - idsh.VirtualAddress));
CopyMemory (&pImportInfo[nCut].ModuleName[0], RVAModuleName, 4);
while(pid->OriginalFirstThunk.u1.AddressOfData.Name[1])
{
char *RVAFunctionName=(char *)(pData + (pid->OriginalFirstThunk.u1.AddressOfData.Name[1] - idsh.VirtualAddress));
CopyMemory (&pImportInfo[nCut].FunctionName[nNameCut], RVAFunctionName, 4);
pid->OriginalFirstThunk+=4;
++nNameCut;
}
/*while(pid->FirstThunk.u1.Function)
{
char *RVAIAT=(char *)(pData + (pid->FirstThunk.u1.Function - idsh.VirtualAddress));
CopyMemory (&pImportInfo[nCut].IAT[nFuncCut], RVAIAT, 4);
pid->FirstThunk+=4;
++nFuncCut;
}*/
/* 增量到下一个输入目录项。*/
++pid;
++nCnt;
}
}
inline LPVOID CPEInfo::GetExportTableOfFileMaping (LPVOID lpFile, PGET_EXPORT_INFO *pExportInfo)
{
PIMAGE_EXPORT_DIRECTORY ped
IMAGE_SECTION_HEADER sh;
PGET_EXPORT_INFO pExportInfo;
int nCnt=0;
/* 取数据目录的指针 */
if ((ped = (PIMAGE_EXPORT_DIRECTORY)ImageDirectoryOffset(lpFile, IMAGE_DIRECTORY_ENTRY_EXPORT, true)) == NULL)
return 0;
/* 取.edata节头 */
if (!GetSectionHdrByName (lpFile, &sh, ".edata"))
return 0;
while (ped->Name)
{
//pNames = (char *)(*(int *)((int)ped->AddressOfNames - (int)sh.VirtualAddress + (int)sh.PointerToRawData + (int)lpFile) - (int)sh.VirtualAddress + (int)sh.PointerToRawData + (int)lpFile);
char *addFuns, *addOrds;
char addNames[MAXNUM];
CopyMemory (&pExportInfo[nCnt].ModuleName[0], ped->Name, 4);
for(int i=0;i<ped.NumberOfFunctions;i++)
{
char *RAVFuns = (char *)((int)ped->AddressOfFunctions - (int)sh.VirtualAddress + (int)sh.PointerToRawData + (int)lpFile);
CopyMemory (&pExportInfo[nCnt].function[i], RAVFuns, 4);
ped->AddressOfFunctions+=4;
}
for(int k=0;k<ped.NumberOfNames;k++)
{
char *RAVNames = (char *)((int)ped->AddressOfNames - (int)sh.VirtualAddress + (int)sh.PointerToRawData + (int)lpFile);
CopyMemory (&pExportInfo[nCnt].FunctionName[k], RAVNames, 4);
ped->AddressOfNames+=4;
char *RAVOrds = (char *)((int)ped->AddressOfOrdinals - (int)sh.VirtualAddress + (int)sh.PointerToRawData + (int)lpFile);
CopyMemory (&pExportInfo[nCnt].Ordinals[k], RAVOrds, 4);
ped->AddressOfOrdinals+=2;
}
++ped;
++nCnt;
}
}
inline LPVOID CPEInfo::GetPEInfoOfFileMaping(LPVOID PathName)
{
HANDLE hFile;
HANDLE hMapping;
void *pFileView;
// 打开文件
if ((hFile = CreateFile(PathName, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, 0))
== INVALID_HANDLE_VALUE)
{
printf("Can't open file./n");
return 0;
}
// 创建内存映射文件
if (!(hMapping = CreateFileMapping(hFile, 0, PAGE_READONLY|SEC_COMMIT, 0, 0, 0)))
{
printf("Mapping failed./n");
CloseHandle(hFile);
return 0;
}
// 获取文件映象
if (!(pFileView = MapViewOfFile(hMapping,FILE_MAP_READ,0,0,0)))
{
printf("View failed./n");
CloseHandle(hMapping);
CloseHandle(hFile);
return 0;
}
if(ImageFileType(pFileView) != IMAGE_NT_SIGNATURE)
return 0;
IMAGE_DOS_HEADER dosh = (IMAGE_DOS_HEADER*)pFileView;
IMAGE_NT_HEADERS nth = (IMAGE_NT_HEADERS*)NTSIGNATURE(pFileView); //==NT标志 + IMAGE_FILE_HEADER + IMAGE_OPTIONAL_HEADER
IMAGE_FILE_HEADER fileh = (IMAGE_FILE_HEADER*)PEFHDROFFSET(pFileView);
IMAGE_OPTIONAL_HEADER opth = (IMAGE_OPTIONAL_HEADER*)OPTHDROFFSET(pFileView);
IMAGE_SECTION_HEADER sech = (IMAGE_SECTION_HEADER*)SECHDROFFSET(pFileView);
//节的总数
fileh.NumberOfSections;
//基址,已经被GetModuleHandle取代,
opth.ImageBase;
//应用程序入口地址,也是输入地址表(Import Address Table,IAT)结束位置 ,因为IAT必定在程序入口地址的前面
opth.AddressOfEntryPoint;
PGET_EXPORT_INFO pExportInfo;
PGET_EXPORT_INFO pImportInfo;
GetExportTableOfFileMaping (pFileView, &pExportInfo);
GetImportTableOfFileMaping (pFileView, &pImportInfo);
// 清除内存映射和关闭文件
UnmapViewOfFile(pFileView);
CloseHandle(hMapping);
CloseHandle(hFile);
}
/
// HookApi.cpp
---------------------------------------------------------------------------
//
static int WINAPI GetProcessInfo(LPVOID lpId)
{
DWORD* dCurThreadId = (DWORD*)lpId;
CProcessDtl dtlProcess(dCurThreadId);
int nRet = dtlProcess.Run();
return nRet;
}
DWORD CreateProcessInfoThread(DWORD dCurThreadId)
{
if(m_dwCount == (MAXIMUM_WAIT_OBJECTS - 1))
{
::MessageBox(NULL, _T("ERROR: Cannot create ANY MORE threads!!!"), _T("sample1"), MB_OK);
return 0;
}
DWORD dwThreadID;
HANDLE hThread = ::CreateThread(NULL, 0, GetProcessInfo, dCurThreadId, CREATE_SUSPENDED, &dwThreadID);
if(hThread == NULL)
{
::MessageBox(NULL, _T("ERROR: Cannot create thread!!!"), _T("Main Dialog"), MB_OK);
return 0;
}
m_arrThreadHandles[m_dwCount] = hThread;
m_dwCount++;
return dwThreadID;
}
//
---------------------------------------------------------------------------
---------------------------------------------------------------------------
---------------------------------------------------------------------------
---------------------------------------------------------------------------
---------------------------------------------------------------------------
---------------------------------------------------------------------------
---------------------------------------------------------------------------
---------------------------------------------------------------------------
http://d.download.csdn.net/down/483615/love0_0xin
http://d.download.csdn.net/down/231145/hu030152
http://d.download.csdn.net/down/624375/happyly008
http://d.download.csdn.net/down/515111/loomman