windows消息机制总结(包括mfc,.Net)

WinForm_初识_事件_消息提示 `WinForms`,作为` .NET Framework` 中用于创建 Windows 应用程序的用户界面的一部分,提供了丰富的`控件`和`组件`,极大地便利了桌面应用程序的开发。本篇文章将深入探讨 WinForms 中的事件驱动机制和消息提示框的使用方法,旨在帮助开发者更好地理解和运用这些基础知识,以提升开发效率和改善程序的用户体验。 阅读详情

无论任何框架怎么包装,其内部消息处理的过程都是类似的,消息处理的过程大概如下:操作系统捕获诸如鼠标单击、键盘按下等消息时会自动识别是那个应用程序的消息【我估计比如鼠标单击,根据当前单击的位置判断是那个应用程序的窗口】,然后把消息放到这个应用程序的进程的消息队列中(每个应用程序都有一个消息队列),每个应用程序中都有一个main函数,此函数中有一个While循环,不断的从消息队列中取出消息(一个结构体的实例),紧接着执行TranslateMessage转换消息(用来把虚拟键消息转换为字符消息),然后紧接着执行DispatchMessage分发消息(DispatchMessage函数会在内部调用操作系统函数判断到底是那个窗体或控件的消息,然后发送消息)【我估计这个在内部的操作系统函数是根据鼠标单击的位置判断是单击的那个窗体或最前面的控件】。注意每个控件内部都有一个消息处理函数WndProc(即一个Switch-Case结构),DispatchMessage会根据情况自动调用对应控件的WndProc消息处理函数。

 

下面是转自网页的部分内容,帮助深入理解:

一、揭开.NET消息循环的神秘面纱,转自:http://www.sudu.cn/info/html/edu/20071025/318789.html

 曾经在Win32平台下奋战的程序员们想必记得,为了弄清楚“消息循环”的概念,度过多少不眠之夜。尽管如今在应用程序代码的编写过程中,我们已经不再需要它,但是深刻理解Windows平台内部的消息流转机制依然必要..

  在早年直接用Win32/Win16 API写程序的时代,消息循环是我们必须搞懂的第一个观念。现在,不管你用是Windows上面的哪一套Application Framework(MFC、VCL、VB、.NET Framework),甚至Unix、Linux、MacOSX上面的Application Framework,都不太容易看到消息循环。事实上,消息循环依然存在,只是被这些ApplicationFramework包装起来,深深地埋藏在某个角落。

  本文章试图唤起大家对于消息循环的回忆,也试图解释消息循环如何被封装进.NET Framework的Windows Forms中。虽然Windows Forms将这一切都藏起来,但是也留下许多空间,让我们可以自行处理Win32的消息。

  传统的Windows 程序

  传统的Windows程序,只利用Win32 API撰写,下面是一个程序范例,为了节省篇幅,我将其中许多程序代码省略:

// 程序进入点

int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,

LPTSTR lpCmdLine, int nCmdShow){
 MSG msg;
 if (!InitInstance (hInstance, nCmdShow)){
  return FALSE;
 }

 // 主消息循环:

 while (GetMessage(&msg, NULL, 0, 0)){
  TranslateMessage(&msg); DispatchMessage(&msg);
 }
 return (int) msg.wParam;
}

// 函数: WndProc(HWND, unsigned, WORD, LONG)
// 用途: 处理主窗口的消息。

