询问者
如何得到某个进程的GDI对象句柄列表?

问题
全部回复
-
你好,
感谢你在这里发帖。
查询GDI对象句柄表,因为所有进程共享GDI对象句柄表,所以需要根据进程标识符筛选。此方法需要gdi32.dll的支持。底下demo实现了这个方法,根据进程ID从系统GDI对象句柄表中筛选出所有符合要求的GDI对象句柄,并根据句柄类型分类。仅供参考。
//process.cpp #include <iostream> #include <TCHAR.h> #include "Header.h" int main() { // get process id DWORD dwId = 16888;//process ID // open the process HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, dwId); DWORD err = 0; if (hProcess == NULL) { printf("OpenProcess %u failed\n", dwId); err = GetLastError(); return -1; } DWORD a=NULL; GetProcessHandleCount(hProcess, &a); std::cout << a<<std::endl; // determine if 64 or 32-bit processor SYSTEM_INFO si; GetNativeSystemInfo(&si); // NOTE: as this is undocumented, it *may vary* depending on bitness (32/64) and on Windows version. // use WinDbg "dt ntdll!_PEB" command and search for GdiSharedHandleTable offset to find the truth out DWORD GdiSharedHandleTableOffset = si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64 ? 0xF8 : 0x94; DWORD tableCount = 16384; // count of GDI table cells // determine if this process is running on WOW64 BOOL wow; IsWow64Process(GetCurrentProcess(), &wow); // read basic info to get PEB address, we only need the beginning of PEB DWORD pebSize = GdiSharedHandleTableOffset + 8; LPBYTE peb = (LPBYTE)malloc(pebSize); ZeroMemory(peb, pebSize); if (wow) { // we're running as a 32-bit process in a 64-bit process PROCESS_BASIC_INFORMATION_WOW64 pbi; ZeroMemory(&pbi, sizeof(pbi)); // get process information from 64-bit world _NtQueryInformationProcess query = (_NtQueryInformationProcess)GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtWow64QueryInformationProcess64"); err = query(hProcess, 0, &pbi, sizeof(pbi), NULL); if (err != 0) { printf("NtWow64QueryInformationProcess64 failed\n"); CloseHandle(hProcess); return -1; } // read PEB from 64-bit address space _NtWow64ReadVirtualMemory64 read = (_NtWow64ReadVirtualMemory64)GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtWow64ReadVirtualMemory64"); err = read(hProcess, pbi.PebBaseAddress, peb, pebSize, NULL); if (err != 0) { printf("NtWow64ReadVirtualMemory64 PEB failed\n"); CloseHandle(hProcess); return -1; } // get GDI table ptr from PEB GDICELL_WOW64* gdiTable = (GDICELL_WOW64*) * (LPVOID*)(peb + GdiSharedHandleTableOffset); // address in remote process adress space if (gdiTable == NULL) { printf("GDI32.DLL is not loaded in the process\n"); CloseHandle(hProcess); return -1; } free(peb); DWORD tableSize = sizeof(GDICELL_WOW64) * tableCount; // size of GDI table GDICELL_WOW64* table = (GDICELL_WOW64*)malloc(tableSize); // local table copied over to our address space // copy GDI table err = read(hProcess, gdiTable, table, tableSize, NULL); if (err != 0) { printf("NtWow64ReadVirtualMemory64 GdiTable failed\n"); free(table); CloseHandle(hProcess); return -1; } for (DWORD i = 0; i < tableCount; i++) { GDICELL_WOW64 cell = table[i]; if (cell.wProcessId == dwId) { HGDIOBJ gdiHandle = (HGDIOBJ)((cell.wUpper << 16) + i); WORD type = cell.wType & 0x7F; switch (type) { case 1: printf("DC handle:0x%08X\n", gdiHandle); break; case 4: printf("Region handle:0x%08X\n", gdiHandle); break; case 5: printf("Bitmap handle:0x%08X\n", gdiHandle); break; case 8: printf("Palette handle:0x%08X\n", gdiHandle); break; case 10: printf("Font handle:0x%08X\n", gdiHandle); break; case 16: printf("Brush handle:0x%08X\n", gdiHandle); break; case 48: printf("Pen handle:0x%08X\n", gdiHandle); break; default: printf("Unknown type handle:0x%08X\n", gdiHandle); break; } } } free(table); } else { // we're running as a 32-bit process in a 32-bit OS, or as a 64-bit process in a 64-bit OS PROCESS_BASIC_INFORMATION pbi; ZeroMemory(&pbi, sizeof(pbi)); // get process information _NtQueryInformationProcess query = (_NtQueryInformationProcess)GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtQueryInformationProcess"); err = query(hProcess, 0, &pbi, sizeof(pbi), NULL); if (err != 0) { printf("NtQueryInformationProcess failed\n"); CloseHandle(hProcess); return -1; } // read PEB _NtReadVirtualMemory read = (_NtReadVirtualMemory)GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtReadVirtualMemory"); err = read(hProcess, pbi.PebBaseAddress, peb, pebSize, NULL); if (err != 0) { printf("NtReadVirtualMemory PEB failed\n"); CloseHandle(hProcess); return -1; } // get GDI table ptr GDICELL* gdiTable = (GDICELL*) * (LPVOID*)(peb + GdiSharedHandleTableOffset); // address in remote process adress space if (gdiTable == NULL) { printf("GDI32.DLL is not loaded in the process\n"); CloseHandle(hProcess); return -1; } free(peb); DWORD tableSize = sizeof(GDICELL) * tableCount; // size of GDI table GDICELL* table = (GDICELL*)malloc(tableSize); // local table copied over to our address space // read GDI table err = read(hProcess, gdiTable, table, tableSize, NULL); if (err != 0) { printf("NtReadVirtualMemory GdiTable failed\n"); free(table); CloseHandle(hProcess); return -1; } for (DWORD i = 0; i < tableCount; i++) { GDICELL cell = table[i]; if (cell.wProcessId != dwId) continue; HGDIOBJ gdiHandle = (HGDIOBJ)((cell.wUpper << 16) + i); WORD type = cell.wType & 0x7F; switch (type) { case 1: printf("DC handle:0x%08X\n", gdiHandle); break; case 4: printf("Region handle:0x%08X\n", gdiHandle); break; case 5: printf("Bitmap handle:0x%08X\n", gdiHandle); break; case 8: printf("Palette handle:0x%08X\n", gdiHandle); break; case 10: printf("Font handle:0x%08X\n", gdiHandle); break; case 16: printf("Brush handle:0x%08X\n", gdiHandle); break; case 48: printf("Pen handle:0x%08X\n", gdiHandle); break; default: printf("Unknown type handle:0x%08X\n", gdiHandle); break; } } free(table); } CloseHandle(hProcess); }
//Header.h #pragma once #include <Windows.h> // defines a GDI CELL typedef struct { LPVOID pKernelAddress; USHORT wProcessId; USHORT wCount; USHORT wUpper; USHORT wType; LPVOID pUserAddress; } GDICELL; // defines a GDI CELL for WOW64 typedef struct { PVOID64 pKernelAddress; USHORT wProcessId; USHORT wCount; USHORT wUpper; USHORT wType; PVOID64 pUserAddress; } GDICELL_WOW64; // NtQueryInformationProcess for pure 32 and 64-bit processes typedef NTSTATUS(NTAPI* _NtQueryInformationProcess)( IN HANDLE ProcessHandle, ULONG ProcessInformationClass, OUT PVOID ProcessInformation, IN ULONG ProcessInformationLength, OUT PULONG ReturnLength OPTIONAL ); typedef NTSTATUS(NTAPI* _NtReadVirtualMemory)( IN HANDLE ProcessHandle, IN PVOID BaseAddress, OUT PVOID Buffer, IN SIZE_T Size, OUT PSIZE_T NumberOfBytesRead); // NtQueryInformationProcess for 32-bit process on WOW64 typedef NTSTATUS(NTAPI* _NtWow64ReadVirtualMemory64)( IN HANDLE ProcessHandle, IN PVOID64 BaseAddress, OUT PVOID Buffer, IN ULONG64 Size, OUT PULONG64 NumberOfBytesRead); // PROCESS_BASIC_INFORMATION for pure 32 and 64-bit processes typedef struct _PROCESS_BASIC_INFORMATION { PVOID Reserved1; PVOID PebBaseAddress; PVOID Reserved2[2]; ULONG_PTR UniqueProcessId; PVOID Reserved3; } PROCESS_BASIC_INFORMATION; // PROCESS_BASIC_INFORMATION for 32-bit process on WOW64 // The definition is quite funky, as we just lazily doubled sizes to match offsets... typedef struct _PROCESS_BASIC_INFORMATION_WOW64 { PVOID Reserved1[2]; PVOID64 PebBaseAddress; PVOID Reserved2[4]; ULONG_PTR UniqueProcessId[2]; PVOID Reserved3[2]; } PROCESS_BASIC_INFORMATION_WOW64;
Best Regards,
Suarez Zhou
MSDN Community Support
Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.- 已建议为答案 Yong LuMicrosoft contingent staff, Moderator 2019年11月28日 3:32
-
你好,
如果你的问题解决了,请标记有价值的回复为答案,这会对社区其他成员有帮助。
Best Regards,
Suarez Zhou
MSDN Community Support
Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com. -
你好,非常感谢.
我编译不过去.
我把文件加入到VC DOS 支持MFC的新工程中,出现了下列错误.
--------------------Configuration: dosgdi0 - Win32 Debug--------------------
Compiling...
dosgdi0.cpp
D:\temp\dosgdi0\dosgdi0.cpp(51) : error C2059: syntax error : '__stdcall'
D:\temp\dosgdi0\dosgdi0.cpp(57) : error C2091: function returns function
D:\temp\dosgdi0\dosgdi0.cpp(64) : error C2091: function returns function
D:\temp\dosgdi0\dosgdi0.cpp(72) : error C2091: function returns function
D:\temp\dosgdi0\dosgdi0.cpp(79) : error C2146: syntax error : missing ';' before identifier 'UniqueProcessId'
D:\temp\dosgdi0\dosgdi0.cpp(79) : error C2501: 'ULONG_PTR' : missing storage-class or type specifiers
D:\temp\dosgdi0\dosgdi0.cpp(79) : error C2501: 'UniqueProcessId' : missing storage-class or type specifiers
D:\temp\dosgdi0\dosgdi0.cpp(89) : error C2146: syntax error : missing ';' before identifier 'UniqueProcessId'
D:\temp\dosgdi0\dosgdi0.cpp(89) : error C2501: 'ULONG_PTR' : missing storage-class or type specifiers
D:\temp\dosgdi0\dosgdi0.cpp(89) : error C2501: 'UniqueProcessId' : missing storage-class or type specifiers
D:\temp\dosgdi0\dosgdi0.cpp(110) : error C2065: 'GetProcessHandleCount' : undeclared identifier
D:\temp\dosgdi0\dosgdi0.cpp(114) : error C2065: 'GetNativeSystemInfo' : undeclared identifier
D:\temp\dosgdi0\dosgdi0.cpp(118) : error C2065: 'PROCESSOR_ARCHITECTURE_AMD64' : undeclared identifier
D:\temp\dosgdi0\dosgdi0.cpp(123) : error C2065: 'IsWow64Process' : undeclared identifier
D:\temp\dosgdi0\dosgdi0.cpp(137) : error C2065: '_NtQueryInformationProcess' : undeclared identifier
D:\temp\dosgdi0\dosgdi0.cpp(137) : error C2146: syntax error : missing ';' before identifier 'query'
D:\temp\dosgdi0\dosgdi0.cpp(137) : error C2065: 'query' : undeclared identifier
D:\temp\dosgdi0\dosgdi0.cpp(137) : error C2146: syntax error : missing ';' before identifier 'GetProcAddress'
D:\temp\dosgdi0\dosgdi0.cpp(148) : error C2440: '=' : cannot convert from 'int (__cdecl *(__cdecl *)(void))(void *,unsigned long,void *,unsigned long,unsigned long *)' to 'unsigned long'
This conversion requires a reinterpret_cast, a C-style cast or function-style cast
D:\temp\dosgdi0\dosgdi0.cpp(169) : error C2440: '=' : cannot convert from 'int (__cdecl *(__cdecl *)(void))(void *,unsigned long,void *,unsigned long,unsigned long *)' to 'unsigned long'
This conversion requires a reinterpret_cast, a C-style cast or function-style cast
D:\temp\dosgdi0\dosgdi0.cpp(230) : error C2146: syntax error : missing ';' before identifier 'query'
D:\temp\dosgdi0\dosgdi0.cpp(230) : error C2146: syntax error : missing ';' before identifier 'GetProcAddress'
D:\temp\dosgdi0\dosgdi0.cpp(241) : error C2440: '=' : cannot convert from 'int (__cdecl *(__cdecl *)(void))(void *,unsigned long,void *,unsigned long,unsigned long *)' to 'unsigned long'
This conversion requires a reinterpret_cast, a C-style cast or function-style cast
D:\temp\dosgdi0\dosgdi0.cpp(263) : error C2440: '=' : cannot convert from 'int (__cdecl *(__cdecl *)(void))(void *,unsigned long,void *,unsigned long,unsigned long *)' to 'unsigned long'
This conversion requires a reinterpret_cast, a C-style cast or function-style cast
Error executing cl.exe.
dosgdi0.exe - 24 error(s), 0 warning(s)
下面是我的源代码// dosgdi0.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <Windows.h>
#include "dosgdi0.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;
//process.cpp
#include <iostream>
#include <TCHAR.h>
//#include "Header.h"
// defines a GDI CELL
typedef struct
{
LPVOID pKernelAddress;
USHORT wProcessId;
USHORT wCount;
USHORT wUpper;
USHORT wType;
LPVOID pUserAddress;
} GDICELL;
// defines a GDI CELL for WOW64
typedef struct
{
PVOID64 pKernelAddress;
USHORT wProcessId;
USHORT wCount;
USHORT wUpper;
USHORT wType;
PVOID64 pUserAddress;
} GDICELL_WOW64;
// NtQueryInformationProcess for pure 32 and 64-bit processes
typedef NTSTATUS(NTAPI* _NtQueryInformationProcess)(
IN HANDLE ProcessHandle,
ULONG ProcessInformationClass,
OUT PVOID ProcessInformation,
IN ULONG ProcessInformationLength,
OUT PULONG ReturnLength OPTIONAL
);
typedef NTSTATUS(NTAPI* _NtReadVirtualMemory)(
IN HANDLE ProcessHandle,
IN PVOID BaseAddress,
OUT PVOID Buffer,
IN SIZE_T Size,
OUT PSIZE_T NumberOfBytesRead);
// NtQueryInformationProcess for 32-bit process on WOW64
typedef NTSTATUS(NTAPI* _NtWow64ReadVirtualMemory64)(
IN HANDLE ProcessHandle,
IN PVOID64 BaseAddress,
OUT PVOID Buffer,
IN ULONG64 Size,
OUT PULONG64 NumberOfBytesRead);
// PROCESS_BASIC_INFORMATION for pure 32 and 64-bit processes
typedef struct _PROCESS_BASIC_INFORMATION {
PVOID Reserved1;
PVOID PebBaseAddress;
PVOID Reserved2[2];
ULONG_PTR UniqueProcessId;
PVOID Reserved3;
} PROCESS_BASIC_INFORMATION;
// PROCESS_BASIC_INFORMATION for 32-bit process on WOW64
// The definition is quite funky, as we just lazily doubled sizes to match offsets...
typedef struct _PROCESS_BASIC_INFORMATION_WOW64 {
PVOID Reserved1[2];
PVOID64 PebBaseAddress;
PVOID Reserved2[4];
ULONG_PTR UniqueProcessId[2];
PVOID Reserved3[2];
} PROCESS_BASIC_INFORMATION_WOW64;
int f0(DWORD dwId)
{
// get process id
//DWORD dwId = 16888;//process ID
// open the process
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, dwId);
DWORD err = 0;
if (hProcess == NULL)
{
printf("OpenProcess %u failed\n", dwId);
err = GetLastError();
return -1;
}
DWORD a=NULL;
GetProcessHandleCount(hProcess, &a);
std::cout << a<<std::endl;
// determine if 64 or 32-bit processor
SYSTEM_INFO si;
GetNativeSystemInfo(&si);
// NOTE: as this is undocumented, it *may vary* depending on bitness (32/64) and on Windows version.
// use WinDbg "dt ntdll!_PEB" command and search for GdiSharedHandleTable offset to find the truth out
DWORD GdiSharedHandleTableOffset = si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64 ? 0xF8 : 0x94;
DWORD tableCount = 16384; // count of GDI table cells
// determine if this process is running on WOW64
BOOL wow;
IsWow64Process(GetCurrentProcess(), &wow);
// read basic info to get PEB address, we only need the beginning of PEB
DWORD pebSize = GdiSharedHandleTableOffset + 8;
LPBYTE peb = (LPBYTE)malloc(pebSize);
ZeroMemory(peb, pebSize);
if (wow)
{
// we're running as a 32-bit process in a 64-bit process
PROCESS_BASIC_INFORMATION_WOW64 pbi;
ZeroMemory(&pbi, sizeof(pbi));
// get process information from 64-bit world
_NtQueryInformationProcess query = (_NtQueryInformationProcess)GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtWow64QueryInformationProcess64");
err = query(hProcess, 0, &pbi, sizeof(pbi), NULL);
if (err != 0)
{
printf("NtWow64QueryInformationProcess64 failed\n");
CloseHandle(hProcess);
return -1;
}
// read PEB from 64-bit address space
_NtWow64ReadVirtualMemory64 read = (_NtWow64ReadVirtualMemory64)GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtWow64ReadVirtualMemory64");
err = read(hProcess, pbi.PebBaseAddress, peb, pebSize, NULL);
if (err != 0)
{
printf("NtWow64ReadVirtualMemory64 PEB failed\n");
CloseHandle(hProcess);
return -1;
}
// get GDI table ptr from PEB
GDICELL_WOW64* gdiTable = (GDICELL_WOW64*) * (LPVOID*)(peb + GdiSharedHandleTableOffset); // address in remote process adress space
if (gdiTable == NULL)
{
printf("GDI32.DLL is not loaded in the process\n");
CloseHandle(hProcess);
return -1;
}
free(peb);
DWORD tableSize = sizeof(GDICELL_WOW64) * tableCount; // size of GDI table
GDICELL_WOW64* table = (GDICELL_WOW64*)malloc(tableSize); // local table copied over to our address space
// copy GDI table
err = read(hProcess, gdiTable, table, tableSize, NULL);
if (err != 0)
{
printf("NtWow64ReadVirtualMemory64 GdiTable failed\n");
free(table);
CloseHandle(hProcess);
return -1;
}
for (DWORD i = 0; i < tableCount; i++)
{
GDICELL_WOW64 cell = table[i];
if (cell.wProcessId == dwId)
{
HGDIOBJ gdiHandle = (HGDIOBJ)((cell.wUpper << 16) + i);
WORD type = cell.wType & 0x7F;
switch (type)
{
case 1:
printf("DC handle:0x%08X\n", gdiHandle);
break;
case 4:
printf("Region handle:0x%08X\n", gdiHandle);
break;
case 5:
printf("Bitmap handle:0x%08X\n", gdiHandle);
break;
case 8:
printf("Palette handle:0x%08X\n", gdiHandle);
break;
case 10:
printf("Font handle:0x%08X\n", gdiHandle);
break;
case 16:
printf("Brush handle:0x%08X\n", gdiHandle);
break;
case 48:
printf("Pen handle:0x%08X\n", gdiHandle);
break;
default:
printf("Unknown type handle:0x%08X\n", gdiHandle);
break;
}
}
}
free(table);
}
else
{
// we're running as a 32-bit process in a 32-bit OS, or as a 64-bit process in a 64-bit OS
PROCESS_BASIC_INFORMATION pbi;
ZeroMemory(&pbi, sizeof(pbi));
// get process information
_NtQueryInformationProcess query = (_NtQueryInformationProcess)GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtQueryInformationProcess");
err = query(hProcess, 0, &pbi, sizeof(pbi), NULL);
if (err != 0)
{
printf("NtQueryInformationProcess failed\n");
CloseHandle(hProcess);
return -1;
}
// read PEB
_NtReadVirtualMemory read = (_NtReadVirtualMemory)GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtReadVirtualMemory");
err = read(hProcess, pbi.PebBaseAddress, peb, pebSize, NULL);
if (err != 0)
{
printf("NtReadVirtualMemory PEB failed\n");
CloseHandle(hProcess);
return -1;
}
// get GDI table ptr
GDICELL* gdiTable = (GDICELL*) * (LPVOID*)(peb + GdiSharedHandleTableOffset); // address in remote process adress space
if (gdiTable == NULL)
{
printf("GDI32.DLL is not loaded in the process\n");
CloseHandle(hProcess);
return -1;
}
free(peb);
DWORD tableSize = sizeof(GDICELL) * tableCount; // size of GDI table
GDICELL* table = (GDICELL*)malloc(tableSize); // local table copied over to our address space
// read GDI table
err = read(hProcess, gdiTable, table, tableSize, NULL);
if (err != 0)
{
printf("NtReadVirtualMemory GdiTable failed\n");
free(table);
CloseHandle(hProcess);
return -1;
}
for (DWORD i = 0; i < tableCount; i++)
{
GDICELL cell = table[i];
if (cell.wProcessId != dwId)
continue;
HGDIOBJ gdiHandle = (HGDIOBJ)((cell.wUpper << 16) + i);
WORD type = cell.wType & 0x7F;
switch (type)
{
case 1:
printf("DC handle:0x%08X\n", gdiHandle);
break;
case 4:
printf("Region handle:0x%08X\n", gdiHandle);
break;
case 5:
printf("Bitmap handle:0x%08X\n", gdiHandle);
break;
case 8:
printf("Palette handle:0x%08X\n", gdiHandle);
break;
case 10:
printf("Font handle:0x%08X\n", gdiHandle);
break;
case 16:
printf("Brush handle:0x%08X\n", gdiHandle);
break;
case 48:
printf("Pen handle:0x%08X\n", gdiHandle);
break;
default:
printf("Unknown type handle:0x%08X\n", gdiHandle);
break;
}
}
free(table);
}
CloseHandle(hProcess);
}
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.
f0(1);
CString strHello;
strHello.LoadString(IDS_HELLO);
cout << (LPCTSTR)strHello << endl;
}
return nRetCode;
}
stdafx.h代码:
// stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently, but
// are changed infrequently
//
#if !defined(AFX_STDAFX_H__48940212_4EA5_466F_8D02_505DEE438573__INCLUDED_)
#define AFX_STDAFX_H__48940212_4EA5_466F_8D02_505DEE438573__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers
#include <afx.h>
#include <afxwin.h> // MFC core and standard components
#include <afxext.h> // MFC extensions
#include <afxdtctl.h> // MFC support for Internet Explorer 4 Common Controls
#ifndef _AFX_NO_AFXCMN_SUPPORT
#include <afxcmn.h> // MFC support for Windows Common Controls
#endif // _AFX_NO_AFXCMN_SUPPORT
#include <iostream>
// TODO: reference additional headers your program requires here
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_STDAFX_H__48940212_4EA5_466F_8D02_505DEE438573__INCLUDED_)
非常感谢.
谢谢.
- 已编辑 张新波 2019年12月24日 10:04