有关句柄和指针的常用函数

有关句柄和指针的常用函数

1. 如何获取应用程序的 实例句柄? AfxGetInstanceHandle()
    应用程序的 实例句柄保存在CWinAppIm_hInstance 中,可以这么调用 AfxGetInstancdHandle获得句柄.
      Example: HANDLE hInstance=AfxGetInstanceHandle();

2. 如何通过代码获得应用程序主窗口的 指针? AfxGetMainWnd  GetSafeHwnd() AfxGetAppName()  AfxGetThread
   主窗口的 指针保存在CWinThread::m_pMainWnd中,调用 AfxGetMainWnd实现。

  【例】   AfxGetMainWnd() ->ShowWindow(SW_SHOWMAXMIZED); //使程序最大化.

  【例】此例的主窗口是对话框,下面的代码是在另外一个CFileTreeCtrl 类(子窗)中相关函数实现在主对话框(主窗)中的几个 静态文本框(子窗)中显示路径:
            CWnd* m_pCWnd= AfxGetMainWnd(); //得到主窗口指针,通过主窗指针访问其他子窗资源
            //方法一
            m_pCWnd->SetDlgItemText(IDC_STATIC_path,"CWnd* "+m_sCurPath); //在主窗中的子窗(ID:IDC_STATIC_path)中显示字符串
            m_pCWnd->SetDlgItemText(IDC_STATIC_who,"路径显示由FileTreeCtrl类完成:");
            //方法二
            m_pCWnd->SendMessage(STN_CLICKED); //向主窗口发送一个消息,显示任务由主窗完成。
                                               //在主窗的.cpp中有:ON_MESSAGE(STN_CLICKED, OnSTATICpath3)相关描述

           //有的函数必须通过窗口的 句柄 来访问,我们可以使用下面的方法三
           //CWnd::GetSafeHwnd
           //Returns the window handle for a window
           //HWND GetSafeHwnd( ) const;
           HWND m_hWnd_tree =GetSafeHwnd();//【注】此处得到的只是当前窗口(FileTree类)的句柄
           HWND m_hWnd = m_pCWnd->GetSafeHwnd();// 这里才是主窗口的句柄(由主窗指针得到主窗的句柄)

           //BOOL SetWindowText( HWND hWnd, LPCTSTR lpString )
           ::SetWindowText(m_hWnd,"ok2222");//修改主窗口标题
           ::SetDlgItemText(m_hWnd,IDC_STATIC_path2,"HWND: "+m_sCurPath);

  【另】AfxGetThread
      CWinThread* AfxGetThread( );
      Return Value:Pointer to the currently executing thread.

3. 如何在程序中获得其他程序的 图标? AfxGetInstanceHandle()

  HINSTANCE AfxGetInstanceHandle( );
   Return Value
     An HINSTANCE to the current instance of the application. If called from within a DLL linked with the USRDLL version of MFC, an HINSTANCE to the DLL is returned.
   Remarks
     This function allows you to retrieve the instance handle of the current application. AfxGetInstanceHandle always returns the HINSTANCE of your executable file (.EXE) unless it is called from within a DLL linked with the USRDLL version of MFC. In this case, it returns an HINSTANCE to the DLL.

     两种方法:
        (1) SDK函数 SHGetFileInfo 或使用 ExtractIcon获得图标资源的 handle(句柄),
        (2) SDK函数 SHGetFileInfo获得有关文件的 很多信息,如大小图标,属性,类型等.

          Example(1): 在程序窗口左上角显示 NotePad图标.
           void CSampleView: OnDraw(CDC * pDC)
             {
                if( :: SHGetFileInfo(_T("c://pwin95//notepad.exe"),0,
                     &stFileInfo,sizeof(stFileInfo),SHGFI_ICON))
                   {
                     pDC ->DrawIcon(10,10,stFileInfo.hIcon);
                   }
              }

                                                                          
         Example(2):同样功能,Use ExtractIcon Function
          void CSampleView:: OnDraw(CDC *pDC)
              {
                HICON hIcon=:: ExtractIcon(AfxGetInstanceHandle(),_T
                 ("NotePad.exe"),0);

                if (hIcon &&hIcon!=(HICON)-1)
                   pDC->DrawIcon(10,10,hIcon);
              }
   【说明】关于如何得到系统文件的正确路径,象win.ini system32.ini等的路径,各种系统中具体的路径是不一样的。如:
           获得notepad.exe的路径正规上来说用GetWindowsDirectory 函数得到;
           如果是调用 win95下的画笔,应该用访问注册表的方法获得其路径;
           要作成一个比较考究的程序,考虑应该全面点.

   【另】
                HINSTANCE AfxGetResourceHandle( );
                Return Value:An HINSTANCE handle where the default resources of the application are loaded.