LRESULT CALLBACK WndProc(
 HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
  int wmId, wmEvent; PAINTSTRUCT ps;
  HDC hdc;
  switch (message){
   case WM_COMMAND:
    wmId = LOWORD(wParam);
    wmEvent = HIWORD(wParam);
    // 剖析菜单选取项目:
    switch (wmId){
     case IDM_ABOUT:
      DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX,hWnd, (DLGPROC)About);
      break;
     case IDM_EXIT:
      DestroyWindow(hWnd);
      break;
     default:
      return DefWindowProc(hWnd, message,wParam,lParam);
    }
    break;
   case WM_PAINT:
    hdc = BeginPaint(hWnd, &ps);

    // TODO: 在此加入任何绘图程序代码...
    EndPaint(hWnd, &ps);
    break;

   case WM_DESTROY:
    PostQuitMessage(0);
    break;
   default:
    return DefWindowProc(hWnd, message,wParam, lParam);
  }
  return 0;
 }

 // [关于] 方块的消息处理例程。

 LRESULT CALLBACK About(HWND hDlg, UINT message,

 WPARAM wParam, LPARAM lParam){
  switch (message){
   case WM_INITDIALOG:
    return TRUE;
   case WM_COMMAND:
    if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL){
     EndDialog(hDlg, LOWORD(wParam));
     return TRUE;
    }
    break;
   }
   return FALSE;
  }


  1、从_tWinMain内,程序进入主消息循环;

  2、消息循环从消息队列(Message Queue)中取得一个消息(透过调用GetMessage())。每个执行中的程序都有一个属于自己的消息队列;

  3、消息循环根据消息内容来决定消息应该送给哪个Windows Procedure(WndProc),.. 这就称为消息分发(Message Dispatch)。通常“每一种”窗口或控件(control)都有一个Windows Procedure,来处理该种窗口/控件的行为;

  4、Windows Procedure根据消息内容来决定应该调用哪个函数(利用Switch/Case语法);..

  5、Windows Procedure处理完,控制权回到消息循环。继续进行2、3、4、5的动作;

  6、当消息队列为空的时候,GetMessage()无法取得任何消息,就会进入Idle(空闲)状态,进入睡眠状态(而不是Busy Waiting)。当消息队列不再为空的时候,程序会自动醒过来,继续进行2、3、4、5的动作;

  7、当取得的消息是WM_QUIT,GetMessage()就会得到0的返回值,因而离开消息循环,程序结束。程序会利用调用PostQuitMessage()来将WM_QUIT放置进消息队列中,来造成稍后结束,而不会直接贸然跳离开循环来结束。

  虽名为队列(queue),.. 但是消息队列中的消息并非总是先进先出(First In First Out,FIFO),有一些特例:

  . 只要消息队列中有WM_QUIT ,就会先取出WM_QUIT,导致程序结束。

  . 只有在没有其它消息的时候,WM_PAINT 和WM_TIMER才会被取出。且多个WM_PAINT可能会被合并成一个,WM_TIMER也是如此。

  . 利用TranslateMessage()来处理消息,可能会造成新消息的产生。例如:TranslateMessage()可以辨识出WM_KEYDOWN(按键按下)加上WM_KEYUP(按键放开)就产生WM_CHAR(字符输入)。

  何谓消息

  鼠标移动、按键被按下、窗口被关闭.,这些都会产生消息。在Windows操作系统中,消息是以下面的数据结构存在的(定义在WinUser.h档案中):..

typedef struct tagMSG {
 HWND hwnd;
 UINT message;
 WPARAM wParam;
 LPARAM lParam;
 DWORD time;
 POINT pt;
} MSG;


  消息内有六个信息,分别是:

  . hwnd:窗口/控件的唯一hwnd的编号。消息循环会根据此信息,将消息送到正确目标。

  . message:Windows预先定义的消息种类的ID。

  . wParam 与lParam:有些message本身需要携带更多的信息,这些信息就放在wParam与lParam中。

  . time与pt:消息发生当时的时间与鼠标位置。

  .NET Framework如何封装消息循环

  .NET Framework的Windows Forms将消息循环封装起来,以方便我们使用。本节中所提到的类(class),都是属于System.Windows.Forms名字空间(namespace)。

  简单归纳如下:消息循环被封装进了Application类的Run()静态方法中;Windows Procedure被封装进了NativeWindow 与Control 类中;个别的消息处理动作被封装进Control 类的OnXyz()(例如OnPaint())。我们可以覆盖(override)OnXyz(),来提供我们自己的程序。也可以利用.NET的事件(event)机制,在Xyz事件上,加入我们的事件处理函数(Event Handler)。Control类的OnXyz()会主动调用Xyz 事件的处理函数。

  请注意,因为Xyz 的事件处理函数是由Control类的OnXyz()方法所调用的,所以当你覆写OnXyz()方法时,不要忘了调用Control类的OnXyz()(除非你有特殊需求),否则Xyz事件处理函数将会没有作用。只要调用base.OnXyz(),就可以调用到Control类的OnXyz()方法,如下所示:

