- 浏览: 408828 次
- 性别:
- 来自: 深圳
文章分类
最新评论
-
wcjagta:
...
dedecms插件开发教程 -
xc2013:
看起来不错 先下载来试试
ECSHOP完全静态化解决方法 -
greemranqq:
你好,我在xp 上做实验,也是JS css带不过来,关于 ro ...
nginx资源定向 css js路径问题 -
hotsmile:
表结构给出来吧,测试的提示说要注册,
中国移动CMPP短信开发平台通讯包 2.8 -
mengdejun:
gang80306176 写道这个插件怎么用和安装普通插件一样 ...
phpcms2008 sp4单网页编辑器插件
atlstdthunk.h
// This is a part of the Active Template Library. // Copyright (C) Microsoft Corporation // All rights reserved. // // This source code is only intended as a supplement to the // Active Template Library Reference and related // electronic documentation provided with the library. // See these sources for detailed information regarding the // Active Template Library product. #ifndef __ATLSTDTHUNK_H__ #define __ATLSTDTHUNK_H__ #pragma once #pragma push_macro("malloc") #undef malloc #pragma push_macro("realloc") #undef realloc #pragma push_macro("free") #undef free #pragma push_macro("new") #undef new #pragma push_macro("HeapAlloc") #undef HeapAlloc #pragma push_macro("HeapFree") #undef HeapFree #pragma push_macro("GetProcessHeap") #undef GetProcessHeap namespace ATL { ///////////////////////////////////////////////////////////////////////////// // Thunks for __stdcall member functions #if defined(_M_IX86) PVOID __stdcall __AllocStdCallThunk(VOID); VOID __stdcall __FreeStdCallThunk(PVOID); #pragma pack(push,1) struct _stdcallthunk { DWORD m_mov; // mov dword ptr [esp+0x4], pThis (esp+0x4 is hWnd) DWORD m_this; // BYTE m_jmp; // jmp WndProc DWORD m_relproc; // relative jmp BOOL Init(DWORD_PTR proc, void* pThis) { m_mov = 0x042444C7; //C7 44 24 0C m_this = PtrToUlong(pThis); m_jmp = 0xe9; m_relproc = DWORD((INT_PTR)proc - ((INT_PTR)this+sizeof(_stdcallthunk))); // write block from data cache and // flush from instruction cache FlushInstructionCache(GetCurrentProcess(), this, sizeof(_stdcallthunk)); return TRUE; } //some thunks will dynamically allocate the memory for the code void* GetCodeAddress() { return this; } void* operator new(size_t) { return __AllocStdCallThunk(); } void operator delete(void* pThunk) { __FreeStdCallThunk(pThunk); } }; #pragma pack(pop) #elif defined(_M_AMD64) PVOID __AllocStdCallThunk(VOID); VOID __FreeStdCallThunk(PVOID); #pragma pack(push,2) struct _stdcallthunk { USHORT RcxMov; // mov rcx, pThis ULONG64 RcxImm; // USHORT RaxMov; // mov rax, target ULONG64 RaxImm; // USHORT RaxJmp; // jmp target BOOL Init(DWORD_PTR proc, void *pThis) { RcxMov = 0xb948; // mov rcx, pThis RcxImm = (ULONG64)pThis; // RaxMov = 0xb848; // mov rax, target RaxImm = (ULONG64)proc; // RaxJmp = 0xe0ff; // jmp rax FlushInstructionCache(GetCurrentProcess(), this, sizeof(_stdcallthunk)); return TRUE; } //some thunks will dynamically allocate the memory for the code void* GetCodeAddress() { return this; } void* operator new(size_t) { return __AllocStdCallThunk(); } void operator delete(void* pThunk) { __FreeStdCallThunk(pThunk); } }; #pragma pack(pop) #elif defined (_M_ALPHA) // For ALPHA we will stick the this pointer into a0, which is where // the HWND is. However, we don't actually need the HWND so this is OK. #pragma pack(push,4) struct _stdcallthunk //this should come out to 20 bytes { DWORD ldah_at; // ldah at, HIWORD(func) DWORD ldah_a0; // ldah a0, HIWORD(this) DWORD lda_at; // lda at, LOWORD(func)(at) DWORD lda_a0; // lda a0, LOWORD(this)(a0) DWORD jmp; // jmp zero,(at),0 BOOL Init(DWORD_PTR proc, void* pThis) { ldah_at = (0x279f0000 | HIWORD(proc)) + (LOWORD(proc)>>15); ldah_a0 = (0x261f0000 | HIWORD(pThis)) + (LOWORD(pThis)>>15); lda_at = 0x239c0000 | LOWORD(proc); lda_a0 = 0x22100000 | LOWORD(pThis); jmp = 0x6bfc0000; // write block from data cache and // flush from instruction cache FlushInstructionCache(GetCurrentProcess(), this, sizeof(_stdcallthunk)); return TRUE; } void* GetCodeAddress() { return this; } }; #pragma pack(pop) #elif defined(_SH3_) #pragma pack(push,4) struct _stdcallthunk // this should come out to 16 bytes { WORD m_mov_r0; // mov.l pFunc,r0 WORD m_mov_r1; // mov.l pThis,r1 WORD m_jmp; // jmp @r0 WORD m_nop; // nop DWORD m_pFunc; DWORD m_pThis; BOOL Init(DWORD_PTR proc, void* pThis) { m_mov_r0 = 0xd001; m_mov_r1 = 0xd402; m_jmp = 0x402b; m_nop = 0x0009; m_pFunc = (DWORD)proc; m_pThis = (DWORD)pThis; // write block from data cache and // flush from instruction cache FlushInstructionCache(GetCurrentProcess(), this, sizeof(_stdcallthunk)); return TRUE; } void* GetCodeAddress() { return this; } }; #pragma pack(pop) #elif defined(_MIPS_) #pragma pack(push,4) struct _stdcallthunk { WORD m_pFuncHi; WORD m_lui_t0; // lui t0,PFUNC_HIGH WORD m_pFuncLo; WORD m_ori_t0; // ori t0,t0,PFUNC_LOW WORD m_pThisHi; WORD m_lui_a0; // lui a0,PTHIS_HIGH DWORD m_jr_t0; // jr t0 WORD m_pThisLo; WORD m_ori_a0; // ori a0,PTHIS_LOW BOOL Init(DWORD_PTR proc, void* pThis) { m_pFuncHi = HIWORD(proc); m_lui_t0 = 0x3c08; m_pFuncLo = LOWORD(proc); m_ori_t0 = 0x3508; m_pThisHi = HIWORD(pThis); m_lui_a0 = 0x3c04; m_jr_t0 = 0x01000008; m_pThisLo = LOWORD(pThis); m_ori_a0 = 0x3484; // write block from data cache and // flush from instruction cache FlushInstructionCache(GetCurrentProcess(), this, sizeof(_stdcallthunk)); return TRUE; } void* GetCodeAddress() { return this; } }; #pragma pack(pop) #elif defined(_ARM_) #pragma pack(push,4) struct _stdcallthunk // this should come out to 16 bytes { DWORD m_mov_r0; // mov r0, pThis DWORD m_mov_pc; // mov pc, pFunc DWORD m_pThis; DWORD m_pFunc; BOOL Init(DWORD_PTR proc, void* pThis) { m_mov_r0 = 0xE59F0000; m_mov_pc = 0xE59FF000; m_pThis = (DWORD)pThis; m_pFunc = (DWORD)proc; // write block from data cache and // flush from instruction cache FlushInstructionCache(GetCurrentProcess(), this, sizeof(_stdcallthunk)); return TRUE; } void* GetCodeAddress() { return this; } }; #pragma pack(pop) #elif defined(_M_IA64) #pragma pack(push,8) extern "C" void _StdCallThunkProcProc(void); struct _FuncDesc { void* pfn; void* gp; }; struct _stdcallthunk { _FuncDesc m_funcdesc; void* m_pFunc; void* m_pThis; BOOL Init(DWORD_PTR proc, void* pThis) { m_funcdesc.pfn = ((_FuncDesc*)(&_StdCallThunkProcProc))->pfn; // Pointer to actual beginning of StdCallThunkProc m_funcdesc.gp = &m_pFunc; m_pFunc = reinterpret_cast< void* >( proc ); m_pThis = pThis; ::FlushInstructionCache( GetCurrentProcess(), this, sizeof( _stdcallthunk ) ); return TRUE; } void* GetCodeAddress() { return( &m_funcdesc ); } }; #pragma pack(pop) //IA64 thunks do not currently use the atlhunk.cpp allocator. #else #error Only ARM, ALPHA, SH3, MIPS, IA64, AMD64 and X86 supported #endif #if defined(_M_IX86) || defined (_M_AMD64) #pragma pack(push,8) class CDynamicStdCallThunk { public: _stdcallthunk *pThunk; CDynamicStdCallThunk() { pThunk = NULL; } ~CDynamicStdCallThunk() { if (pThunk) { delete pThunk; } } BOOL Init(DWORD_PTR proc, void *pThis) { if (pThunk == NULL) { pThunk = new _stdcallthunk; if (pThunk == NULL) { return FALSE; } } return pThunk->Init(proc, pThis); } void* GetCodeAddress() { return pThunk->GetCodeAddress(); } }; #pragma pack(pop) typedef CDynamicStdCallThunk CStdCallThunk; #else typedef _stdcallthunk CStdCallThunk; #endif // _M_IX86 || _M_AMD64 } // namespace ATL #pragma pop_macro("GetProcessHeap") #pragma pop_macro("HeapAlloc") #pragma pop_macro("HeapFree") #pragma pop_macro("new") #pragma pop_macro("free") #pragma pop_macro("realloc") #pragma pop_macro("malloc") #endif // __ATLSTDTHUNK_H__
atlthunk.cpp
/*++ Copyright (c) 1989 Microsoft Corporation Module Name: thunkpool.cpp Abstract: This module contains the support routines for managing a pool of ATL thunk structures. An ATL thunk contains object code that is built on the fly. Normally ATL allocates these structures from standard usermode heap. On platforms supporting "no-execute" operation, however, heap is protected no-execute so this isn't an option. The code here manages a separate "heap" of thunk structures that are allocated from execute-enabled page allocations. Author: Forrest Foltz (forrestf) 16-May-2002 Environment: User mode only. Revision History: --*/ #include <windows.h> #include "atlstdthunk.h" extern "C" { typedef struct _CLIENT_ID { HANDLE UniqueProcess; HANDLE UniqueThread; } CLIENT_ID; typedef CLIENT_ID *PCLIENT_ID; struct _PEB; typedef struct _PEB * PPEB; typedef struct _TEB { NT_TIB NtTib; PVOID EnvironmentPointer; CLIENT_ID ClientId; PVOID ActiveRpcHandle; PVOID ThreadLocalStoragePointer; PPEB ProcessEnvironmentBlock; /* .... Don't need any thing below this*/ } TEB, *PTEB; _inline struct _TEB * Atl_NtCurrentTeb( void ) { __asm mov eax, fs:[0x18] } } #if !defined(_X86_) #error Unsupported platform #endif #if !defined(PAGE_SIZE) #define PAGE_SIZE 4096 #endif #if !defined(DECLSPEC_NOINLINE) #define DECLSPEC_NOINLINE __declspec(noinline) #endif #define ATL_THUNKS_PER_PAGE (PAGE_SIZE / sizeof(ATL_THUNK_ENTRY)) // // Local function prototypes and typedefs // BOOL static __InitializeThunkPool ( VOID ); typedef PSINGLE_LIST_ENTRY (__stdcall *PINTERLOCKED_PUSH_ENTRY_SLIST) ( PSLIST_HEADER ListHead, PSINGLE_LIST_ENTRY ListEntry ); typedef PSINGLE_LIST_ENTRY (__stdcall *PINTERLOCKED_POP_ENTRY_SLIST) ( PSLIST_HEADER ListHead ); // // An ATL thunk structure, used to manage free thunks in the pool // typedef union _ATL_THUNK_ENTRY { SLIST_ENTRY SListEntry; struct ATL::_stdcallthunk Thunk; } ATL_THUNK_ENTRY, *PATL_THUNK_ENTRY; // // Pointer to the process-wide ATL thunk slist. // PSLIST_HEADER __AtlThunkPool = NULL; // // Special value for __AtlThunkPool indicating that the standard // heap should be used for thunk allocation. // #define ATLTHUNK_USE_HEAP_VALUE (PSLIST_HEADER)UlongToPtr(1) #define ATLTHUNK_USE_HEAP() (__AtlThunkPool == ATLTHUNK_USE_HEAP_VALUE) PINTERLOCKED_PUSH_ENTRY_SLIST __AtlInterlockedPushEntrySList = NULL; PINTERLOCKED_POP_ENTRY_SLIST __AtlInterlockedPopEntrySList = NULL; PVOID __AllocStdCallThunk_cmn ( VOID ) /*++ Routine Description: This function is called by ATL to allocate a thunk structure from executable memory. Arguments: None. Return Value: Returns a pointer to a thunk structure on success. Raises an exception on failure. --*/ { PATL_THUNK_ENTRY lastThunkEntry; PATL_THUNK_ENTRY thunkEntry; PVOID thunkPage; // // Perform initialization if this is the first time through. // if (__AtlThunkPool == NULL) { if (__InitializeThunkPool() == FALSE) { goto outOfMemory; } } if (ATLTHUNK_USE_HEAP()) { // // On a non-NX capable platform, use the standard heap. // thunkEntry = (PATL_THUNK_ENTRY)HeapAlloc(GetProcessHeap(), 0, sizeof(ATL::_stdcallthunk)); if (thunkEntry == NULL) { goto outOfMemory; } return thunkEntry; } // // Attempt to pop a thunk structure from the list and return it // thunkEntry = (PATL_THUNK_ENTRY)__AtlInterlockedPopEntrySList(__AtlThunkPool); if (thunkEntry != NULL) { return &thunkEntry->Thunk; } // // The thunk list was empty. Allocate a new page of executable // memory. // thunkPage = (PATL_THUNK_ENTRY)VirtualAlloc(NULL, PAGE_SIZE, MEM_COMMIT, PAGE_EXECUTE_READWRITE); if (thunkPage == NULL) { goto outOfMemory; } // // See if another thread has replenished the pool while we were off // allocating memory. This does not close the window but makes it much // smaller. // // The volatile reference moves the overhead of making the page present // outside of the window. // *(DWORD volatile *)thunkPage; thunkEntry = (PATL_THUNK_ENTRY)__AtlInterlockedPopEntrySList(__AtlThunkPool); if (thunkEntry != NULL) { // // The pool has been replenished. Free the page and use the thunk // entry that we just received. // VirtualFree(thunkPage,0,MEM_RELEASE); return thunkEntry; } // // Create an array of thunk structures on the page and insert all but // the last into the free thunk list. // // The last is kept out of the list and represents the thunk allocation. // thunkEntry = (PATL_THUNK_ENTRY)thunkPage; lastThunkEntry = thunkEntry + ATL_THUNKS_PER_PAGE - 1; do { __AtlInterlockedPushEntrySList(__AtlThunkPool,&thunkEntry->SListEntry); thunkEntry += 1; } while (thunkEntry < lastThunkEntry); return thunkEntry; outOfMemory: return NULL; } VOID __FreeStdCallThunk_cmn ( IN PVOID Thunk ) /*++ Routine Description: This function is called by ATL to release a thunk structure back to the process-wide free thunk pool. Arguments: Thunk - supplies a pointer to a thunk structure that was allocated with __AllocStdCallThunk(). Return Value: None. --*/ { PATL_THUNK_ENTRY thunkEntry; if (ATLTHUNK_USE_HEAP()) { // // On a non-NX capable platform, use the standard heap. // HeapFree(GetProcessHeap(),0,Thunk); } else { // // Simply push the free thunk structure back onto the pool // thunkEntry = (PATL_THUNK_ENTRY)Thunk; __AtlInterlockedPushEntrySList(__AtlThunkPool,&thunkEntry->SListEntry); } } BOOL static DECLSPEC_NOINLINE __InitializeThunkPool ( VOID ) /*++ Routine Description: This function is called on the first invocation of __AllocStdCallThunk(). It retrieves a pointer to the process-wide thunk pool SLIST_HEADER, if one already exists, otherwise this routine supplies an initialized SLIST_HEADER. Arguments: None. Return Value: Returns TRUE if initialization succeeded, FALSE otherwise. --*/ { #define PEB_POINTER_OFFSET 0x34 PSLIST_HEADER *atlThunkPoolPtr; PSLIST_HEADER atlThunkPool; // // On Win64, a per-process ATL thunk "heap" (anchored in the PEB) is always // mantained as an SLIST. // // On X86, such a heap is conditional. If the OS is < 5.1 (Windows XP) then // thunks are allocated/freed from/to the heap, otherwise they are mantained // as they would be on Win64. // // Two reasons for this: // // - We can't guarantee that the SLIST slot in the PEB is available downlevel // - Downlevel OSs may not offer the SLIST functionality // HMODULE kernel32Module; BOOL result; result = IsProcessorFeaturePresent( 12 /*PF_NX_ENABLED*/ ); if (result == FALSE) { // // NX execution is not happening on this machine. // // Indicate that the regular heap should be used by setting // __AtlThunkPool to a special value. // __AtlThunkPool = ATLTHUNK_USE_HEAP_VALUE; return TRUE; } // // We are running on Windows NT5.1 or later. Get the kernel32 pointers to // InterlockedPushEntrySList and InterlockedPopEntrySList. They can't be // simply imported as this library may run in environments without those // routines. // kernel32Module = LoadLibrary( "kernel32.dll" ); if (kernel32Module != NULL) { __AtlInterlockedPushEntrySList = (PINTERLOCKED_PUSH_ENTRY_SLIST) GetProcAddress( kernel32Module, "InterlockedPushEntrySList" ); __AtlInterlockedPopEntrySList = (PINTERLOCKED_POP_ENTRY_SLIST) GetProcAddress( kernel32Module, "InterlockedPopEntrySList" ); } if (__AtlInterlockedPushEntrySList == NULL || __AtlInterlockedPopEntrySList == NULL) { // // If either address could not be retrieved then fail the // initialization. // return FALSE; } atlThunkPoolPtr = (PSLIST_HEADER *)((PCHAR)(Atl_NtCurrentTeb()->ProcessEnvironmentBlock) + PEB_POINTER_OFFSET); atlThunkPool = *atlThunkPoolPtr; if (atlThunkPool == NULL) { // // The pool list has not yet been initialized. Try to use ours. // // Normally we would simply call InitializeSListHead() to initialize // the SLIST_HEADER. However, this creates linkage that conflicts with // modules (such as duser) which also link to ntslist.lib. // // So to avoid that, the SLIST_HEADER is initialized manually. This // code is platform-specific. // atlThunkPool = (PSLIST_HEADER)HeapAlloc( GetProcessHeap(), 0, sizeof(SLIST_HEADER) ); if (atlThunkPool == NULL) { return FALSE; } //InitializeSListHead(atlThunkPool); atlThunkPool->Alignment = 0; if (InterlockedCompareExchangePointer( (PVOID *)atlThunkPoolPtr, atlThunkPool, NULL ) != NULL) { // // Another thread was initializing as well, and won the race. // Free our slist header and use the one that is now there. // HeapFree( GetProcessHeap(), 0, atlThunkPool ); } atlThunkPool = *atlThunkPoolPtr; } __AtlThunkPool = atlThunkPool; return TRUE; } // // Now create the actual routines, one pair within an ATL namespace and one // without. // PVOID __stdcall __AllocStdCallThunk ( VOID ) { return __AllocStdCallThunk_cmn(); } VOID __stdcall __FreeStdCallThunk ( IN PVOID Thunk ) { __FreeStdCallThunk_cmn(Thunk); } namespace ATL { PVOID __stdcall __AllocStdCallThunk ( VOID ) { return __AllocStdCallThunk_cmn(); } VOID __stdcall __FreeStdCallThunk ( IN PVOID Thunk ) { __FreeStdCallThunk_cmn(Thunk); } } // namespace ATL
- thunk.rar (5.7 KB)
- 下载次数: 9
发表评论
-
迅雷下载开放引擎
2011-03-03 13:31 2662*****产品说明*****迅雷下载开放引擎是迅雷开放下载 ... -
c++实现委托
2011-02-28 18:24 1315转载自:http://blog.huang-wei.com/2 ... -
游戏外挂
2011-02-27 21:44 1983网游外挂的制作流程首 ... -
C++反射机制实现
2011-02-27 21:35 862阅读 -
Thunk技术
2011-02-27 21:19 1503Thunk技术,一般认为是 ... -
sqlite3
2011-02-26 19:23 1339void *sqlite3_aggregate_context ... -
mfc双缓冲类封装
2011-02-25 19:23 1659MemDC.h #ifndef _MEMDC_H_ #d ... -
自己写的vc开发框架,基于thunk技术
2011-02-25 19:14 1472QWindow.h #pragma once #defin ... -
C语言读写配置文件
2009-10-11 21:35 2376CException.h /**************** ...
相关推荐
在ATL中,thunk主要分为两种类型:STDMETHODCALLTYPE thunk和C++虚函数调用thunk。STDMETHODCALLTYPE是一种常见的COM调用约定,它与stdcall类似,参数由被调用者清理。而C++虚函数调用thunk则用于处理C++对象的多态...
这个“ATL开发指南源码”显然是一份详细的教程或示例集合,帮助开发者深入理解和实践ATL编程。下面我们将深入探讨ATL的核心概念、主要功能以及如何利用它来创建高效且小巧的COM组件。 ATL起源于1997年,主要是为了...
全面使用VC ATL编程的例子源码(适合使用COM的中高级程序员) 压缩包中包含的文件如下: collection.zip:包含VC Atl开发的集合的源代码(组件程序和测试程序) enum.zip:包含VC Atl开发的枚举器的源代码(组件...
这个“atl开发指南源码”是基于ATL开发指南的第二版,提供了一系列示例代码,帮助开发者深入理解并实践ATL技术。 ATL的主要目标是为COM编程提供轻量级的解决方案,它通过模板技术和元编程技术,减少了编写COM对象所...
ATL(Active Template Library)是Microsoft开发的...通过这个ATL编程基础源码,你可以深入理解ATL如何与COM结合,以及如何利用它来构建Windows GUI应用程序。这是一个很好的起点,可以帮助你进一步掌握ATL和COM编程。
文件系统监控ATL组件源码是一份非常有价值的资源,它为开发者提供了标准的ATL(Active Template Library)实现,用于监视和控制文件系统的活动。ATL是微软开发的一个C++库,它简化了COM(Component Object Model)...
ATL源码学习中关于聚合的支持主要涉及以下几个方面: 1. **IUnknown接口**:所有COM对象都必须实现IUnknown接口,它包含了三个基本方法:QueryInterface、AddRef和Release。在聚合中,聚合对象负责处理IUnknown的...
在本套源码中,我们看到的是使用C#语言与ATL技术结合的例子,运行环境为Visual Studio 2008。 1. ATLShellExtDragAndDropHandler:这是一个实现拖放操作的外壳扩展。在Windows操作系统中,外壳是用户界面的一部分,...
本压缩包"ATL开发指南源码.rar"包含了与某本书配套的源代码示例,旨在帮助读者通过实践来理解和掌握ATL编程技术。 在学习ATL开发时,有几个关键知识点是必不可少的: 1. **COM基础**:理解COM的基本概念,如接口、...
这个压缩包包含了该书前11章的练习源码,对于学习和掌握ATL编程技巧具有很高的价值。 1. ATL基础知识:ATL是一种轻量级的库,主要设计用于快速、高效地创建COM对象。它通过模板技术减少了大量的样板代码,使得...
【标题】"取MAC地址的网页控件OCX(MFC/ATL)源码"涉及到的核心技术是创建一个能够获取计算机硬件物理地址(MAC地址)的ActiveX控件,该控件可以在网页环境中使用。这通常是通过MFC(Microsoft Foundation Classes)...
中文版 清晰 pdf,经典ATL又一升级力作,不容错过。 这是第一部分。因为不能大于60M,所以只能分开为2部分了。 原书名: ATL Internals: Working with ATL 8 (2nd Edition) 作者: (美)Chris Tavares Kirk Fertitta...
这个压缩包包含的"ATL开发指南"和"ATL开发指南源码"是学习和理解ATL编程的重要资源。 一、ATL基础 ATL是一个轻量级的库,它的设计目标是尽可能高效地实现COM接口和对象。ATL通过模板类和宏来简化COM编程,减少了...
ATL ActiveX OpenGL JavaScript 是一个技术组合,用于在网页中集成3D图形渲染,通过JavaScript调用由ATL(Active Template Library)创建的ActiveX控件来实现OpenGL的功能。ATL是微软提供的一种C++库,它简化了COM...
总的来说,“ATL开发指南”是一份全面的参考资料,不仅提供了ATL的理论知识,还配以源码实例,是初学者和有经验的开发者深入研究ATL技术的理想选择。通过研读这份指南,你可以掌握创建高效、小巧COM组件的技能,为你...
在ATL中,我们通常会遇到以下关键概念: 1. **CComObjectRootEx**: 这个模板类是所有ATL COM对象的基础,它负责对象的引用计数和接口管理。通过继承CComObjectRootEx,我们可以得到基本的COM对象行为。 2. **...
这个"ATL开发指南(随书源码)"很可能是一本关于ATL编程技术的书籍配套源代码,帮助读者深入理解并实践ATL编程。 ATL是一个轻量级的库,它提供了一组模板类,用于简化COM对象的创建和实现。在Windows平台上,COM是一...