4.   有关取得桌面句柄 GetDesktopWindow()

MSDN中的例子:

// 静态函数CWnd:: GetDesktopWindow 返回桌面窗口的指针。下例说明了MFC
void CFrameWnd::BeginModalState ()
{
  //first count all windows that need to be disabled
  UINT nCount=0;
  HWND hWnd=:: GetWindow (:: GetDesktopWindow (), GW_CHILD);
  while (hWnd!=NULL)
  {
    if (:: IsWindowEnabled (hwnd) &&
        CWnd::FromHandlePermanent (hWnd)!=NULL &&
        AfxIsDescendant (pParent->m_hWnd, hWnd) &&
        :: SendMessage (hWnd, WM_DISABLEMODAL, 0, 0) == 0)
    {
       ++nCount;
    }
    hWnd=:: GetWindow (hWnd, GW_HWNDNEXT);
  }
}

//用户的问题:下面程序取的不是同一程序的句柄,但是GetModuleFileName返回的结果一样请问为什莫

HWND ChWnd;//子窗口句柄
HWND hwDesktop=::GetDesktopWindow();//取得桌面句柄
ChWnd=::GetWindow(hwDesktop,GW_CHILD);//取得桌面子句柄
CString csTitle,csClass,csTm,mLookstring;
char szBuffer[255];
while(ChWnd!=NULL)//循环取子句柄的同级句柄
{
    if(::IsWindowVisible(ChWnd))//判断是否为可显示窗口
    {
         ::GetWindowText(ChWnd,csTitle.GetBuffer(255),254);
         ::GetClassName(ChWnd,csClass.GetBuffer(255),254);
         csTitle.ReleaseBuffer();//标题
         csClass.ReleaseBuffer();//类名
         csTm.Format("%08X:",ChWnd);
         if(csTitle=="")
         {
               mLookstring=csTm+csClass;
         }else
         {
               mLookstring=csTm+csTitle;
         }
         //这里的窗口句柄不是同一个程序吧?(问题所在!)可是为什莫结果一样
         HINSTANCE hInstance = (HINSTANCE)::GetWindowLong(ChWnd,DWL_USER);
         ::GetModuleFileName(hInstance, szBuffer, sizeof(szBuffer));
         MessageBox(szBuffer,mLookstring);
    }
    ChWnd=::GetWindow(ChWnd,GW_HWNDNEXT);
}

回答:

问题在于Win32下GetWindowLong(ChWnd,DWL_USER)总是返回当前程序运行的hInstance,所以你得到的文件名总是一个。所以你要用枚举所有"进程的程序名"来获得程序名。
 

=== 再谈句柄于指针的区别

 许多开始学习VC的朋友,最多听说的两个词莫过于指针和句柄了。
 但是,确经常搞不清他们之间的区别。
 首先,句柄是一个窗口的标志,也就是所有从CWND类继承下来的,多有句柄这个成员。
 他能做的,也就是唯一代表一个桌面上的窗口罢了。而指针是一个地址,如果它指向了一个内存中的对象,那么就可以对它进行任意操作了,当然,并不局限于自己的应用程序,你如果能够获得别的应用程序的某个对象的指针,也可以进行操作。然而,如果要获得指针,首先,必须找到那个窗口的句柄,然后用函数FromHandle就可以得到他的指针了。

===  问题1:

如何在自定义的消息中发送一个字符串?例如:
SendMessage(MyWnd,WM_USERDEFINED, 0,0)
如何将字符串Buffer写入wParam或lParam?

 你可以把字符串的地址传递过去,因为地址正好是32位。如:
char s[256];
SendMessage(MyWnd,WM_USERDEFINED, (WPARAM) s,0)
接收方只需要将wParam赋给一个char*就可以了。但此方法只能使用于在一个进程内部传递数据。
 

===  问题2:
1.在VC应用程序框架中,如何加入自己做的类,如何定义这个类的对象,我想在鼠标点击某个菜单项的时候才生成这个对象,做得到吗?(这个类的构造函数是带参数的)。
2.消息发送函数:
  PostMessage(HWND handle,WM_MYMESSAGE,
              WPARAM wParam,LPARAM lParam)
  中:
第一个参数如何获得?
如果我的消息是在自己的应用程序中生成的,想发给应用程序的窗口让它显示某些数据(用TextOut函数),能做到吗?
(也可以说是这样的问题:用Appwizard生成应用程序框架,在生成的类(如CView)中如何得到窗口的句柄,并放在PostMessage函数中。)
3.wParam,lParam,在消息响应函数中如何用?vc是怎样保证这两个数传到函数中的?问题比较多,谢谢!
水平: 刚入门

回答:

1、这个问题是肯定的。你可以使用ClassWizard定义类,也可以手工输入。如果类定义已经在某个文件中,只要使用Project|Add files将文件加入工程就可以了。要想定义类的对象,只要在你的菜单项的相应事件中就可以了。如:
{
...
MyClass myObject("Hello");
myObject.MyMethod();
...
}
2、在你自己的程序中传递消息当然没有任何问题,只要你知道要调用的窗口类是从CWnd继承来的,你就可以使用GetSafeHwnd函数获得窗口句柄。不过一般在自己的同一个程序中有时不愿意使用自定义消息,因为太麻烦。你完全可以给要调用的类添加一个成员函数,只要想显示数据,直接调用这个成员函数不就可以了?何必使用PostMessage呢?一般只有在程序间调用,才愿意使用自定义消息。这时,你通常可以使用FindWindow获得窗口句柄(QA000251 "如何利用FindWindow()函数查找程序")。
3、对于MFC已经定义了消息处理函数的消息,MFC会自动把wParam和lParam映射为更容易使用的方式。如OnMouseMove( UINT nFlags, CPoint point )。对于MFC不能自动处理的函数,如你使用ON_MESSAGE定义消息函数,则MFC会把wParam和lParam原原本本的传递给你的函数,不做任何处理。

===  一个未公开的Win32 API函数:GetTaskmanWindow  ()

    下例中还用到: GetProcAddress    GetParent(hWnd)
                    HMODULE hUser32 = GetModuleHandle("user32");

download

// getaskmanwnd.cpp (Windows NT/2000)
//
// 利用一个未公开的Win32 API函数:GetTaskmanWindow,
// 对Windows的任务栏进行操作(显示/隐藏)。这个函数返回拥有任务栏按钮的窗口句柄。
//
// This example will show you how you can obtain a handle to the
// Windows Taskbar window.
//
// (c)1999 Ashot Oganesyan K, SmartLine, Inc
// mailto:ashot@aha.ru, http://www.protect-me.com, http://www.codepile.com

#i nclude <windows.h>
#i nclude <stdio.h>


// User32!GetTaskmanWindow (NT specific!)
//
// This function returns a handle to the window that ownes the taskbar buttons
//
// HWND GetTaskmanWindow()
//
typedef HWND (WINAPI *PROCGETTASKMANWND)(void);


PROCGETTASKMANWND GetTaskmanWindow;