protected override void OnPaint(PaintEventArgs e){
 base.OnPaint (e);// TODO: 加入 Form1.OnPaint 实作
}


  我们可以利用覆写Control类的OnXyz(),来决定该消息发生时要做些什么。同理,我们甚至可以覆写Control与NativeWindow类的WndProc(),来定义Windows Procedure。

  再次提醒你,因为OnXyz()系列方法是由Control类的WndProc()所调用的,所以当你覆写WndProc()时,不要忘了调用Control类的WndProc()(除非你有特殊需求),否则OnXyz()系列方法(以及Xyz事件处理函数)将会没有作用。只要调用base.WndProc(),就可以调用到Control类的WndProc(),如下所示:

protected override void WndProc(ref Message m){
 base.WndProc (ref m);//TODO: 加入Form1.WndProc 实作
}


  你可能也注意到了,WndProc()需要一个Message类的参数,这正是MSG被封装成.NET版本的结果。

  一个Windows Forms的范例

  为了让读者更加了解实际的状况,我用下面的实例范例作说明:

namespace WindowsApplication1{
 /// Form1 的摘要描述。
 public class Form1 : Form{
  /// 设计工具所需的变数。
  private Container components = null;
  public Form1(){
   AutoScaleBaseSize = new Size(5, 15);
   ClientSize = new Size(2Array2, 266);
   Name = "Form1";
   Text = "Form1";
   Paint += new PaintEventHandler(this.Form1_Paint);
   Paint += new PaintEventHandler(this.Form1_Paint2);
  }
  /// 应用程序的主进入点。
  [STAThread]
  static void Main(){
   Application.Run(new Form1());
  }
  protected override void OnPaint(PaintEventArgs e){
   base.OnPaint (e); // 2
  }
  private void Form1_Paint(object sender, PaintEventArgs e){
   // 3
  }
  private void Form1_Paint2(object sender, PaintEventArgs e){
   // 4
  }
  protected override void WndProc(ref Message m){
   base.WndProc (ref m); // 1
  }
 }
}


  1、在Main()中,利用Application.Run()来将Form1窗口显示出来,并进入消息循环。程序的执行过程中,Application.Run()一直未结束。

  2、OS在此Process的消息队列内放进一个WM_PAINT消息,好让窗口被显示出来。

  3、WM_PAINT被Application.Run()内的消息循环取出来,分发到WndProc()。由于多态(Polymorphism)的因素,此次调用(invoke)到的WndProc()是属于Form1的WndProc(),也就是上述程序中批注(comment)1的地方,而不是调用到 Control.WndProc()。

  4、在Form1.WndProc()的最后,有调用base.WndProc(),这实际上调用到Control.WndProc()。

  5、Control.WndProc()从Message参数中得知此消息是WM_PAINT,于是调用OnPaint()。由于多态的因素,此次调用到的OnPaint()是属于Form1的OnPaint(),也就是上述程序中批注2的地方,而不是调用到 Control.OnPaint()。

  6、在Form1.OnPaint()的最后,有调用base.OnPaint(),这实际上调用到Control.OnPaint()。

  7、我们曾经在Form1的构造函数(constructor)中将Form1_Paint()与Form1_Paint2()登记成为Paint事件处理函数
(Event Handler)。Control.OnPaint()会去依序去调用这两个函数,也就是上述程序中批注3与4的地方。

  干嘛知道这么多?拜工具之赐,现在的程序员很幸福,可以在糊里胡涂的情况下写出程序来。不过这样的程序员恐怕竞争力不强,毕竟将组件(component)拖放(drag and drop)到画面上,再设定组件属性的工作,称不上有太大的难度。只有深入了解内部原理,才能让自己对技术融会贯通,也才能让程序员之路走得更稳健、更长久。

 

 

二、GetMessage和PeekMessage的联系与区别以及用法 TranslateMessage与DispatchMessage

转自:http://blog.sina.com.cn/s/blog_8a7012cf010151cr.html

联系:

在Windows的内部,GetMessage和PeekMessage执行着相同的代码,Peekmessage和Getmessage都是向系统的消息队列中取得消息,并将其放置在指定的结构。

