VS2017集成FastReport.Net并拿模板保存及数据库

对开发同实践分离之考虑,设计一个通用的表设计窗体显得越发重大(下图为祈求一律):

          if(FAILED(lock.Lock()))

征:isSaveAs为true时,表明点击的是外存为按钮。

m_dwMainThreadID负责保存该应用程序的主线程ID

//初始化报表
        private void InitializeReport(string RptMode)
        {
            DataSet Ds = mymeans.GetDataSet("SELECT RPT_NO,RPT_NAME,FILEDATA FROM AT_REPORT WHERE FORMID='" + FormID + "' AND RPT_NO='" + RptNo + "'", "REPORT");
            RptTable = Ds.Tables[0];
            RptRow = RptTable.Rows[0];
            RegisterDesignerEvents();
            DesignReport(RptMode);
        }

              CappModule 类—应用程序基础类

8、保存委托函数:

{

证明:tvwRight是图一律右侧边Treeview的称谓。

              bRet

m_pSettingChangeNotify->Add(hWnd);

 

         
lock.Unlock();

 

         return bRet;

     }

 

BOOL
RemoveSettingChangeNotify(HWND hWnd)

     {

         
CStaticDataInitCriticalSectionLock lock;

          if(FAILED(lock.Lock()))

         {

             
ATLTRACE2(atlTraceUI, 0, _T(“ERROR : Unable to lock critical section in
CAppModule::RemoveSettingChangeNotify.\n”));

             
ATLASSERT(FALSE);

              return FALSE;

         }

 

         BOOL bRet =
FALSE;

          if(m_pSettingChangeNotify != NULL)

              bRet =
m_pSettingChangeNotify->Remove(hWnd);

 

         
lock.Unlock();

 

         return bRet;

     }

 

     现
在返刚才提到的Run()函数,里面最好初步便定义了一个CmessageLoop循环对象,然后经过_Module对象的AddMessageLoop
成员函数加入到循环队列里面,直到_Module调用了RemoveMessageLoop移除循环队列,程序才了循环,返回到WinMain函数。

    
在此地还有一个比较重要之类似,那就算是CMessageLoop,是外保持了网的音,维持了程序的生命周期。那么下面我们来探视是类似的定义和求实的落实方式。

CmessageLoop包含了之类一些分子函数和成员变量

成员变量

//处理消息

    
ATL::CSimpleArray<CMessageFilter*> m_aMsgFilter;

     //处理空闲句柄

    
ATL::CSimpleArray<CIdleHandler*> m_aIdleHandler;

     //Win32API信息结构

     MSG
m_msg;

 

    
成员函数(用红标志的函数是虚函数)

AddMessageFilter        
加入一长长的信息过滤

RemoveMessageFilter     
移除了同长条信息过滤

AddIdleHandler      
加入一个闲句柄

RemoveIdleHandler       
 移有一个空余词柄

AddUpdateUI             
为了配合老的ATL而计划之

RemoveUpdateUI          
为了配合老的ATL而设计之

IsIdleMessage           
过滤一些照WM_MOUSEMOVE之类的音讯

Run                     
音循环。关键部分!!!

PreTranslateMessage     
信息过滤

OnIdle                  
空闲处理

 

重新此自己无备对每个函数都进展详细的剖析,主要分析中心之函数Run,CmessageLoop由它来保持正系统的音讯循环。

函数如下:

int Run()

     {

         //空闲?

         BOOL bDoIdle
= TRUE;

         //空闲计数器

         int nIdleCount = 0;

         //返回标志

         BOOL
bRet;

 

         //开始消息循环了哦!!!

          for(;;)

         {

 

              //当bDoIdle为TRUE,并且不可知由信队列中取出消息了,那么开空闲操作了!

              //PM_NOREMOVE:再PeekMessage函数处理后不以消息从队列里移除

              while(bDoIdle && !::PeekMessage(&m_msg,
NULL, 0, 0, PM_NOREMOVE))

             
{

                  
if(!OnIdle(nIdleCount++))

                  
     bDoIdle = FALSE;

             
}

             

              //从此时此刻线程获取一个音

              //返回-1意味出现一个误

              //返回
0表示提交了一个WM_QUIT,程序将退出

              //成功获得一个音讯,返回不等于0的价

              bRet =
::GetMessage(&m_msg, NULL, 0, 0);

 

              if(bRet == -1)

             
{

                  
ATLTRACE2(atlTraceUI, 0, _T(“::GetMessage returned -1
(error)\n”));

                  
continue;   // error, don’t process

             
}

              else if(!bRet)

             
{

                  
ATLTRACE2(atlTraceUI, 0, _T(“CMessageLoop::Run – exiting\n”));

                  
break;   // WM_QUIT, exit message loop

             
}

 

              //如果熟悉下c语言来写Win32之程序员会发现,原来WinMain中的哪位处理消息循环的说话放到这里来了!!!

              if(!PreTranslateMessage(&m_msg))

             
{

                  
//translates virtual-key messages into
character messages.

                  
::TranslateMessage(&m_msg);

                  
//dispatches a message to a window
procedure

                  
::DispatchMessage(&m_msg);

             
}

             

              //判断是否为空消息?

             
//排除WM_MOUSEMOVE WM_NCMOUSEMOVE WM_SYSTIMER消息

              if(IsIdleMessage(&m_msg))

             
{

                  
bDoIdle = TRUE;

                  
nIdleCount = 0;

             
}

         }

 

         return (int)m_msg.wParam;

     }

上述就是是本着ATLAPP.H中之几只比根本的类的解析,还时有发生任何几单近乎的分析自己用在以后的章被

(待续。。。)

5、注册事件:

          if(FAILED(lock.Lock()))

public string FormID { get; set; } = "PRDT"; //单据ID
private string RptNo, RptName; //报表编号、名称
private DataTable RptTable; //数据表
private DataRow RptRow; //数据行(报表数据源)
private bool isSaveAs = false; //另存为

     if(FAILED(lock.Lock()))

开发条件:

              AtlCreateBoldFont()   产生一个粗体字体

注:mymeans.GetDataSet是温馨写的近乎方式,主要是以SQL生成DataSet。

                  
bRet = FALSE;

  IV、预览与打印。已规划好之模版不待每次都进设计界面,直接预览或打印即可。

             
_ATL_EMPTY_DLGTEMPLATE templ;

 9、报表模板保存:

}

2、定义属性与变量:

 

7、另存为对话框:

 

  1.2代码引用。

    
CStaticDataInitCriticalSectionLock lock;

//菜单事件注册
        private void RegisterDesignerEvents()
        {
            Config.DesignerSettings.CustomSaveDialog += new OpenSaveDialogEventHandler(DesignerSettings_CustomSaveDialog);
            Config.DesignerSettings.CustomSaveReport += new OpenSaveReportEventHandler(DesignerSettings_CustomSaveReport);
        }

              
TranslateMessage(&msg);

  I、报表设计窗体支持具有单据调用,一种单据支持多单打印模板。

              typedef ATL::CSimpleArray<HWND>  
_notifyClass;

  图片 1

          if(m_pSettingChangeNotify == NULL)