void main(int argc, char* argv[])
{
if (argc<2)
{
printf("Usage:/n/ngetaskmanwnd.exe S|H/n");
return;
}

HMODULE hUser32 = GetModuleHandle("user32");
if (!hUser32)
return;

GetTaskmanWindow = (PROCGETTASKMANWND)GetProcAddress(hUser32,"GetTaskmanWindow");
if (!GetTaskmanWindow)
return;

HWND hWnd = GetTaskmanWindow();

if (!hWnd)
return;

if (*argv[1]=="H" || *argv[1]=="h")
ShowWindow(GetParent(hWnd),SW_HIDE);
else
ShowWindow(GetParent(hWnd),SW_SHOW);

}

 
<think>我们正在讨论虚幻引擎中的句柄指针。用户之前的问题是关于句柄指针的一般区别,现在特别询问在虚幻引擎中的情况。我需要结合虚幻引擎的特性来回答。 首先回顾一下句柄指针的基本概念: - 指针:直接存储内存地址,用于访问对象。 - 句柄:通常是一个抽象标识(如整数),通过系统(如引擎或操作系统)映射到实际资源。 在虚幻引擎中,这两种机制都存在,但使用场景目的不同。 参考引用内容: 引用[1]提到了UFUNCTION宏,这是用于将C++函数暴露给蓝图系统的。虽然与句柄指针没有直接关系,但说明虚幻引擎有自己的一套抽象机制,其中可能涉及句柄的使用。 引用[2]介绍了纹理空间着色,其中提到了纹理映射,这可能会使用到句柄(例如纹理句柄)来管理纹理资源。 引用[3]提到了多线程环境下的竞争问题,这提醒我们在使用指针时需要注意线程安全,而句柄系统可能由引擎内部管理,提供一定程度的线程安全。 在虚幻引擎中,句柄指针的差异关联: 1. **指针(Pointer)**: - 虚幻引擎中大量使用C++对象,因此指针是直接操作对象的常用方式。 - 例如,`AActor*`指向一个Actor对象。 - 但是,直接使用裸指针存在风险,比如对象被销毁后成为野指针。 2. **句柄(Handle)**: - 虚幻引擎中,句柄常用于管理那些需要安全引用的资源,例如: - **TWeakObjectPtr**:虽然名为指针,但实际上是一种句柄。它是对UObject的弱引用,不会阻止垃圾回收,当对象被销毁时,它会自动置空。内部实现可能使用一个句柄(例如索引到对象表的整数)而不是直接指针。 - **FDelegateHandle**:用于管理委托(delegate)的注册,以便后续可以取消注册。 - **资源句柄**:如纹理、网格等资源,引擎可能使用句柄来引用,而不是直接使用指针,以便于资源管理跨平台安全。 - 句柄的优势在于:当资源被卸载或对象被销毁时,句柄可以安全地检测到,避免访问无效内存。 3. **智能指针**: - 虚幻引擎也有自己的智能指针系统(如TSharedPtr, TSharedRef, TWeakPtr),这些可以看作是指针的封装,提供引用计数自动管理。它们与句柄有相似之处(安全引用),但实现上还是基于指针(只不过加了控制块)。 - 但是,对于UObject(继承自UObject的对象),引擎使用自己的垃圾回收机制,因此通常使用裸指针或TWeakObjectPtr,而不使用智能指针。 4. **关联**: - 句柄内部通常包含一个指向资源管理系统的索引或键,通过这个索引,系统可以找到实际的资源指针。因此,句柄可以看作是指针的间接层。 - 例如,`TWeakObjectPtr`内部存储了一个`FObjectHandle`,它由两部分组成:一个对象索引一个唯一标识符(用来检查对象是否已被替换)。当需要访问对象时,通过全局对象表将句柄解析为指针。 5. **差异**: - **生命周期管理**指针直接指向内存,而句柄由引擎的资源管理系统维护,可以安全地处理对象销毁。 - **安全性**句柄更安全,特别是在多线程环境下(如引用[3]提到的竞争问题)异步加载时,因为句柄可以验证有效性。 - **性能**指针访问更快,因为直接访问内存;句柄需要间接查找(但引擎做了优化,如缓存指针,减少查找开销)。 6. **虚幻引擎中的具体例子**: - **TWeakObjectPtr**:用于安全的弱引用。使用示例: ```cpp TWeakObjectPtr<AMyActor> WeakActorPtr = MyActor; // 在另一个地方使用 if (WeakActorPtr.IsValid()) { AMyActor* ActorPtr = WeakActorPtr.Get(); } ``` - **FTextureResource**:纹理资源可能通过句柄引用,但通常我们使用`UTexture*`。在底层渲染代码中,可能会使用句柄(如RHI纹理句柄)来代表平台相关的纹理资源。 7. **为什么使用句柄**: - 避免野指针:当对象被垃圾回收后,句柄可以自动失效。 - 支持资源热重载:句柄可以保持不变,而实际资源指针改变(重新加载后)。 - 跨模块边界:句柄可以安全地传递,而指针可能因为模块卸载(如动态加载的模块)而无效。 总结: | 特性 | 指针(如AActor*) | 句柄(如TWeakObjectPtr) | |--------------|----------------------------------|-----------------------------------| | 直接内存访问 | 是 | 否(通过Get()获取指针,可能无效) | | 安全性 | 低(可能野指针) | 高(自动失效) | | 性能 | 高(直接访问) | 较低(需要检查有效性) | | 使用场景 | 同一作用域内,对象生命周期确定 | 跨函数、跨线程、不确定生命周期 | | 管理方式 | 无(或手动管理) | 引擎内部资源管理系统 | 在虚幻引擎中,推荐的做法是: - 对于UObject派生类,使用`TWeakObjectPtr`或`TObjectPtr`(UE5引入的增强指针)来避免野指针。 - 对于非UObject对象,可以使用智能指针(如`TSharedPtr`)或句柄。 注意:在UE中,句柄通常不是整数,而是一个类(如`TWeakObjectPtr`),它封装了查找验证逻辑。 相关问题: 1. 在虚幻引擎中,TWeakObjectPtr是如何实现安全引用的? 2. 虚幻引擎的垃圾回收机制如何与句柄交互? 3. 在渲染系统中,句柄是如何管理GPU资源的? 4. 如何避免在多线程环境下使用指针导致的竞争条件? 以上问题可以引导用户进一步理解虚幻引擎中的资源管理。</think>在虚幻引擎(Unreal Engine)中,句柄(Handle)指针(Pointer)都是管理资源的机制,但设计目的实现方式有显著差异。以下是核心区别关联: --- ### **一、核心区别** | **特性** | **指针(Pointer)** | **句柄(Handle)** | |------------------|---------------------------------------------|------------------------------------------------| | **本质** | 直接内存地址(如 `AActor* ActorPtr`) | 资源的抽象标识符(如 `FDelegateHandle`) | | **资源管理** | 需手动管理生命周期(易内存泄漏) | 由引擎自动管理(如垃圾回收/资源池)[^3] | | **安全性** | 高风险(野指针、多线程竞争)[^3] | 高安全(自动失效检测,如 `TWeakObjectPtr`) | | **稳定性** | 对象移动/销毁后失效 | 对象销毁后句柄自动标记无效(`IsValid()`检查) | | **使用场景** | 高频操作(如游戏逻辑循环) | 跨系统边界(如事件委托、异步加载) | | **虚幻实现** | 原生C++指针(`UObject*`) | 引擎封装类型(`FHandle`、`TWeakPtr`等) | > **示例对比** > ```cpp > // 指针:直接访问对象(风险高) > AActor* ActorPtr = GetActor(); > ActorPtr->Destroy(); > > // 句柄:安全访问(引擎管理) > FDelegateHandle EventHandle = OnEvent.Add(...); > if (EventHandle.IsValid()) OnEvent.Remove(EventHandle); // 安全移除 > ``` --- ### **二、核心关联** 1. **间接访问资源** 两者均提供对资源(如 `UObject`、纹理、委托)的间接访问,避免直接暴露底层实现[^1]。 2. **资源标识作用** - 指针:标识对象内存地址(如 `UTexture* TexturePtr`) - 句柄:标识资源在引擎内部的逻辑ID(如渲染资源句柄 `FRHITextureHandle`)[^2] 3. **相互转换机制** 虚幻提供工具类实现安全转换: ```cpp // 将句柄转为指针(需有效性检查) UObject* ObjPtr = WeakObjectPtr.Get(); // 使用 TWeakObjectPtr ``` --- ### **三、虚幻引擎中的典型应用** #### **1. 指针的核心场景** - **游戏对象操作** ```cpp APawn* PlayerPawn = GetPlayerPawn(); // 直接操作Pawn对象 ``` - **性能敏感逻辑** 在 `Tick()` 循环中直接访问组件指针,避免句柄的间接开销。 #### **2. 句柄的核心场景** - **事件委托系统** ```cpp FDelegateHandle Handle = OnActorSpawn.AddLambda([](){...}); // 委托句柄 ``` - **弱引用管理** ```cpp TWeakObjectPtr<AActor> WeakActorPtr = ActorPtr; // 自动失效检测 ``` - **渲染资源管理** 纹理空间着色中,通过句柄解耦资源访问(如 `FRHITextureHandle`)[^2] ![](https://docs.unrealengine.com/5.3/Images/rendering/texture-space-shading/TextureSpaceShadingOverview.webp) *纹理空间着色通过句柄分离可见性采样(屏幕空间)着色(纹理空间)[^2]* - **异步资源加载** ```cpp FStreamableHandle AssetHandle = LoadAssetAsync(...); // 异步加载句柄 ``` --- ### **四、设计选择原因** 1. **句柄的优势** - **线程安全**:避免多线程竞争(如 `Stop()` 与 `Run()` 的竞争)[^3] - **生命周期安全**:对象销毁后句柄自动失效(如 `TWeakPtr`) - **跨系统兼容**:统一管理不同资源(如委托、GPU资源、异步任务) 2. **指针的适用场景** - 需要直接内存操作的高性能场景(如物理模拟) - 对象生命周期完全可控的局部逻辑(如临时计算) --- ### **五、总结** | **维度** | 指针(Pointer) | 句柄(Handle) | |----------------|-------------------------------------|-------------------------------------| | **设计目标** | 最大化性能 | 最大化安全性与稳定性 | | **使用风险** | 内存泄漏/野指针 | API误用(如未移除委托句柄) | | **最佳实践** | 局部作用域、高频逻辑 | 跨系统通信、资源异步操作 | | **演进趋势** | 逐渐被 `TObjectPtr`(UE5)增强 | 仍是引擎核心机制(委托/弱引用) | > **黄金法则**: > - 优先使用句柄管理**跨系统**资源(委托、异步加载、弱引用) > - 仅在**性能关键路径****生命周期可控**时使用裸指针
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值