区别:
PeekMessage: 有消息时返回TRUE,没有消息返回FALSE    
GetMessage:有消息时且消息不为 WM_QUIT时返回TRUE,如果有消息且为WM_QUIT则返回FALSE,没有消息时不返回。
GetMessage : 取得消息后,删除除WM_PAINT消息以外的消息。
PeekMessage:取得消息后,根据 wRemoveMsg参数判断是否删除消息。PM_REMOVE则删除,PM_NOREMOVE不删除。
The PeekMessage function normally does not remove WM_PAINT messages from the queue. WM_PAINT messages remain in the queue until they are processed. However, if a WM_PAINT message has a null update region, PeekMessage does remove it from the queue.
不能用PeekMessage从消息队列中删除WM_PAINT消息,从队列中删除WM_PAINT消息可以令窗口显示区域的失效区域变得有效(刷新窗口),如果队列中包含 WM_PAINT消息程序就会一直while循环了。

用法:
原型:BOOL GetMessage(
  LPMSG lpMsg,         // address of structure with message
  HWND hWnd,           // handle of window
  UINT wMsgFilterMin,   // first message
  UINT wMsgFilterMax   // last message
);
while ( GetMessage(&msg, NULL, 0, 0))        
{        
    TranslateMessage (&msg);        
    DispatchMessage (&msg);        
}      
return msg.wParam;

原型:
BOOL PeekMessage(
  LPMSG lpMsg,         // pointer to structure for message
  HWND hWnd,           // handle to window
  UINT wMsgFilterMin,   // first message
  UINT wMsgFilterMax,   // last message
  UINT wRemoveMsg       // removal flags
);
while (TRUE)
{        
    if ( PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))        
    {        
            if (msg.message == WM_QUIT)        
                    break;        
            TranslateMessage (&msg);        
            DispatchMessage (&msg);        
    }        
    else        
    {        
            // 处理空闲任务        
    }        
}        
return msg.wParam;

TranslateMessage(转换消息):
用来把虚拟键消息转换为字符消息。由于Windows对所有键盘编码都是采用虚拟键的定义,这样当按键按下时,并不得字符消息,需要键盘映射转换为字符的消息。
TranslateMessage函数用于将虚拟键消息转换为字符消息。字符消息被投递到调用线程的消息队列中,当下一次调用GetMessage函数时被取出。当我们敲击键盘上的某个字符键时,系统将产生WM_KEYDOWN和WM_KEYUP消息。这两个消息的附加参数(wParam和lParam)包含的是虚拟键代码和扫描码等信息,而我们在程序中往往需要得到某个字符的ASCII码,TranslateMessage这个函数就可以将WM_KEYDOWN和WM_ KEYUP消息的组合转换为一条WM_CHAR消息(该消息的wParam附加参数包含了字符的ASCII码),并将转换后的新消息投递到调用线程的消息队列中。注意,TranslateMessage函数并不会修改原有的消息,它只是产生新的消息并投递到消息队列中。
也就是说TranslateMessage会发现消息里是否有字符键的消息,如果有字符键的消息,就会产生WM_CHAR消息,如果没有就会产生什么消息。

DispatchMessage(分派消息):
把 TranslateMessage转换的消息 发送到窗口的消息处理函数,此函数在窗口注册时已经指定。

 

 

 

 

VC++消息映射机制深度解析:从Windows消息泵到MFC实战避坑指南 消息驱动架构是Windows GUI编程的核心基础,其原理基于操作系统生成消息、应用程序通过消息泵循环获取并分派消息到窗口过程。这一机制构成了所有Windows桌面应用的运行基石,其技术价值在于实现用户输入与程序逻辑的解耦,支撑了响应式交互体验。在MFC框架中,消息映射表通过静态数据结构将消息ID与处理函数关联,替代了原始的switch-case处理方式,大幅提升了开发效率。然而,在维护遗留系统或进行混合开发时,开发者常面临消息路由失效、线程安全等工程挑战。本文聚焦VC++消息映射,深入剖析CWnd::Wi 阅读详情

相关推荐

Visual C++ 6.0编程实战:从MFC消息机制到Windows桌面开发核心原理