//设计
        private void btnDes_Click(object sender, EventArgs e)
        {
            if (tvwRight.SelectedNode != null)
            {
                if (!string.IsNullOrEmpty(FormID) && !string.IsNullOrEmpty(RptNo))
                {
                    InitializeReport("DESIGN");
                }
                else
                {
                    MessageBox.Show("报表获取失败。", "信息", MessageBoxButtons.OK, MessageBoxIcon.Information);
                }
            }
            else
            {
                MessageBox.Show("请先选择报表。", "信息", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
        }

     }

 6、设计模板加载:

//    
HRESULT hRes = ::CoInitializeEx(NULL, COINIT_MULTITHREADED);

//保存菜单:对话框
        private void DesignerSettings_CustomSaveDialog(object sender, OpenSaveDialogEventArgs e)
        {
            isSaveAs = true;
        }

    
_Module.AddMessageLoop(&theLoop);   //将消息添加至信息循环

  II、报表模板存储在数据库被。一是支持客户端设计以及保存模板,二凡一致坏修改所有客户端生效。

     int nRet = theLoop.Run();

哼了,主要的机能就是享受到此,希望对大家来一部分扶助。

 

//设计报表
        private void DesignReport(string RptMode)
        {
            using (Report TargetReport = new Report())
            {
                TargetReport.FileName = RptName;
                if (RptRow["FILEDATA"].ToString().Length > 0)
                {
                    byte[] ReportBytes = (byte[])RptRow["FILEDATA"];
                    using (MemoryStream Stream = new MemoryStream(ReportBytes))
                    {
                        TargetReport.Load(Stream);
                    }
                }
                //操作方式:DESIGN-设计;PREVIEW-预览;PRINT-打印
                if (RptMode == "DESIGN")
                {
                    TargetReport.Design();
                }
                else if (RptMode == "PREVIEW")
                {
                    TargetReport.Prepare();
                    TargetReport.ShowPrepared();
                }
                else if (RptMode == "PRINT")
                {
                    TargetReport.Print();
                }
            }
        }

     {

是因为篇幅较多,本次重大分享计划按钮的职能。闲话少说!

 

证:FormID是单ID,即哪种单据调用报表设计窗体则吃此属性赋值。RptNo、RptName在点击图一律报表种类时赋值。

    
WS_OVERLAPPEDWINDOW | WS_VSCROLL | WS_HSCROLL,

2、新增FastReportDesign窗体(图一):

 

  III、点击保存是以模板保存在数据库中,点击任何存也可拿模板保存也文件。这样可兑现模板的复制。

 

3、双击设计按钮:

 

说明:FastReport设计器菜单保存及另外存也力量,都是拿设计模板保存成文件。由于我们需要以筹划模板保存及数据库,所以要遮掩掉系统本来的力量协调写。另外索要征的凡,保存按钮无见面弹来对话框,所以当点击任何存为时,才见面触发OpenSaveDialogEventHandler。(可参看FastReport自带范例CustomOpenSaveDialogs)

    
//注册窗口

//保存报表
        private void SaveReport(Report TargetReport)
        {
            try
            {
                using (MemoryStream msStream = new MemoryStream())
                {
                    //保存
                    TargetReport.Save(msStream);
                    RptRow["FILEDATA"] = msStream.ToArray();
                    if (MyMeans.Con == null || MyMeans.Con.State != ConnectionState.Open)
                    {
                        mymeans.ConOpen();
                    }
                    SqlCommand Cmd = MyMeans.Con.CreateCommand();
                    Cmd.CommandText = "UPDATE AT_REPORT SET FILEDATA=@FILEDATA WHERE FORMID=@FORMID AND RPT_NO=@RPT_NO";
                    Cmd.Parameters.AddWithValue("@FILEDATA", msStream.ToArray());
                    Cmd.Parameters.AddWithValue("@FORMID", FormID);
                    Cmd.Parameters.AddWithValue("@RPT_NO", RptNo);
                    Cmd.ExecuteNonQuery();
                    //另存为
                    if(isSaveAs==true)
                    {
                        SaveFileDialog saveFileDialog = new SaveFileDialog();
                        //设置文件类型
                        saveFileDialog.Filter = "报表文件(*.frx)|*.frx|C# 文件(*.cs)|*.cs|FastReport VCL report(*.fr3)|*.fr3|RDL file(*rdl)|*.rdl";
                        //设置默认文件类型显示顺序  
                        saveFileDialog.FilterIndex = 1;
                        //是否自动在文件名中添加扩展名
                        saveFileDialog.AddExtension = true;
                        //是否记忆上次打开的目录
                        saveFileDialog.RestoreDirectory = true;
                        //设置默认文件名
                        saveFileDialog.FileName = RptName;
                        //按下确定选择的按钮  
                        if (saveFileDialog.ShowDialog() == DialogResult.OK)
                        {
                            //获得文件路径 
                            string localFilePath = saveFileDialog.FileName.ToString();
                            //文件保存
                            FileStream fsStream = new FileStream(localFilePath, FileMode.Create);
                            msStream.WriteTo(fsStream);
                            //资源释放      
                            fsStream.Close();
                            fsStream = null;
                        }
                        //赋初始值
                        isSaveAs = false;
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
        }

 

//保存菜单:委托函数
        private void DesignerSettings_CustomSaveReport(object sender, OpenSaveReportEventArgs e)
        {
            SaveReport(e.Report);
        }

     …

CREATE TABLE [dbo].[AT_REPORT](
    [FORMID] [varchar](20) NOT NULL,
    [RPT_NO] [varchar](20) NOT NULL,
    [RPT_NAME] [varchar](50) NULL,
    [FILEDATA] [varbinary](max) NULL,
 CONSTRAINT [PK_AT_REPORT] PRIMARY KEY CLUSTERED 
(
    [FORMID] ASC,
    [RPT_NO] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

         }

using System.Data.SqlClient;
using FastReport;
using FastReport.Utils;
using FastReport.Design;

AddSettingChangeNotify()添加一个窗口句柄。

说明:mymeans.ConOpen()是友好写的接近措施,主要是连续数据库。

              return;

  1.1引用FastReport库文件。

             
ATLTRACE2(atlTraceUI, 0, _T(“ERROR : Unable to lock critical section in
CAppModule::InitSettingChangeNotify.\n”));

务求和长:

     return FALSE;

1、数据表设计。

     void TermSettingChangeNotify()

4、初始化方法:

         BOOL bRet =
FALSE;

VS2017+SQL SERVER 2014+FastReport.Net(2017.1.16)

         }

图片 2

}   

{

以WTL::CappModule中定义了8独国有成员函数,分别吗:

 

             
ATLASSERT(m_pSettingChangeNotify != NULL);

// If
you are running on NT 4.0 or higher you can use the following call
instead to

    
lock.Unlock();

          if(m_pSettingChangeNotify != NULL &&
m_pSettingChangeNotify->GetSize() > 0)

       类定义如下:

             
ATLTRY(m_pSettingChangeNotify = new
_notifyClass);

 

 

LRESULT CALLBACK
WndProc(HWND hwnd,UINT Message,WPARAM wParam,LPARAM lParam);

 

         }

}

             
ATLASSERT(FALSE);

     //清理消息

             
ATLTRACE2(atlTraceUI, 0, _T(“ERROR : Unable to lock critical section in
CAppModule::TermSettingChangeNotify.\n”));

BOOL
AddSettingChangeNotify(HWND hWnd)

          while(GetMessage(&msg,NULL,0,0))

              //??空的ATL Dialog Template吗?

             
}

              return FALSE;

        

 

             
ATLASSERT(FALSE);

         {

#ifdef _WIN64

         
CStaticDataInitCriticalSectionLock lock;

             
ATLTRACE2(atlTraceUI, 0, _T(“ERROR : Unable to lock critical section in
CAppModule::InitSettingChangeNotify.\n”));

         
::DefWindowProc(NULL, 0, 0, 0L);

         {

             
ATLASSERT(FALSE);

拖欠函数通过线程Id在m_pMsgLoopMap消息队列中找对应的消息循环,找到后回去。

         }

         
ShowWindow(hwnd,iCmdShow);

         
UpdateWindow(hwnd);

     {

     return bRet;

     hRes = _Module.Init(NULL, hInstance); //等下分析其的实现     
ATLASSERT(SUCCEEDED(hRes));

     }

         BOOL bRet =
(m_pSettingChangeNotify != NULL);

          if(m_pSettingChangeNotify == NULL)

             
}

                  
::SetWindowLongPtr(hNtfWnd, GWLP_USERDATA, (LONG_PTR)this);

 

率先由全局变量_Module开始。

{

 

         }

        

RemoveMessageLoop()移除消息循环队列。

     }

                  
bRet = m_pSettingChangeNotify->Add(hNtfWnd);

                  
bRet = FALSE;

 

         
CStaticDataInitCriticalSectionLock lock;

              return NULL;

             
{

 

         
lock.Unlock();

         {

              AtlGetDefaultGuiFont()获得默认的示字体

 

          WNDCLASS
wndclass;

     hwnd =
CreateWindow(szAppName,TEXT(“My Application”),

              ::DestroyWindow((*m_pSettingChangeNotify)[0]);

             
ATLASSERT(FALSE);

#endif

         
CStaticDataInitCriticalSectionLock lock;

         {

          if(FAILED(lock.Lock()))

       另外还有3独全局函数:

int Run(LPTSTR /*lpstrCmdLine*/ = NULL, int nCmdShow = SW_SHOWDEFAULT)

    
::CoUninitialize();

     //生成框架

              
DispatchMessage(&msg);

从这个_tWinMain函数的定义,你得窥见先后的要部分是自己紫色标记出来的Run()函数。这个函数是一个自定义的函数,不过要通过ATL/WTL导向程序,那么会自动生成这样一个Run()函数的,下面我们先分析一下者自动生成的Run函数。

              if(::IsWindow(hNtfWnd))

#else

 

 

每当就篇稿子我未思过多的剖析应用程序框架和窗口的底细,这些内容以放在以后的几篇稿子中详细分析,本文主要针对ATLAPP.H头文件被实现之有的历程进展详细分析。

5. 始发消息循环

         {

AddMessageLoop()添加一个音循环,进入信息循环队列里。

     {

     {

          if(InitSettingChangeNotify() !=
FALSE)

         return bRet;

 

 

     {

// this resolves ATL window thunking problem when
Microsoft Layer for Unicode (MSLU) is used

         
ATLTRACE(_T(“Main window creation failed!\n”));

              AtlInitCommonControls()初始化一些控件所用一并之DLL

     {

// need
conditional code because types don’t match in winuser.h

         delete m_pSettingChangeNotify;

     BOOL
bRet = m_pMsgLoopMap->Add(::GetCurrentThreadId(), pMsgLoop);

          if(FAILED(lock.Lock()))

          if(bRet &&
m_pSettingChangeNotify->GetSize() == 0)

     }

 

// need
conditional code because types don’t match in winuser.h

              else

         
CStaticDataInitCriticalSectionLock lock;

 

                  
::SetWindowLongPtr(hNtfWnd, GWLP_USERDATA, PtrToLong(this));

     //创建窗口

RemoveSettingChangeNotify()清理环境

             
}

BOOL
RemoveMessageLoop()

         
lock.Unlock();

         {

     }

     {

             
ATLTRACE2(atlTraceUI, 0, _T(“ERROR : Unable to lock critical section in
CAppModule::GetMessageLoop.\n”));

             
ATLTRACE2(atlTraceUI, 0, _T(“ERROR : Unable to lock critical section in
CAppModule::AddSettingChangeNotify.\n”));

         
CMessageLoop* pLoop = m_pMsgLoopMap->Lookup(dwThreadID);

       关键部分雷同通过红色字体标记出来,嗯,没错正如AddMessageLoop函数一样,该函数也是由此线程Id来查找信息循环移除对象的。

#endif

 

    
_Module.RemoveMessageLoop();

              CserverAppModule类—用于Com服务构架的应用程序类

 

2. 创造窗口

     {

              return FALSE;

         return bRet;

         }

     }

     //锁住要片断,由于进程同步的涉嫌!!!

//窗口过程处理函数

4. 来得应用程序框架

 

         
MessageBox(NULL,TEXT(“Porgram requires Windows
NT!”),szAppName,MB_ICONERROR);

              //增加一个无模式对话框

    
ATLASSERT(pMsgLoop != NULL);

         }

除8单国有成员函数外,该类还定义了3只国有成员变量

     if(!RegisterClass(&wndclass))

         
wndclass.lpfnWndProc = WndProc;

}

      WTL程序的布局

          if(FAILED(lock.Lock()))

              //销毁窗口

          {

     BOOL
InitSettingChangeNotify(DLGPROC pfnDlgProc =
_SettingChangeDlgProc)

    
             
//加入该窗口句柄

          if(FAILED(lock.Lock()))

{

             
ATLASSERT(FALSE);

             
ATLASSERT(::IsWindow(hNtfWnd));

         
lock.Unlock();

GetMessageLoop()获得信息循环。

 

         }

下分别来分析几只根本成员函数的贯彻:

        CidleHandler 类—用于空闲消息处理的

    
CW_USEDEFAULT,CW_USEDEFAULT,

         }

         
wndclass.style       = CS_HREDRAW | CS_VREDRAW;

              HWND
hNtfWnd = ::CreateDialogIndirect(GetModuleInstance(), &templ, NULL,
pfnDlgProc);

这就是说你也许会见问WTL的WinMain函数再哪里?如果您通过WTL/ATL导向生成一个应用程序,那么您见面于同工程名字同名的.cpp文件被窥见如下的代码:

         return pLoop;

1. 注册窗口类

             
ATLASSERT(FALSE);

         
m_pSettingChangeNotify = NULL;

// make
the EXE free threaded. This means that calls come in on a random RPC
thread.

              else

         
lock.Unlock();

 

         
ATLTRACE2(atlTraceUI, 0, _T(“ERROR : Unable to lock critical section in
CAppModule::AddMessageLoop.\n”));

         
lock.Unlock();

int WINAPI
_tWinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPTSTR lpstrCmdLine,
int nCmdShow)

     }

     //清除消息

     //运行信息循环

          return 0;

    
CW_USEDEFAULT,CW_USEDEFAULT,

     CMessageLoop
theLoop;                  //定义消息循环

     {

#ifdef _WIN64

              //增加一个无模式对话框

int WINAPI WinMain(HINSTANCE
hInstance,HINSTANCE hPrevInstance,LPSTR szCmdLine,int iCmdShow)

              return FALSE;

     return nRet;

         {

       
AtlInitCommonControls(ICC_COOL_CLASSES | ICC_BAR_CLASSES); // add flags to support other
controls

_Module维持在转应用程序的主线程,控制着程序的信息循环队列,是一个CAppModule的目标。该CAppModule从ATL::CcomModule继承。

          HWND hwnd =
NULL;

         BOOL bRet =
m_pMsgLoopMap->Remove(::GetCurrentThreadId());

          MSG
msg;

             
_ATL_EMPTY_DLGTEMPLATE templ;

             
ATLASSERT(m_pSettingChangeNotify != NULL);

     if(wndMain.CreateEx() == NULL)

             
}

     return nRet;

    
NULL,NULL,hInstance,NULL);

    
wndMain.ShowWindow(nCmdShow);

              // init everything

 

             
ATLASSERT(::IsWindow(hNtfWnd));

             
{

CMessageLoop*
GetMessageLoop(DWORD dwThreadID = ::GetCurrentThreadId()) const

 

              if(::IsWindow(hNtfWnd))

     HRESULT hRes =
::CoInitialize(NULL);

m_pSettingChangeNotify负责存放窗口句柄

    
_Module.Term();

 

2. 每当大局的_Module中进入此消息循环

6. 了事消息循环

m_pMsgLoopMap负责存储消息循环

     }

 

         return 0;

         BOOL bRet =
(m_pSettingChangeNotify != NULL);

 

拖欠函数用来初始化一个存放窗口句柄的目标

                  
::SetWindowLongPtr(hNtfWnd, GWLP_USERDATA, (LONG_PTR)this);

实现分析

                  
bRet =
m_pSettingChangeNotify->Add(hNtfWnd);

         
ATLASSERT(::IsWindow(hWnd));

         {

                  
::SetWindowLongPtr(hNtfWnd, GWLP_USERDATA, PtrToLong(this));

 

         

3. 生化为一个应用程序框架对象

        
//进入信息循环

InitSettingChangeNotify()初始化环境

3. 进信息循环

    
ATLASSERT(m_pMsgLoopMap->Lookup(::GetCurrentThreadId()) == NULL);  
// not in map yet

             
ATLTRACE2(atlTraceUI, 0, _T(“ERROR : Unable to lock critical section in
CAppModule::RemoveMessageLoop.\n”));

          if(bRet &&
m_pSettingChangeNotify->GetSize() == 0)

ATLAPP.H包含了音讯循环类、接口类、和发应用程序所不可或缺的一对基础类定义。

              return FALSE;

              typedef ATL::CSimpleArray<HWND>  
_notifyClass;

        CmessageLoop类—用于信息循环的

         
ATLASSERT(FALSE);

7. 赶回WinMain函数,结束程序

经此Run函数我们好看看在函数中成就了之类几独过程:

         return bRet;

#else

 

1. 生变为一个消息循环对象(theLoop)

       一个窗口程序的创办及销毁过程要通过如下几个阶段

         }

 

              HWND
hNtfWnd = ::CreateDialogIndirect(GetModuleInstance(), &templ, NULL,
pfnDlgProc);

     return msg.wParam;

BOOL
AddMessageLoop(CMessageLoop* pMsgLoop)

 

    
关键部分自为此革命的书标记出来了,意思是啊?通过时线程的Id来标示一个消息循环,存储在m_pMsgLoopMap中。

若果就此C写了Win32窗口程序的人数必然会记得如下的构造:

     int nRet =
Run(lpstrCmdLine, nCmdShow);//程序的重大分

         
ATLASSERT(SUCCEEDED(hRes));

         {

             
{

          }

              // init everything

              CmessageFilter类—用于信息过滤的

     CMainFrame
wndMain;                //应用程序框架好像

         
CStaticDataInitCriticalSectionLock lock;

     BOOL
InitSettingChangeNotify(DLGPROC pfnDlgProc =
_SettingChangeDlgProc)

             
{

 

         {

     //显示框架

         
CStaticDataInitCriticalSectionLock lock;

             
ATLTRY(m_pSettingChangeNotify = new
_notifyClass);