Windows桌面开发的核心在于理解底层消息循环与图形设备接口(GDI)等基础概念。消息映射机制作为Windows程序的事件驱动基础,通过将用户操作转化为系统消息并分发给对应处理函数,构成了GUI应用的交互骨架。GDI绘图原理则提供了图形渲染的底层支持,涉及设备上下文、坐标变换等关键技术。这些原理不仅是MFC框架的基石,更是现代Qt、WPF等GUI框架共同依赖的技术内核。掌握消息循环与GDI编程,能帮助开发者深入理解Windows桌面应用的运行机制,为维护遗留系统和学习现代框架打下坚实基础。本文通过Visu

long_yu2的专栏 375

winform通过消息机制触发事件

上述会存在哪些潜在的问题。

nbspzs的专栏 759

深入理解MFC:微软基础类库详解

MFC作为微软早期推出的C++类库,曾在Windows应用程序开发中占据重要地位。它通过对Windows API的封装和面向对象设计,为开发者提供了一种高效构建Windows桌面应用的方式。尽管如今有了许多更新、更现代的开发工具和框架,MFC依然在维护大型遗留系统或特定领域应用程序开发中具有不可忽视的价值。

weixin_73414031的博客 2449

windows程序消息机制(Winform界面更新有关)

当然在某些需要cpu最大限度运动的程序里面就可以使用另外的方法,例如某些3d游戏或者及时战略游戏中,一般会使用PeekMessage()这个方法,它不会被windows阻塞,从而保证整个游戏的流畅和比较高的帧速。因此,一个线程可以向另一个线程的消息队列发送消息从而告诉对方做什么,这样就完成了线程间的通信。否则,在后台线程和主截面线程共享某些状态数据的情况下,如果不同步调用,而是各自继续执行的话,可能会造成执行序列上的问题,虽然不发生死锁,但是会出现不可预料的显示结果或者数据处理错误。然后就是消息的参数。

weixin_53370274的博客 1038

MFC

01章 用向导创建文档窗口 MFC教程是小雅最怕写的内容,除了水平问题之外,还有一点就是,MFC将许多程序封装起来,使众多程序员在编程时,即使编出了程序,也不知究竟为什么这样就可以了。这一现象使小雅想到当今的Java程序员,许多人在开发外包项目时,因为整个Frame

2376

MFC Windows 程序设计[140]之多样消息对话框属性页(附源码)

MFC是微软公司提供的一个类库(class libraries),用以减少应用程序开发人员的工作量。其中包含大量Windows句柄封装类和很多Windows的内建控件和组件的封装类。有很多初学MFC的小伙伴们都觉得MFC比较难学,看书吧,看了就忘了,网上的一些教程又是写的含糊不清,故而学习起来很吃力...... 故此,本专栏亲自研究,实践,由易到难,层层深入,将调试过程中所遭所遇进行详细讲解,注意事项进行一一列举,希望能够帮助到各位初学MFC的小伙伴,避免走弯路,费时费力。......

hnjzfwy的博客 223

(转)c#消息处理

一、消息概述 Windows下应用程序的执行是通过消息驱动的。消息是整个应用程序的工作引擎,我们需要理解掌握我们使用的编程语言是如何封装消息的原理。 1 什么是消息(Message) 消息就是通知和命令。在.NET框架类库中的System.Windows.Forms命名空间中微软采用面对对象的方式重新定义了Message。新的消息(Message)结构的公共部分属性基...

anivdqdt84098的博客 632

MFC Windows程序设计(第二版)中文版实战指南

简介:《MFC Windows程序设计(第二版)中文版》系统讲解了基于C++的Microsoft Foundation Classes(MFC)库在Windows平台下的应用开发。本书全面涵盖MFC核心架构与组件,包括框架类、文档/视图模型、对话框、控件、GDI图形绘制、数据库访问及网络编程等内容,结合丰富实例帮助读者掌握MFC编程精髓。每个章节以PDF形式独立呈现,附带可运行源码,便于学习与实践。适合从入门到进阶的开发者深入理解MFC机制,提升Windows桌面应用程序开发能力。

weixin_42593130的博客 1084

【C#】Windows程序消息机制

1、Windows程序消息机制使用消息队列实现。 (1)、UI线程为主线程,用于管理整个窗体以及子控件的运行。 (2)、窗体上的所有消息是消息队列的主要来源。 (3)、PeekMessage、GetMessage用于查看应用程序消息队列,有消息时将队列中的消息派发出去。 GetMessage只有在消息队列中有消息时返回,队列中无消息GetMessage就会一直等,直至下一个消息出现时才返回。在等的这段时间,应用程序不能执行任何指令。即:当队列为空,GetMessage会被阻塞,使得while循环停止,防止某

YingVickyCao 1764

深入解析MFC创建窗口实例的完整流程

MFC(Microsoft Foundation Classes)是一组封装了Windows API的C++类库,旨在简化Windows应用程序的开发流程。通过面向对象的方式,MFC提供了对窗口、消息处理、图形界面控件等核心功能的封装,使开发者能够以更高层次的抽象进行编程。在现代Windows桌面应用开发中,尽管有.NET Framework和UWP等新兴框架,但MFC因其性能优越、与原生API高度集成,仍广泛应用于企业级软件和遗留系统的维护与升级中。

weixin_42581846的博客 984

MFC类库全解(中文版)

MFC(Microsoft Foundation Classes)是微软公司提供的一套C++类库,目的是简化Windows平台下应用程序的开发。通过封装Windows API,MFC提供了一套更为直观、易用的面向对象编程接口。在某些高级应用场景中,开发者可能需要创建完全自定义的窗口类。通过继承CWnd类,可以定义满足特定功能需求的窗口控件。例如,创建一个带有特殊绘图能力的窗口类,可以如下实现:public:// 设备上下文// 在这里添加绘图代码...// 其他成员函数...在。

weixin_42405592的博客 825

第五章Windows Message Mapping Windows 消息映射(上)

第五章 Windows Message Mapping Windows 消息映射In Chapter 3, you saw how the MFC library application framework calls the view class’s virtual OnDraw function. In the online help for the MFC library, wher

GodSun_的专栏 3051

探索Windows系统字体:MFC框架实现

在操作系统中,字体不仅承载了文本的可视表达,也是用户交互体验的关键元素。获取系统字体资源对开发图形用户界面(GUI)至关重要,它允许程序准确地显示和操作字体信息,增强应用程序的可读性和美观性。Microsoft Foundation Classes (MFC) 是一个C++类库,旨在简化基于Windows的软件开发。最初于1992年随Visual C++ 1.0推出,MFC为Windows开发者提供了一种更加面向对象的方式来编写Windows应用程序。

weixin_33256096的博客 785

MFC消息机制深度解密:从WM_CLOSE到自定义消息的完整指南(VS2015环境)

本文深入解析了在VS2015环境下进行MFC项目开发时,Windows消息机制的核心原理与应用。详细剖析了从WM_CLOSE、WM_DESTROY等关键窗口生命周期消息的处理,到SendMessage与PostMessage的同步/异步通信差异,并提供了自定义消息从定义、映射到实现跨线程通信的完整实战指南,帮助开发者构建更健壮、响应精准的桌面应用程序。

soda5的博客 818

C#消息循环与响应机制

你可能通过看书知道了MFC的消息循环和传递机制,但是C#的事件和MFC的消息机制有什么区别和共同点呢?本文档揭示了winform程序的内部消息机制.

c# 使用windows消息队列机制

c#使用windows消息队列实现进程通讯,本代码只是范例代码,需要实现安装windows的消息队列,然后在“专用队列”中建立一个名为“liuq”的消息队列。具体怎么安装消息队列,怎么建立消息队列这里不赘述。

windows消息队列C语言,windows 消息队列

许多朋友都不会使用MSDN LIBRARY(虽然MSDN 跟 MSDN LIBRARY 不是一回事,但是下文中还是简写为MSDN),其实它是非常重要的东西。其实所有的说明都可以在MSDN中查到。环境:VS2008 + SP1补丁 MSDN LIBRARY 2008 + SP1 补丁打开 这个版本的 MSDN 后,可以看到如图的界面在最左下角,我们可以看到 Contents 、Index 、...

weixin_29524677的博客 1442

C# Message (消息机制)

Windows下应用程序的执行是通过消息驱动的。消息是整个应用程序的工作引擎,我们需要理解掌握我们使用的编程语言是如何封装消息的原理。

上一篇: c++基础---C++宏定义详解
下一篇: c++高级---关于C++指针大小和Void*使用的总结
HNFXS985
博客等级 码龄14年 219粉丝 150原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值