搜档网
当前位置:搜档网 › MFC架构处理流程

MFC架构处理流程

MFC架构处理流程
MFC架构处理流程

MFC技术内幕系列之(一)---MFC应用程序“生死因果”内幕

///////////////////////////////////////////////////////////////////////////////////

/********* 文章系列:MFC技术内幕系列***********/

/************MFC技术内幕系列之(一)***********/

/****文章题目:MFC应用程序“生死因果”内幕*****/

/* Copyright(c)2002 bigwhite */

/* All rights Reserved */

/***********关键字:MFC,生死因果**************/

/* 时间:2002.7.23 */

/* 注释:本文所涉及的程序源代码均在Microsoft */

/ Visual https://www.sodocs.net/doc/233479764.html, Enterprise Architect Edition /

/* 开发工具包提供的源代码中 */

////////////////////////////////////////////////////////////////////////////////////////////////

引言:

侯捷老师在他那本著名的"深入浅出MFC"(第二版)的第六章中对比着传统的Win32API编程,详细讲解了MFC应用程序“生死因果”,而且侯捷老师还在"深入浅出MFC"(第二版)一书的“无责任书评”中称应用程序和MFC Framework的因果关系,是学习MFC程序设计的关键,并把它作为学习MFC程序设计的"第一个台阶".

作为已是“过来人”的我非常赞同侯捷老师的观点,特写下此篇文章以供大家参考,本文章特别对MFC 程序设计的初学者大有裨益。

正文:

初学MFC程序设计的人(甚至包括已经很精通Win32API编程的大虾们)都会感到很疑惑,对MFC应用程序的运行流程不能马上领悟,多数人都会提出类似"WinMain函数跑到哪里去了?","窗口函数(WinProc),消息循环好像一下子都消失了?"等问题。下面就让我们看一个MFC SDI应用程序的运行流程并挖掘一下MFC库的源代码,来尽力争取弄清MFC应用程序“生死因果”的内幕。

////////////////////////////////////////////

/* 1. Windows 帮忙*/

/* 程序诞生!*/

//////////////////////////////////////////

Windows 操作系统为应用程序创建进程核心对象,并为该应用程序分配4GB的进程地址空间,系统加载器

将应用程序可执行文件映像以及一些必要的代码(包括数据和一些应用程序使用的dlls)加载到应用程序的进程地址空间中。

/////////////////////////////////////////////

/* 2.启动函数是什么?*/

/////////////////////////////////////////////

Windows 操作系统在初始化该应用程序进程的同时,将自动为该应用程序创建一个主线程,该主线程与

C/C++运行时库的启动函数一道开始运行。很多初学者并不知道C/C++运行时库的启动函数是何方神圣,这里我

简单介绍一下:当你的应用程序编译后开始链接时,系统的链接器会根据你的应用程序的设置为你的应用程序

选择一个C/C++运行时库的启动函数(注释:这些函数声明在..\Visual https://www.sodocs.net/doc/233479764.html,\vc7\crt\src\crt0.c 中)

一般的ANSI版本的GUI的应用程序的C/C++运行时库的启动函数为:

int WinMainCRTStartup(void);

其它版本的C/C++运行时库的启动函数如下:

ANSI版本的CUI的应用程序: int mainCRTStartup(void);

Unicode版本的CUI的应用程序: int wmainCRTStartup(void);

Unicode版本的GUI的应用程序: int wWinMainCRTStartup(void);

C/C++运行时库的启动函数的主要功能为初始化C/C++运行时库和为所有全局和静态的C++类对象调用构造函数。

/////////////////////////////////////////////////

/* 3.侯捷老师所说的"引爆器" */

/////////////////////////////////////////////////

前面所说的C/C++运行时库的启动函数的主要功能之一是为所有全局和静态的C++类对象调用构造函数。侯捷老师所说的"引爆器"---CMyWinApp theApp这个Application Object就是由启动函数调用其构造函数构造出来的。CWinApp的构造函数到底作了什么?看看源代码吧,源代码最能说明问题了。

注释:CWinApp的构造函数定义在..\Visual https://www.sodocs.net/doc/233479764.html,\vc7\atlmfc\src\mfc\appcore.cpp

CWinApp::CWinApp(LPCTSTR lpszAppName)

{

if (lpszAppName != NULL)

m_pszAppName = _tcsdup(lpszAppName);

else

m_pszAppName = NULL;

// initialize CWinThread state

AFX_MODULE_STATE* pModuleState = _AFX_CMDTARGET_GETSTATE();

AFX_MODULE_THREAD_STATE* pThreadState = pModuleState->m_thread;

ASSERT(AfxGetThread() == NULL);

pThreadState->m_pCurrentWinThread = this;

ASSERT(AfxGetThread() == this);

m_hThread = ::GetCurrentThread();

m_nThreadID = ::GetCurrentThreadId();

// initialize CWinApp state

ASSERT(afxCurrentWinApp == NULL); // only one CWinApp object please

pModuleState->m_pCurrentWinApp = this;

ASSERT(AfxGetApp() == this);

// in non-running state until WinMain

m_hInstance = NULL;

m_hLangResourceDLL = NULL;

m_pszHelpFilePath = NULL;

m_pszProfileName = NULL;

m_pszRegistryKey = NULL;

m_pszExeName = NULL;

m_pRecentFileList = NULL;

m_pDocManager = NULL;

m_atomApp = m_atomSystemTopic = NULL;

m_lpCmdLine = NULL;

m_pCmdInfo = NULL;

// initialize wait cursor state

...//

// initialize current printer state

...//

// initialize DAO state

m_lpfnDaoTerm = NULL; // will be set if AfxDaoInit called

// other initialization

...//

}

从源代码中可以看出CWinApp的构造函数主要收集了一些关于应用程序主线程的信息及初始化一些相关应用程序的信息。值得注意的是CWinApp类的一些主要的数据成员如:m_hInstance,m_lpCmdLine,m_pCmdInfo及m_atomApp等都初始化为NULL,这些成员在后面将被重新赋值。

//////////////////////////////////////////////

/* 4. WinMain函数登场了*/

//////////////////////////////////////////////

C/C++运行时库的启动函数int WinMainCRTStartup(void);所调用的WinMain函数---同时也是主线程的入口函数为:

int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPTSTR lpCmdLine ,int nCmdShow);

注释1:该函数定义在..\Visual https://www.sodocs.net/doc/233479764.html,\vc7\atlmfc\src\mfc\appmodul.cpp中

注释2:_t 是为了照顾Unicode版本而定义的宏。

讲到这个时候你也许会稍稍展开你那紧皱的眉头,不过也许你还会问:"MFC中的WinMain函数到底作了什么?" 其实很简单,看看源代码就知道了。

extern "C" int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,

LPTSTR lpCmdLine, int nCmdShow)

{

// call shared/exported WinMain

return AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);

}

这一下清楚了,MFC中的WinMain函数其实什么也没做,只是调用了一个函数AfxWinMain。

/////////////////////////////////////////////////

/* 5.MFC程序的入口点函数*/

//////////////////////////////////////////////////

MFC作了一个"乾坤大挪移",将WinMain函数的全部责任转移交给了MFC程序的入口点函数---AfxWinMain。

注释:该函数定义在..\Visual https://www.sodocs.net/doc/233479764.html,\vc7\atlmfc\src\mfc\winmain.cpp中。

// Standard WinMain implementation

// Can be replaced as long as 'AfxWinInit' is called first

int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,

LPTSTR lpCmdLine, int nCmdShow)

{

ASSERT(hPrevInstance == NULL);

int nReturnCode = -1;

CWinThread* pThread = AfxGetThread();

CWinApp* pApp = AfxGetApp();

// AFX internal initialization

if (!AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow))

goto InitFailure;

// App global initializations (rare)

if (pApp != NULL && !pApp->InitApplication())

goto InitFailure;

// Perform specific initializations

if (!pThread->InitInstance())

{

if (pThread->m_pMainWnd != NULL)

{

TRACE(traceAppMsg, 0, "Warning: Destroying non-NULL m_pMainWnd\n");

pThread->m_pMainWnd->DestroyWindow();

}

nReturnCode = pThread->ExitInstance();

goto InitFailure;

}

nReturnCode = pThread->Run();

InitFailure:

#ifdef _DEBUG

// Check for missing AfxLockTempMap calls

if (AfxGetModuleThreadState()->m_nTempMapLock != 0)

{

TRACE(traceAppMsg, 0, "Warning: Temp map lock count non-zero (%ld).\n",

AfxGetModuleThreadState()->m_nTempMapLock);

}

AfxLockTempMaps();

AfxUnlockTempMaps(-1);

#endif

AfxWinTerm();

return nReturnCode;

}

从上面源代码可以看出AfxWinMain函数主要由四大模块组成,他们分别是AfxWinInit,InitApplication,

InitInstance,Run。下面将分别介绍这四大模块的功能。

///////////////////////////////////////////////

/* 5.1 AFX的内部初始化*/

///////////////////////////////////////////////

AfxWinInit函数是既CWinApp类构造函数后的又一个重量级的函数。不妨看一下它的源代码:注释:该函数定义在..\Visual https://www.sodocs.net/doc/233479764.html,\vc7\atlmfc\src\mfc\appinit.cpp中。

BOOL AFXAPI AfxWinInit(HINSTANCE hInstance, HINSTANCE hPrevInstance,

LPTSTR lpCmdLine, int nCmdShow)

{

ASSERT(hPrevInstance == NULL);

// handle critical errors and avoid Windows message boxes

SetErrorMode(SetErrorMode(0) |

SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);

// set resource handles

AFX_MODULE_STATE* pModuleState = AfxGetModuleState();

pModuleState->m_hCurrentInstanceHandle = hInstance;

pModuleState->m_hCurrentResourceHandle = hInstance;

// fill in the initial state for the application

CWinApp* pApp = AfxGetApp();

if (pApp != NULL)

{

// Windows specific initialization (not done if no CWinApp)

pApp->m_hInstance = hInstance;

hPrevInstance; // Obsolete.

pApp->m_lpCmdLine = lpCmdLine;

pApp->m_nCmdShow = nCmdShow;

pApp->SetCurrentHandles();

}

// initialize thread specific data (for main thread)

if (!afxContextIsDLL)

AfxInitThread();

// Initialize CWnd::m_pfnNotifyWinEvent

HMODULE hModule = ::GetModuleHandle(_T("user32.dll"));

if (hModule != NULL)

{

CWnd::m_pfnNotifyWinEvent = (CWnd::PFNNOTIFYWINEVENT)::GetProcAddress(hModule, "NotifyWin Event");

}

return TRUE;

}

还记得我在第三个标题---侯捷老师所说的"引爆器"处的话么,"CWinApp类的一些主要的数据成员在后面将被重新赋值。",AfxWinInit函数就是这些数据成员被赋值的地方,它重新初始化这些在整个程中都扮演重要角色的成员,并且调用AfxInitThread()为主线程作了一些初始化工作,这些都为以后MFC框架的正常运作铺平了道路。

/////////////////////////////////////////////////

/* 5.2 应用程序的全局初始化*/

/////////////////////////////////////////////////

InitApplication函数(virtual)为程序进行全局初始化:

注释1:该函数定义在..\Visual https://www.sodocs.net/doc/233479764.html,\vc7\atlmfc\src\mfc\appcore.cpp中。

BOOL CWinApp::InitApplication()

{

if (CDocManager::pStaticDocManager != NULL)

{

if (m_pDocManager == NULL)

m_pDocManager = CDocManager::pStaticDocManager;

CDocManager::pStaticDocManager = NULL;

}

if (m_pDocManager != NULL)

m_pDocManager->AddDocTemplate(NULL);

else

CDocManager::bStaticInit = FALSE;

LoadSysPolicies();

return TRUE;

}

由于初次调用时CDocManager::pStaticDocManager==0x00000000;m_pDocManager==0x00000000;所以InitApplication函数只是调用了CWinApp::LoadSysPolicies();而后者将加载一些注册表的信息用来初始化一些程序定义的结构并为程序注册一些基本信息。(由于该函数可能尚未文档化,所以关于LoadSysPolicies函数的说明只是看了源代码后的推测,下面列出了它的部分源代码仅供参考)

注释2:该函数定义在..\Visual https://www.sodocs.net/doc/233479764.html,\vc7\atlmfc\src\mfc\appcore.cpp中。

BOOL CWinApp::LoadSysPolicies()

{

HKEY hkPolicy = NULL;

DWORD dwValue = 0;

DWORD dwDataLen = sizeof(dwValue);

DWORD dwType = 0;

// clear current policy settings.

m_dwPolicies = _AFX_SYSPOLICY_NOTINITIALIZED;

static _AfxSysPolicyData rgExplorerData[] =

{

{_T("NoRun"), _AFX_SYSPOLICY_NORUN},

{_T("NoDrives"), _AFX_SYSPOLICY_NODRIVES},

{_T("RestrictRun"), _AFX_SYSPOLICY_RESTRICTRUN},

{_T("NoNetConnectDisconnect"), _AFX_SYSPOLICY_NONETCONNECTDISCONNECTD},

{_T("NoRecentDocsHistory"), _AFX_SYSPOLICY_NORECENTDOCHISTORY},

{_T("NoClose"), _AFX_SYSPOLICY_NOCLOSE},

{NULL, NULL}

};

...//

static _AfxSysPolicyData rgComDlgData[] =

{

{_T("NoPlacesBar"), _AFX_SYSPOLICY_NOPLACESBAR},

{_T("NoBackButton"), _AFX_SYSPOLICY_NOBACKBUTTON},

{_T("NoFileMru"), _AFX_SYSPOLICY_NOFILEMRU},

{NULL, NULL}

};

static _AfxSysPolicies rgPolicies[] =

{

{_T("Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer"),

rgExplorerData},

{_T("Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Network"),

rgNetworkData},

{_T("Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Comdlg32"),

rgComDlgData},

{NULL, NULL}

};

_AfxSysPolicies *pPolicies = rgPolicies;

_AfxSysPolicyData *pData = NULL;

...//

}

注释3:在MFC文档中有这么一句话"The CWinApp::InitApplication member function is obsolete in MFC.",所以你大多情况下不用在意这个virtual函数。

/////////////////////////////////////////////////

/* 5.3 应用程序的标准实例化*/

//////////////////////////////////////////////////

CWinApp::InitInstance()是一个虚函数,大多数应用程序都要override这个函数。让我们看看应用程序向导MFC AppWizard(.exe)为SDI 程序作出的override后的代码吧!

BOOL CMyWinApp::InitInstance()

{

// 如果一个运行在 Windows XP 上的应用程序清单指定要

// 使用 ComCtl32.dll 版本 6 或更高版本来启用可视化方式,

//则需要 InitCommonControls()。否则,将无法创建窗口。

InitCommonControls();

CWinApp::InitInstance();//显式调用基类的InitInstance()

// 初始化 OLE 库

if (!AfxOleInit())

{

AfxMessageBox(IDP_OLE_INIT_FAILED);

return FALSE;

}

AfxEnableControlContainer();

// 标准初始化

SetRegistryKey(_T("应用程序向导生成的本地应用程序"));

LoadStdProfileSettings(4); // 加载标准 INI 文件选项(包括 MRU)

// 注册应用程序的文档模板。

// 文档模板将用作文档、框架窗口和视图之间的连接

CSingleDocTemplate* pDocTemplate;

pDocTemplate = new CSingleDocTemplate(

IDR_MAINFRAME,

RUNTIME_CLASS(CTestDoc),

RUNTIME_CLASS(CMainFrame), // 主 SDI 框架窗口

RUNTIME_CLASS(CTestView));

pDocTemplate->SetContainerInfo(IDR_CNTR_INPLACE);

AddDocTemplate(pDocTemplate);

// 分析标准外壳命令、DDE、打开文件操作的命令行

CCommandLineInfo cmdInfo;

ParseCommandLine(cmdInfo);

if (!ProcessShellCommand(cmdInfo))

return FALSE;

// 唯一的一个窗口已初始化,因此显示它并对其进行更新

m_pMainWnd->ShowWindow(SW_HIDE);

m_pMainWnd->UpdateWindow();

return TRUE;

}

CMyWinApp::InitInstance()先显式调用了基类的InitInstance();

我们先看看这个基类的函数的定义吧!

注释1:该函数定义在..\Visual https://www.sodocs.net/doc/233479764.html,\vc7\atlmfc\src\mfc\appcore.cpp中。

BOOL CWinApp::InitInstance()

{

InitLibId();

m_hLangResourceDLL = LoadAppLangResourceDLL();

if(m_hLangResourceDLL != NULL)

{

AfxSetResourceHandle(m_hLangResourceDLL);

_AtlBaseModule.SetResourceInstance(m_hLangResourceDLL);

}

return TRUE;

}

注释2:https://www.sodocs.net/doc/233479764.html,中的CWinApp::InitInstance()已与vc6.0中的CWinApp::InitInstance()有所区别。

基类的InitInstance()

先调用InitLibId()函数用于Initializes the data member containing the GUID of the current module;

不过该函数现在为空,估计以后微软会填充该函数。

之后调用LoadAppLangResourceDLL()函数加载应用程序所需资源;在vc6.0中的CWinApp::InitInstance()函数只有一条语句:即return TRUE;

CMyWinApp::InitInstance()在其基类的帮助后,开始执行它自己的一系列代码来完成诸如"初始化OLE 库","设置注册表主键以使程序能保存信息到注册表中","分析标准外壳命令","生成程序主框架,文档和视图结构","显示程序主窗口"等工作。

注释3:有关应用程序是如何在CMyWinApp::InitInstance()完成上面一系列工作的,将在本系列文

章之二的“MFC文档视图结构内幕”一文中详述。

注释4:在MSDN中有关InitInstance的叙述如下:"Windows allows several copies of the same program to run at the same time."

////////////////////////////////////////////

/* 5.4 "消息泵"启动了*/

////////////////////////////////////////////

众所周知,Windows是一个以消息为基础,以事件驱动的操作系统,每一个Win32程序也都是如此。那么

MFC应用程序是如何实现消息机制的呢?MFC应用程序框架将这种消息机制包装到了一个"消息泵"中,而这个"消息泵"在CMyWinApp::InitInstance()中被启动了。其源代码如下:

注释1:该函数定义在..\Visual https://www.sodocs.net/doc/233479764.html,\vc7\atlmfc\src\mfc\appcore.cpp中。

// Main running routine until application exits

int CWinApp::Run()

{

if (m_pMainWnd == NULL && AfxOleGetUserCtrl())

{

// Not launched /Embedding or /Automation, but has no main window!

TRACE(traceAppMsg, 0, "Warning: m_pMainWnd is NULL in CWinApp::Run - quitting application.\n");

AfxPostQuitMessage(0);

}

return CWinThread::Run();

}

由上面的源代码看出:CWinApp::Run()调用了其基类的Run()函数,继续看源代码:

int CWinThread::Run()

{

ASSERT_V ALID(this);

_AFX_THREAD_STATE* pState = AfxGetThreadState();

// for tracking the idle time state

BOOL bIdle = TRUE;

LONG lIdleCount = 0;

// acquire and dispatch messages until a WM_QUIT message is received.

for (;;)

{

// phase1: check to see if we can do idle work

while (bIdle &&

!::PeekMessage(&(pState->m_msgCur), NULL, NULL, NULL, PM_NOREMOVE))

{

// call OnIdle while in bIdle state

if (!OnIdle(lIdleCount++))

bIdle = FALSE; // assume "no idle" state

}

// phase2: pump messages while available

do

{

// pump message, but quit on WM_QUIT

if (!PumpMessage())

return ExitInstance();

// reset "no idle" state after pumping "normal" message

//if (IsIdleMessage(&m_msgCur))

if (IsIdleMessage(&(pState->m_msgCur)))

{

bIdle = TRUE;

lIdleCount = 0;

}

} while (::PeekMessage(&(pState->m_msgCur), NULL, NULL, NULL, PM_NOREMOVE));

}

}

//CWinThread implementation helpers

BOOL CWinThread::PumpMessage()

{

return AfxInternalPumpMessage();

}

BOOL AFXAPI AfxInternalPumpMessage()//部分源码

{

_AFX_THREAD_STATE *pState = AfxGetThreadState();

if (!::GetMessage(&(pState->m_msgCur), NULL, NULL, NULL))

{

...//

return FALSE;

}

...//

// process this message

if (pState->m_msgCur.message != WM_KICKIDLE && !AfxPreTranslateMessage(&(pState->m_msgCur)))

{

::TranslateMessage(&(pState->m_msgCur));

::DispatchMessage(&(pState->m_msgCur));

}

return TRUE;

}

终于出现了::TranslateMessage和::DispatchMessage,熟悉Win32API编程的人一定会眼睛一亮,终

于挖出源头了。

/////////////////////////////////////////

/* 6. 收尾工作*/

////////////////////////////////////////

MFC应用程序的主要流程几乎都已被挖掘完了,下面看一下收尾工作是如何进行的。

当应用程序发现消息队列中出现了WM_QUIT消息时, nReturnCode = pThread->Run();CWinApp::Run()返回,并设置返回值。下面将执行AfxWinTerm函数。其源代码如下:注释1:该函数定义在..\Visual https://www.sodocs.net/doc/233479764.html,\vc7\atlmfc\src\mfc\appterm.cpp中。

// Standard cleanup called by WinMain and AfxAbort

void AFXAPI AfxWinTerm(void)

{

// unregister Window classes

AFX_MODULE_STATE* pModuleState = AfxGetModuleState();

AfxLockGlobals(CRIT_REGCLASSLIST);

LPTSTR lpsz = pModuleState->m_szUnregisterList;

while (*lpsz != 0)

{

LPTSTR lpszEnd = _tcschr(lpsz, '\n');

ASSERT(lpszEnd != NULL);

*lpszEnd = 0;

UnregisterClass(lpsz, AfxGetInstanceHandle());

lpsz = lpszEnd + 1;

}

pModuleState->m_szUnregisterList[0] = 0;

AfxUnlockGlobals(CRIT_REGCLASSLIST);

// cleanup OLE if required

CWinThread* pThread = AfxGetApp();

if (pThread != NULL && pThread->m_lpfnOleTermOrFreeLib != NULL)

(*pThread->m_lpfnOleTermOrFreeLib)(TRUE, FALSE);

// cleanup thread local tooltip window

AFX_MODULE_THREAD_STATE* pModuleThreadState = AfxGetModuleThreadState();

if (pModuleThreadState->m_pToolTip != NULL)

{

if (pModuleThreadState->m_pToolTip->DestroyToolTipCtrl())

pModuleThreadState->m_pToolTip = NULL;

}

_AFX_THREAD_STATE* pThreadState = AfxGetThreadState();

if (!afxContextIsDLL)

{

// unhook windows hooks

if (pThreadState->m_hHookOldMsgFilter != NULL)

{

::UnhookWindowsHookEx(pThreadState->m_hHookOldMsgFilter);

pThreadState->m_hHookOldMsgFilter = NULL;

}

if (pThreadState->m_hHookOldCbtFilter != NULL)

{

::UnhookWindowsHookEx(pThreadState->m_hHookOldCbtFilter);

pThreadState->m_hHookOldCbtFilter = NULL;

}

}

}

由源代码可以看出:该函数主要作一些清除工作,将该释放的东西释放,比如卸载钩子等。

等到AfxWinTerm函数结束,AfxWinMain函数返回nReturnCode值,且该值也将作为_WinMain函数的返回值返回。

让我们回过头来再看一看C/C++运行时库的启动函数的源代码:

注释2:函数定义在..\Visual https://www.sodocs.net/doc/233479764.html,\vc7\crt\src\crtexe.c中

int WinMainCRTStartup(void)//部分源代码

{

int argc; /* three standard arguments to main */

_TSCHAR **argv;

_TSCHAR **envp;

int argret;

int mainret;

int managedapp;

#ifdef _WINMAIN_

_TUCHAR *lpszCommandLine;

STARTUPINFO StartupInfo;

#endif /* _WINMAIN_ */

_startupinfo startinfo;

/*

* Determine if this is a managed application

*/

managedapp = check_managed_app();

...//

StartupInfo.dwFlags = 0;

GetStartupInfo( &StartupInfo );

#ifdef WPRFLAG

mainret = wWinMain(

#else /* WPRFLAG */

mainret = WinMain(

#endif /* WPRFLAG */

GetModuleHandleA(NULL),

NULL,

lpszCommandLine,

StartupInfo.dwFlags & STARTF_USESHOWWINDOW

? StartupInfo.wShowWindow

: SW_SHOWDEFAULT);

...//

if ( !managedapp )

exit(mainret);

...//

return mainret;

}

WinMain函数将返回值传给mainret,WinMainCRTStartup调用C运行时函数exit(int status);后者做什么了呢?看看微软自己的文档重视如何说的:

"The exit functions terminate the calling process. exit calls, in last-in-first-out (LIFO) order, the functions registered by atexit and _onexit, then flushes all file buffers before terminating the process.The status value is typically set to 0 to indicate a normal exit and set to some other value to indicate an error."

事实上,exit函数除了做以上工作外,还为所有全局的和静态的C++类对象调用析构函数(如~CMyWinApp),

将返回值传递给Windows操作系统的ExitProcess函数,使得操作系统可以撤销该进程并设置它的exit代码。

//////////////////////////////////////

/* 7. 结束了*/

/////////////////////////////////////

经过这么大篇幅的挖掘,一个MFC应用程序从生到死的流程我们都已目睹完了,相信你一定有所收获,在本文中涉及到一些细节的时候我有时只是一句话代过,因为我将在以后的系列文章中详细讲解,比如:MFC文档视图结构等细节,希望读者能继续关注我的文章。

MFC技术内幕系列之(二)---MFC文档视图结构内幕

////////////////////////////////////////////////////////////////////////////////////

/********* 文章系列:MFC技术内幕系列***********/

/************MFC技术内幕系列之(二)***********/

/**** 文章题目:MFC文档视图结构内幕*****/

/* Copyright(c)2002 bigwhite */

/* All rights Reserved */

/*********关键字:MFC,文档视图结构************/

/* 时间:2002.7.23 */

/* 注释:本文所涉及的程序源代码均在Microsoft */

/ Visual https://www.sodocs.net/doc/233479764.html, Enterprise Architect Edition /

/* 开发工具包提供的源代码中*/

//////////////////////////////////////////////////////////////////////////////////////////////////////////

引言:侯捷老师的"深入浅出MFC"一书的第8章中有“"Document/View"是MFC的基石。”一说,可以看出文档视图结构在MFC Framework中的地位是多么的重要。本文将以一个标准MFC应用程序向导作成的MDI程序为例,来和大家一起详细挖掘文档视图结构的内幕。

正文:

/////////////////////////////////////////////

/* 1.回顾"InitInstance函数" */

/////////////////////////////////////////////

在我的《MFC应用程序“生死因果”内幕》一文中,当谈到CMyWinApp::InitInstance()时,我只是粗略的讲了介绍了一下各个函数的功能,而忽略了很多细节,这里让我们在回顾一下CMyWinApp::InitInstance()函数,并将里面与文档视图结构有关的代码深入探讨一下:

BOOL CMyApp::InitInstance()//只列出了与文档视图结构相关的源代码

{

//...

//文档模板将用作文档、框架窗口和视图之间的连接

CMultiDocTemplate* pDocTemplate;

pDocTemplate = new CMultiDocTemplate(IDR_MyTYPE,

RUNTIME_CLASS(CMyDoc),

RUNTIME_CLASS(CChildFrame), // 自定义 MDI 子框架

RUNTIME_CLASS(CMyView));

AddDocTemplate(pDocTemplate);

// 创建主 MDI 框架窗口

CMainFrame* pMainFrame = new CMainFrame;

if (!pMainFrame->LoadFrame(IDR_MAINFRAME))

return FALSE;

m_pMainWnd = pMainFrame;

// 仅当具有后缀时才调用 DragAcceptFiles

// 在 MDI 应用程序中,这应在设置 m_pMainWnd 之后立即发生

// 分析标准外壳命令、DDE、打开文件操作的命令行

CCommandLineInfo cmdInfo;

ParseCommandLine(cmdInfo);

// 调度在命令行中指定的命令。如果

// 用 /RegServer、/Register、/Unregserver 或 /Unregister 启动应用程序,则返回 FALSE。

if (!ProcessShellCommand(cmdInfo))

return FALSE;

// 主窗口已初始化,因此显示它并对其进行更新

pMainFrame->ShowWindow(m_nCmdShow);

pMainFrame->UpdateWindow();

return TRUE;

}

////////////////////////////////////////////

/* 2.初始化文档模板*/

////////////////////////////////////////////

分析以下代码:

CMultiDocTemplate* pDocTemplate;

pDocTemplate = new CMultiDocTemplate(IDR_MyTYPE,

RUNTIME_CLASS(CMyDoc),

RUNTIME_CLASS(CChildFrame), // 自定义 MDI 子框架

RUNTIME_CLASS(CMyView));

应用程序首先实例化一个CMultiDocTemplate对象,此过程也是对CMultiDocTemplate类数据成员的初始化过程。按调用次序我列出了以下源代码:

注释1: CDocTemplate构造函数定义在:..\Visual https://www.sodocs.net/doc/233479764.html,\vc7\atlmfc\src\mfc\doctempl.cpp

CDocTemplate::CDocTemplate(UINT nIDResource, CRuntimeClass* pDocClass,

CRuntimeClass* pFrameClass, CRuntimeClass* pViewClass)//部分源代码

{

ASSERT_V ALID_IDR(nIDResource);

ASSERT(pDocClass == NULL ||

pDocClass->IsDerivedFrom(RUNTIME_CLASS(CDocument)));

ASSERT(pFrameClass == NULL ||

pFrameClass->IsDerivedFrom(RUNTIME_CLASS(CFrameWnd)));

ASSERT(pViewClass == NULL ||

pViewClass->IsDerivedFrom(RUNTIME_CLASS(CView)));

m_nIDResource = nIDResource;

...//

m_pDocClass = pDocClass;

m_pFrameClass = pFrameClass;

m_pViewClass = pViewClass;

m_pOleFrameClass = NULL;

m_pOleViewClass = NULL;

...//

}

以上为CMultiDocTemplate类的基类CDocTemplate构造函数的部分源代码,该函数初始化了四个重要的成员

m_nIDResource,m_pDocClass,m_pFrameClass和m_pViewClass。

注释2: CMultiDocTemplate构造函数定义在:..\Visual https://www.sodocs.net/doc/233479764.html,\vc7\atlmfc\src\mfc\docmulti.cpp CMultiDocTemplate::CMultiDocTemplate(UINT nIDResource, CRuntimeClass* pDocClass,

CRuntimeClass* pFrameClass, CRuntimeClass* pViewClass)

: CDocTemplate(nIDResource, pDocClass, pFrameClass, pViewClass)

{

ASSERT(m_docList.IsEmpty());

m_hMenuShared = NULL;

m_hAccelTable = NULL;

m_nUntitledCount = 0; // start at 1

// load resources in constructor if not statically allocated

if (!CDocManager::bStaticInit)

LoadTemplate();

}

看完以上代码后,来回过头看一看InitInstance函数将什么参数值传给了CMultiDocTemplate的构造函数。

原来是一些RUNTIME_CLASS宏。以下是RUNTIME_CLASS宏的定义:

注释3: 以下的宏定义在:..\Visual https://www.sodocs.net/doc/233479764.html,\vc7\atlmfc\include\afx.h中

#define RUNTIME_CLASS(class_name) _RUNTIME_CLASS(class_name)

#define _RUNTIME_CLASS(class_name) ((CRuntimeClass*)(&class_name::class##class_name))

这个地方是个难点,这将涉及到MFC的另一个重要技术---"执行期类型识别"。此项技术我将在MFC技术内幕系列之(三)---《MFC执行期类型识别与动态创建技术内幕》中详细讲解。回到眼前来,源代码中这样作是为了将CMyDoc,CChildFrame,CMyView各类中的static CRuntimeClass class##class_name地址赋予CMultiDocTemplate类的各CRuntimeClass*指针成员m_pDocClass,

m_pFrameClass和m_pViewClass,这位以后的动态创建Document/Frame/View"三口组"打下了基础。

///////////////////////////////////////////

/* 3.文档模板列队*/

///////////////////////////////////////////

文档模板初始化结束后,InitInstance函数调用了CWinApp::AddDocTemplate(pDocTemplate)函数,

其主要目的是将以初始化后的那个文档模板加入到文档模板链表中,并由CDocManager类对象进行

管理。以下操作就是为了完成此工作。

注释1: 以下函数定义在:..\Visual https://www.sodocs.net/doc/233479764.html,\vc7\atlmfc\src\mfc\appui2.cpp

void CWinApp::AddDocTemplate(CDocTemplate* pTemplate)//将CMultiDocTemplate* pDocTemplate

{ //传给pTemplate

if (m_pDocManager == NULL)

m_pDocManager = new CDocManager;

m_pDocManager->AddDocTemplate(pTemplate);

}

注释2: 以下函数定义在:..\Visual https://www.sodocs.net/doc/233479764.html,\vc7\atlmfc\src\mfc\docmgr.cpp

CDocManager::CDocManager()

{

}//目前是一个空函数;

void CDocManager::AddDocTemplate(CDocTemplate* pTemplate)//部分源代码

{

if (pTemplate == NULL)

{

...//

}

else

{

ASSERT_V ALID(pTemplate);

ASSERT(m_templateList.Find(pTemplate, NULL) == NULL);// must not be in list

pTemplate->LoadTemplate();

m_templateList.AddTail(pTemplate);//CPtrList m_templateList is a member //of CDocManager

}

}

///////////////////////////////////////////////

/* 4.创建程序主框架窗口*/

///////////////////////////////////////////////

应用程序实例化了一个CMainFrame类对象,并调用LoadFrame函数加载窗口资源创建主框架窗

口。以下是创建主框架窗口的流程。

创建窗口的主要代码是:pMainFrame->LoadFrame(IDR_MAINFRAME);LoadFrame函数是MFC

包装了窗口创建过程的函数,在后面动态创建Child窗口时,它还将披挂上阵(但稍有不同)。下面是

它的源代码,让我们仔细分析一下:

注释1: 以下函数定义在:..\Visual https://www.sodocs.net/doc/233479764.html,\vc7\atlmfc\src\mfc\winmdi.cpp

BOOL CMDIFrameWnd::LoadFrame(UINT nIDResource, DWORD dwDefaultStyle,

CWnd* pParentWnd, CCreateContext* pContext)

{

if (!CFrameWnd::LoadFrame(nIDResource, dwDefaultStyle,

pParentWnd, pContext))

return FALSE;

// save menu to use when no active MDI child window is present

ASSERT(m_hWnd != NULL);

m_hMenuDefault = ::GetMenu(m_hWnd);

if (m_hMenuDefault == NULL)

TRACE(traceAppMsg, 0, "Warning: CMDIFrameWnd without a default menu.\n");

return TRUE;

CMDIFrameWnd::LoadFrame调用了其基类CFrameWnd的LoadFrame,并将参数原封不动的传给它。

注释2: 以下函数定义在:..\Visual https://www.sodocs.net/doc/233479764.html,\vc7\atlmfc\src\mfc\winfrm.cpp

BOOL CFrameWnd::LoadFrame(UINT nIDResource, DWORD dwDefaultStyle,

CWnd* pParentWnd, CCreateContext* pContext) //部分源代码

{

...//

CString strFullString;

if (strFullString.LoadString(nIDResource))

AfxExtractSubString(m_strTitle, strFullString, 0); // first sub-string

VERIFY(AfxDeferRegisterClass(AFX_WNDFRAMEORVIEW_REG));

// attempt to create the window

LPCTSTR lpszClass = GetIconWndClass(dwDefaultStyle, nIDResource);

CString strTitle = m_strTitle;

if (!Create(lpszClass, strTitle, dwDefaultStyle, rectDefault,

pParentWnd, MAKEINTRESOURCE(nIDResource), 0L, pContext))

{

return FALSE; // will self destruct on failure normally

}

...//

if (pContext == NULL) // send initial update

SendMessageToDescendants(WM_INITIALUPDATE, 0, 0, TRUE, TRUE);

return TRUE;

}

//////////////////////////////////////////////////////

/* 4.1注册应用程序主框架窗口类 */

//////////////////////////////////////////////////////

在传统的Win32API编程中,创建窗口一般步骤是定义窗口类,注册窗口类,并调用::CreateWindow 函数来创建。前面说过LoadFrame函数封装了MFC创建窗口的过程,那么也就是说LoadFrame函数将负责定义窗口类,注册窗口类等琐碎工作。下面我们就通过挖掘源代码来看看LoadFrame函数是如何完成这些工作的。

LoadFrame首先调用AfxDeferRegisterClass(AFX_WNDFRAMEORVIEW_REG),

注释1: 以下宏定义在:..\Visual https://www.sodocs.net/doc/233479764.html,\vc7\atlmfc\src\mfc\afximpl.h

#define AfxDeferRegisterClass(fClass) AfxEndDeferRegisterClass(fClass)

注释2: 以下函数定义在:..\Visual https://www.sodocs.net/doc/233479764.html,\vc7\atlmfc\src\mfc\wincore.cpp

BOOL AFXAPI AfxEndDeferRegisterClass(LONG fToRegister)//部分源代码

{

// mask off all classes that are already registered

AFX_MODULE_STATE* pModuleState = AfxGetModuleState();

fToRegister &= ~pModuleState->m_fRegisteredClasses;

if (fToRegister == 0)

return TRUE;

LONG fRegisteredClasses = 0;

// common initialization

WNDCLASS wndcls;

memset(&wndcls, 0, sizeof(WNDCLASS)); // start with NULL defaults

wndcls.lpfnWndProc = DefWindowProc;

wndcls.hInstance = AfxGetInstanceHandle();

wndcls.hCursor = afxData.hcurArrow;

INITCOMMONCONTROLSEX init;

init.dwSize = sizeof(init);

// work to register classes as specified by fToRegister, populate fRegisteredClasses as we go

if (fToRegister & AFX_WND_REG)

// Child windows - no brush, no icon, safest default class styles

wndcls.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;

wndcls.lpszClassName = _afxWnd;

if (AfxRegisterClass(&wndcls))

fRegisteredClasses |= AFX_WND_REG;

}

...//

if (fToRegister & AFX_WNDMDIFRAME_REG)

{

// MDI Frame window (also used for splitter window)

wndcls.style = CS_DBLCLKS;

wndcls.hbrBackground = NULL;

if (_AfxRegisterWithIcon(&wndcls, _afxWndMDIFrame, AFX_IDI_STD_MDIFRAME))

fRegisteredClasses |= AFX_WNDMDIFRAME_REG;

}

if (fToRegister & AFX_WNDFRAMEORVIEW_REG)

{

// SDI Frame or MDI Child windows or views - normal colors

wndcls.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;

wndcls.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);

if (_AfxRegisterWithIcon(&wndcls, _afxWndFrameOrView, AFX_IDI_STD_FRAME))

fRegisteredClasses |= AFX_WNDFRAMEORVIEW_REG;

}

...//

// must have registered at least as mamy classes as requested

return (fToRegister & fRegisteredClasses) == fToRegister;

}

MFC预定义了若干个“窗口类模板”,比如"AFX_WNDMDIFRAME_REG","AFX_WNDFRAMEORVIEW_REG"等,MFC在

LoadFrame函数中调用AfxEndDeferRegisterClass函数为你的应用程序预注册了适当的窗口类。本例中预注册的窗口类为AFX_WNDFRAMEORVIEW_REG。(注意是预注册,如果你在后面更改了CREATESTRUCT结构的域成员,MFC还会根据你的更改重新为你的应用程序正式注册新的窗口类,稍候会有详细叙述)

预注册完窗口类,MFC将判断你是否想更改窗口类的各参数。若你更改了,则MFC会重新注册新类;否则源预注册的窗口类就将成为正式的窗口类。下面我们来看看MFC的判断过程:此判断过程由GetIconWndClass开始

LPCTSTR lpszClass = GetIconWndClass(dwDefaultStyle, nIDResource);

注释3: 以下函数定义在:..\Visual https://www.sodocs.net/doc/233479764.html,\vc7\atlmfc\src\mfc\winfrm.cpp

LPCTSTR CFrameWnd::GetIconWndClass(DWORD dwDefaultStyle, UINT nIDResource)//部分源代码

{

...//

HICON hIcon = ::LoadIcon(hInst, MAKEINTRESOURCE(nIDResource));

if (hIcon != NULL)

{

CREATESTRUCT cs;

memset(&cs, 0, sizeof(CREATESTRUCT));

cs.style = dwDefaultStyle;

PreCreateWindow(cs);

// will fill lpszClassName with default WNDCLASS name

// ignore instance handle from PreCreateWindow.

WNDCLASS wndcls;

GetClassInfo(AfxGetInstanceHandle(), cs.lpszClass, &wndcls) &&

wndcls.hIcon != hIcon)

{

// register a very similar WNDCLASS

return AfxRegisterWndClass(wndcls.style,

wndcls.hCursor, wndcls.hbrBackground, hIcon);

}

}

return NULL; // just use the default

}

GetIconWndClass函数将调用CMainFrame::PreCreateWindow(CREATESTRUCT& cs)来看看应用程序是否修改了CREATESTRUCT结构的域成员。CMainFrame::PreCreateWindow调用CMDIFrameWnd::PreCreateWindow(CREATESTRUCT& cs),后者的代码如下:

BOOL CMDIFrameWnd::PreCreateWindow(CREATESTRUCT& cs)//in winmdi.cpp

{

if (cs.lpszClass == NULL)

{

VERIFY(AfxDeferRegisterClass(AFX_WNDMDIFRAME_REG));

cs.lpszClass = _afxWndMDIFrame;

}

return TRUE;

}

MFC将为应用程序注册AFX_WNDMDIFRAME_REG预定义窗口类,并设置cs.lpszClass = _afxWndMDIFrame。

在应用程序的代码中我更改了cs结构:

BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)

{

if( !CMDIFrameWnd::PreCreateWindow(cs) )

return FALSE;

// TODO: 在此处通过修改 CREATESTRUCT cs 来修改窗口类或

// 样式

cs.dwExStyle=~WS_EX_CLIENTEDGE;

return TRUE;

}

CMainFrame::PreCreateWindow返回后,GetIconWndClass函数调用GetClassInfo函数重新收集cs信息(此时的信息已是更改后的了),并调用AfxRegisterWndClass函数重新注册该窗口类(此窗口类为该应用程序的正式窗口类)。到此为止窗口类注册完毕,以后程序还会调用一次CMainFrame::PreCreateWindow,不过那此只是"过门不如"而已。

/////////////////////////////////////////////////

/* 4.2主框架窗口创建开始*/

/////////////////////////////////////////////////

开始进入创建框架窗口的实质阶段。看LoadFrame函数做了什么?原来它调用了Create函数。

注释1: 以下函数定义在:..\Visual https://www.sodocs.net/doc/233479764.html,\vc7\atlmfc\src\mfc\winfrm.cpp

BOOL CFrameWnd::Create(LPCTSTR lpszClassName,

LPCTSTR lpszWindowName,

DWORD dwStyle,

const RECT& rect,

CWnd* pParentWnd,

LPCTSTR lpszMenuName,

DWORD dwExStyle,

CCreateContext* pContext)

{

HMENU hMenu = NULL;

{

// load in a menu that will get destroyed when window gets destroyed

HINSTANCE hInst = AfxFindResourceHandle(lpszMenuName, RT_MENU);

if ((hMenu = ::LoadMenu(hInst, lpszMenuName)) == NULL)

{

TRACE(traceAppMsg, 0, "Warning: failed to load menu for CFrameWnd.\n");

PostNcDestroy(); // perhaps delete the C++ object

return FALSE;

}

}

m_strTitle = lpszWindowName; // save title for later

if (!CreateEx(dwExStyle, lpszClassName, lpszWindowName, dwStyle,

rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,

pParentWnd->GetSafeHwnd(), hMenu, (LPVOID)pContext))

{

TRACE(traceAppMsg, 0, "Warning: failed to create CFrameWnd.\n");

if (hMenu != NULL)

DestroyMenu(hMenu);

return FALSE;

}

return TRUE;

}

简单地说CFrameWnd::Create函数调用了基类的CWnd::CreateEx;

注释2: 以下函数定义在:..\Visual https://www.sodocs.net/doc/233479764.html,\vc7\atlmfc\src\mfc\wincore.cpp BOOL CWnd::CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName,

LPCTSTR lpszWindowName, DWORD dwStyle,

int x, int y, int nWidth, int nHeight,

HWND hWndParent, HMENU nIDorHMenu, LPVOID lpParam)//部分源代码

{

// allow modification of several common create parameters

CREATESTRUCT cs;

cs.dwExStyle = dwExStyle;

cs.lpszClass = lpszClassName;

cs.lpszName = lpszWindowName;

cs.style = dwStyle;

cs.x = x;

cs.y = y;

cs.cx = nWidth;

cs.cy = nHeight;

cs.hwndParent = hWndParent;

cs.hMenu = nIDorHMenu;

cs.hInstance = AfxGetInstanceHandle();

cs.lpCreateParams = lpParam;

if (!PreCreateWindow(cs))

{

PostNcDestroy();

return FALSE;

}

AfxHookWindowCreate(this);

HWND hWnd = ::CreateWindowEx(cs.dwExStyle, cs.lpszClass,

cs.lpszName, cs.style, cs.x, cs.y, cs.cx, cs.cy,

cs.hwndParent, cs.hMenu, cs.hInstance, cs.lpCreateParams);

...//

return TRUE;

}

BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)

{

if( !CMDIFrameWnd::PreCreateWindow(cs) )

return FALSE;

// TODO: 在此处通过修改 CREATESTRUCT cs 来修改窗口类或

// 样式

cs.dwExStyle=~WS_EX_CLIENTEDGE;

return TRUE;

}

BOOL CMDIFrameWnd::PreCreateWindow(CREATESTRUCT& cs)

{

if (cs.lpszClass == NULL)

{

VERIFY(AfxDeferRegisterClass(AFX_WNDMDIFRAME_REG));

cs.lpszClass = _afxWndMDIFrame;

}

return TRUE;

}

CWnd::CreateEx调用了CMainFrame::PreCreateWindow,但此次AfxDeferRegisterClass将不会被调用。也就是我上面所说的“过门不入”。

CWnd::CreateEx函数还调用了AfxHookWindowCreate(this);后者是干什么的呢?其实它与消息映射和命令传递有关,我将在MFC技术内幕系列之(四)--《MFC消息映射与消息传递内幕》一文中详解。

CWnd::CreateEx调用Win32API ::CreateWindowEx函数(传统的Win32API程序员一定不陌生这个函数),

就这样主框架窗口创建结束。

//////////////////////////////////////////////

/* 5.标准外壳命令解析*/

///////////////////////////////////////////////

MFC向导制作的标准MDI应用程序启动时,应用程序会自动启动一个子窗口框架(实际上是一套文档模板),这是为何呢?下面我将详细讲解一下这个创建过程.

其实这一过程也是在CMyWinApp::InitInstance()函数中完成的,看看下面代码:

CCommandLineInfo cmdInfo;

ParseCommandLine(cmdInfo);

if (!ProcessShellCommand(cmdInfo))

return FALSE;

函数首先实例化一个CCommandLineInfo类对象cmdInfo,让我们看看CCommandLineInfo是个什么东东?

//in afxwin.h

class CCommandLineInfo : public CObject//部分源代码

{

public:

// Sets default values

CCommandLineInfo();

...//

BOOL m_bShowSplash;

BOOL m_bRunEmbedded;

BOOL m_bRunAutomated;

enum { FileNew, FileOpen, FilePrint, FilePrintTo, FileDDE, AppRegister,

AppUnregister, FileNothing = -1 } m_nShellCommand;

// not valid for FileNew

CString m_strFileName;

// valid only for FilePrintTo

CString m_strPrinterName;

CString m_strDriverName;

CString m_strPortName;

~CCommandLineInfo();

// Implementation

...//

};

再让我们来看看它的构造函数的实现:

//in appcore.cpp

CCommandLineInfo::CCommandLineInfo()

{

m_bShowSplash = TRUE;

m_bRunEmbedded = FALSE;

m_bRunAutomated = FALSE;

m_nShellCommand = FileNew;

}

m_nShellCommand = FileNew;这一句对我们最重要;至于CWinApp::ParseCommandLine我想用MFC 文档中的一句话来解释:

Call this member function to parse the command line and send the parameters, one at a time, to CCommandLineInfo::ParseParam.

下面我们来看看外壳命令解析的主角:CWinApp::ProcessShellCommand

//in appui2.cpp

//DDE and ShellExecute support

BOOL CWinApp::ProcessShellCommand(CCommandLineInfo& rCmdInfo)//部分源代码

{

BOOL bResult = TRUE;

switch (rCmdInfo.m_nShellCommand)

{

case CCommandLineInfo::FileNew:

if (!AfxGetApp()->OnCmdMsg(ID_FILE_NEW, 0, NULL, NULL))

OnFileNew();

if (m_pMainWnd == NULL)

bResult = FALSE;

break;

// If we've been asked to open a file, call OpenDocumentFile()

case CCommandLineInfo::FileOpen:

if (!OpenDocumentFile(rCmdInfo.m_strFileName))

bResult = FALSE;

break;

case CCommandLineInfo::FilePrintTo:

case CCommandLineInfo::FilePrint:

...//

case CCommandLineInfo::FileDDE:

...//

case CCommandLineInfo::AppRegister:

...//

case CCommandLineInfo::AppUnregister:

...//

}

return bResult;

}

挖掘源代码的确是了解MFC运行内幕的最好手段,大家一看源代码便知道如之何了。CCommandLineInfo构造函数中m_nShellCommand = FileNew;所以在ProcessShellCommand中对应的代码自然就一目了然了:CWinApp::OnFileNew()被调用了。

//////////////////////////////////////////////////

/* 6.一套文档/视图即将诞生*/

//////////////////////////////////////////////////

上文说CWinApp::OnFileNew()被调用了,那么就让我来看看其代码吧!

//in appdlg.cpp

void CWinApp::OnFileNew()

{

if (m_pDocManager != NULL)

m_pDocManager->OnFileNew();

}

//in docmgr.cpp

void CDocManager::OnFileNew()//部分源代码

{

...//

CDocTemplate* pTemplate = (CDocTemplate*)m_templateList.GetHead();

if (m_templateList.GetCount() > 1)

{

// more than one document template to choose from

// bring up dialog prompting user

CNewTypeDlg dlg(&m_templateList);

INT_PTR nID = dlg.DoModal();

if (nID == IDOK)

pTemplate = dlg.m_pSelectedTemplate;

else

return; // none - cancel operation

}

ASSERT(pTemplate != NULL);

ASSERT_KINDOF(CDocTemplate, pTemplate);

pTemplate->OpenDocumentFile(NULL);

// if returns NULL, the user has already been alerted

}

//in docmulti.cpp

CDocument* CMultiDocTemplate::OpenDocumentFile(LPCTSTR lpszPathName, BOOL bMakeVisible)//部分源代码

{

CDocument* pDocument = CreateNewDocument();

...//

BOOL bAutoDelete = pDocument->m_bAutoDelete;

pDocument->m_bAutoDelete = FALSE; // don't destroy if something goes wrong CFrameWnd* pFrame = CreateNewFrame(pDocument, NULL);

pDocument->m_bAutoDelete = bAutoDelete;

...//

if (lpszPathName == NULL)

{

// create a new document - with default document name

SetDefaultTitle(pDocument);

// avoid creating temporary compound file when starting up invisible

if (!bMakeVisible)

pDocument->m_bEmbedded = TRUE;

if (!pDocument->OnNewDocument())

{

// user has be alerted to what failed in OnNewDocument

TRACE(traceAppMsg, 0, "CDocument::OnNewDocument returned FALSE.\n"); pFrame->DestroyWindow();

return NULL;

}

// it worked, now bump untitled count

m_nUntitledCount++;

}

else

关于完善公司组织架构优化管理流程的建议

关于完善公司组织架构优化管理流程 的建议

关于完善公司组织架构优化管理流程的建议 喻总: 公司组织架构是流程运转、部门设置及职能规划等最基本的结构依据,适宜、高效的组织架构能够最大限度的释放企业的能量,使组织更好发挥协同效应,达到“1+1>2”的合理运营状态。根据我司“组织架构图”所述,公司在董事长领导下,分为五个职能部门:人资部、市场部、出品部、运营部、财务部。 一、公司当前组织架构在日常管理存在的问题: 企业组织架构的设置,应该强调管理职能的有效行使和管理流程的顺畅高效。本人经过对加入公司一年多的工作总结,发现公司现有的组织架构存在以下问题: 1、总部部门管理体系不完善、节点不清晰、权责不明确、执行监督无依据。当前在现阶段日常管理中弊端尚未完全显现,但在公司经营规模进一步扩大后,必将会导致公司整体运营管理不顺畅,不能实现公司期望的达成目标,对公司战略目标的实现将缺乏有效支撑。 2、从当前组织机构看,许多部门要么具体职责空缺要么职能重叠,导致公司相关人员在日常工作中多头管理,职责不明,形成了“要管都管,要不论都不论”的局面。无法有效的进行系统运营工作的推进,造成关键职能(运营管理)弱化甚至缺失,不能体现“精简高效、专业分工、责权对等、执行与监督分设、客户服务导向及流程管理导向”的基本原则。

3、当前公司层面缺少一个对公司整体资源配置、组织管理的职能部门或职位,导致了各部门之间工作配合协调难、协作难,间接发展至各部门之间的不和谐甚至是冷暴力现象。 4、公司层面各部门负责人个人综合素质及过往工作经验与现担任的部门职责所要求能力不匹配,导致各部门之间的工作目标观与价值观不统一,此也是各部门矛盾存在的原因之一,缺乏同一个目标,导致团队没有同一个声音。 5、运营部缺乏指挥、调度、监管的权责。公司运营部虽然设立一年有余,但因为缺乏具体的权责以及公司整体流程的不完善,运营部的日常工作深陷在各类杂务之间(纯粹扮演救火队员及文职后勤人员的角色),无法对分店的经营指标、经营定位、现场管理等份内工作进行有效的规划与实施。 6、出品部的实际工作成绩与公司设立初衷相违背,没有有效的发挥应有职能,在有些方面甚至是某些问题的根源所在。 7、人资部个人认为是公司发展过程中的薄弱环节,缺乏相应的人力资源规划能力,招聘与配置工作严重滞后,直接导致公司在运营管理过程中存在的人员因素(如人员优化、补充等)无法解决,进一步影响了公司整体管理水平的提升。 8、随着公司业务和规模的进一步扩大,个人认为公司有必要设置专门进行客户和企业形象的部门,做好对外宣传和各项企划工作,提升公司外在形象。 9、监管环节缺失,奖惩管理流于形式,当前公司管控系统过于

工作流程、组织结构、岗位职责

1

2

一、副总经理:杨波(岗位职责) 1、每周做好各部门的工作计划,并监控实施; 2、协调各部门的工作内容,对于出现“事务闲置”及“人员闲置”负责任,通过人员激励及任务的合理分 配,保证工作的顺畅; 3、安排好对外安装的项目负责人,并协调其他部门配合该项目顺利完成; 4、对订单的全过程实施跟踪检查,并做好记录,如某个环节出了问题,及时处理并杜绝类似情况发生,并 承担责任; 5、保证当天的事情,当天完成,对于执行不力负责任; 6、保持电话畅通,以便客户、员工等能及时沟通; 7、在团队中完成分配的工作,并监督和提醒其他成员; 8、每周一将上周的工作情况以及本周的工作重点以邮件或书面的形式汇报给总经理; 9、离开厂区处理外部事情前,应在内勤处登记说明去处以及随同人员; 10、完成公司临时分配的任务,并负责任。 3

二、财务部:李小利(岗位职责) 1、及时统计应收应付情况,以供决策者了解别人欠了公司多少钱,公司欠别人多少钱; 2、建立健全公司报销制度,合理控制费用,并给出合理意见; 3、严格执行国家财经法律法规和公司制定的各项规章制度,做好会计核算工作,确保准确、及时报送会计资料; 4、负责审核原始凭证,做到原始凭证内容准确完整(户头是否正确、字迹是否清晰、数量*单价与金额是否相符、大小写金额是否一致,印鉴 是否齐全清晰,辨别凭证是否真实合法),内部自制的原始凭证,做到审批和签字手续齐全,如发现问题及时纠正; 5.及时登记帐薄,总帐与各明细帐、日记账及时核对,做到准确无误; 6、按时编制记帐凭证(经济业务分类、会计科目使用及科目的方向做到准确,摘要简明扼要),做到日事日清。对于编制好的记帐凭证及时传 递给审核人进行审核,对于审核有误的凭证,及时更正; 7、按月清理往来帐项,杜绝呆死帐发生,以保证足够的流动资金,强化资金风险意识,合理安排资金需要量; 8、负责编制月(次月15日前报完)、季、年的财务报表,保证帐帐、帐证、帐实、帐表相符,及时准确对内、外部门提供财务信息。此外,根据 企业内部管理的需要,不定期编制管理费用明细表;每月编制往来账项表; 9、协助库房定期做好固定资产、低值易耗品、材料物资等清查盘点工作; 10、不定期抽查出纳现金实际与账面余额相符情况,负责整理保管好各项目合同书、票据及各种财务资料; 11、定期装订会计凭证、帐簿、银行余额表、表册等,妥善保管并归档; 12、监督和分析企业的财务收、支状况,及时反馈变动因素和实际存在问题,当好领导的参谋; 13、按时完成领导交办的其他工作。 4

组织架构设计流程与调整流程

组织架构设计流程
1.组织架构设计流程与风险控制图 组织架构设计流程与风险控制 不相容责任部门/责任人的职责分工与审批权限划分 业务风险
董事会 总经理 战略委员会 开始 1 制定企业 有的经营活动就没 有明确的方向和目 确定企业 标 主导业务 分析主导 业务流程 2 确定管理层 次和管理幅 度,并与领导 界定不清晰,就容易 出现管理混乱、相互 推诿扯皮的现象 层沟通、确认 3 以主导流程为 基础,确定职 能部门及其相 互协作关系 4 确定具体 岗位及人员 编制 5 编制《组织架构 图》 、 《业务流程 审批 审核 图》 、 《岗位说明 书》 D3 D2 参与 审批 审核 战略发展规划 D1 人力资源部 相关部门
阶 段
如果没有明确的战 略发展规划,企业所
如果企业内部各层 级、各职能部门关系
如果《组织架构图》 、 《业务流程图》 、 《岗位 说明书》等文件编制混 乱,就会影响企业的运 作效率
结束

2.组织架构设计流程控制表 组织架构设计流程控制
控制事项 详细描述及说明 1.战略委员会在制定企业发展战略时,要考虑内、外部环境对企业发展战略的影响与制约;企业 D1 发展战略规划和目标应经过企业总经理和董事会的集体讨论、审核和审批 2.每一个部门、每一位管理者都要有合理的管理幅度。管理幅度太大,可能导致管理人员无暇 顾及一些重要事务;管理幅度太小,可能导致管理者不能完全发挥作用。所以,人力资源部 在设计组织结构的时候,要确定合理、恰当的管理幅度 3.人力资源部应当按照科学、精简、高效、透明、制衡的原则,综合考虑企业性质、发展战略、 阶段 控制 D2 形成各司其职、各负其责、相互制约、相互协调的工作关系;避免职能交叉、缺失或权责过 于集中 4.人力资源部应当对各机构、各部门的职能进行科学合理的分解,确定具体岗位的名称、职责 和工作要求等,明确各个岗位的权限和相互关系;在确保实现企业战略目标的前提下,力求 部门数量最少、人员编制最精,以达到节省沟通成本、缩短业务流程、提高运营效率的目的 文化理念和管理要求等因素,合理设置内部职能机构,明确各机构、各部门的职能和权限,
D3
5. 《组织架构图》 、 《业务流程图》和《岗位说明书》等文件资料应按照统一的规范编写
应建 相关 规范 规范 参照 规范
? 《组织架构设计规范》 ? 《岗位说明书编写规范》 ? 《企业内部控制应用指引》 ? 《中华人民共和国公司法》 ? 《组织架构图》
文件资料
? 《业务流程图》 ? 《岗位说明书》
责任部门 及责任人
? 战略委员会、人力资源部、相关部门 ? 总经理、副总经理、人力资源总监

HR组织架构调整流程

第一章-HR01_组织架构调整流程 1.流程说明 该流程主要描述了依据企业目标策略的调整及业务环境需求的变化而重新确定组织架构时,人力资源依照经核准的《组织系统图》在系统中修改或定义组织架构。 1.该流程主要涉及到的部门是总部人力资源,其具有创建、修改及显示的权限,区公司及营业的人力资源 只具有显示权限 1.创建组织架构包括:创建组织单元、职位、分配成本中心;组织单元与组织单元之间的关系是:一对一 或一对多,组织单元与职位之间的关系是:一对一或一对多;即一个组织单元下可建一个或多个组织单元,也可建一个或多个职位。由于在业务中财务需要对各个组织单元、人员的成本费用进行成本核算,所以需要给组织单元分配成本中心,或给职位分配成本中心,便于同财务的集成。组织单元的编码是由系统外部给号,由8位数字构成,分成四层,编码范围是00000000~,例:01000000~01009999用于总经理,01010000~01019999用于策略,02000000~用于其它各级组织单元。(见附件三十四)1.组织架构创建完后,通过Graphic,打印出组织系统图(参见报表样例“26组织系统图”) 2.流程图

3.系统操作 3.1.操作范例 3.1.1.创建 3.1.1.1.创建组织单元对象、关系 例1:创建组织单元营业,组织代码为 例2:创建组织单元销售行政,组织代码为 3.1.1.1.1. 系统菜单及交易代码 人力资源?组织管理?专家模式?组织单位 交易代码:P010

3.1.1.1.2. 系统屏幕及栏位解释 例1:创建组织单元营业,组织代码为 栏位名称栏位说明资料范例计划版本创建组织时的一个版本号,目前所有的计划版本号都为01 01 组织单元填入组织单元的编码(8位)必须参照职位编码原则填写 对象对象是指组织单元、职位、或任务;必须在“活动的”状态下做信息类型名称下的所有操作此对象是指组织单元 选中信息类型名称中的对象,按键创建组织单元。

关于公司组织架构调整及战略管理的提案

关于组织架构调整及制度流程配套方案 背景:四川XX置业有限公司成立于2003年,经过6年长足发展,公司已陆续开发多个项目,获得了较好的社会回报,资金实力也逐步得到提升。现公司已从单一项目开发向集约式、板块式项目运作进行转变。对此,过去以项目为导向的机构设置和重叠、模糊的职能部门设置不再符合企业发展需求,公司应尽快调整组织架构,建立高效、精细化的地产职能机构。 一、现有组织架构图 1、公司现有组织架构图存在弊端: 1)部门结构设置没有完全结合公司短、中、长期发展规划,仅围绕到项目开展设置部门,易造成部门稳定性差,人员无法定岗定编; 2)组织架构整体设计没有体现集中分权、有效幅度原则,缺乏部分必要部门,而又将一些业务流程节点部分分割,易出现工作交叉、推诿、效率低下以及人员编制重复等问题; 3)组织架构缺乏层叠性与纵伸性,仅从结构图上看,缺乏多样有效的信息传输通路;股东层、管理层、执行层权责没有体现;没有按照地产开发流程提取关

键点归纳后进行设置部门。 2、各职能部门分析 1)办公室:部门涵盖职能涉及企业战略管理、行政后勤管理、人力资源管理、秘书管理、电子信息管理以及审计职能。 意见:涉及工作面幅度大,部分工作没有必然联系性,且办公室主要职能未能完全突出,建议对部门进行拆分。 2)资金部:负责项目前期报建、个人购房按揭办理(逐步剥离);关联公司来往账务处理;企业(项目)融资工作;年度资金计划控制工作; 意见:工作涉及到财务部范畴,应考虑突出融资与资金协调(配额)及监督资金安全性方面的工作,可与其它业务关联性部门组合,并在架构中提升部门阶层; 3)财务部:公司日常账务建立处理;内部报销工作;税务申报工作。 意见:目前该部门未完全发挥应有职能,建议保留部门编制,扩大业务范围,全面负责账务、税务、资金稽核、资金流转、相关金融部门关系建立(维护)、统计、对其他部门财务支持工作。 4)企业发展部:新设部门,职权范围为负责公司级接待工作;对外联系联络,开拓维护政府脉络。 意见:据了解,该部门为非常设部门。因其职能可被包容,在新的组织机构框架设定中应出现常规常设部门。 5)营销部:承担公司项目策划、规划设计、营销职能。 意见:营销部应从土地信息获取、土地调研评估、参与招拍挂到项目规划设计、个案整体包装推广、销售控制等多个方面发挥作用,因此目前部门设置不合理,人员专业配比亟待改进。 6)建设开发部:兼顾工程项目管理、成本预算管理、园林现场管理以及报批报建职能。 意见:部门应该拆分,部门内结构应该严格按照开发量配置人员。 二、提议调整后组织架构图 1、调整思路 符合公司短期项目开发及管理目标,同时结合公司跨越式发展规划,设计精

投资公司组织架构和运作流程

投资公司组织架构图 运作流程

各部门职责 一般由公司总经理、研究部经理、投资部经理及其他相关人员组成。 负责决定公司所管理基金的投资计划、投资策略、投资原则、投资目标、资产分配及投资组合的总体计划等。 一般是由副总经理、部门经理及其他相关人员组成。 主要负责制定和监督执行风险控制政策,根据市场变化对基金的投资组合进行风险评估,并提出风险控制建议。 对部门提交的关于产品、财务等风险评估报告、建议进行讨论,做出决策建议,并提交董事会做出最终决策。 根据公司的经营目标,完成公司下达的基金产品销售目标。 根据接触客户的第一手资料,为投资管理部提供产品研发数据及建议。 营销策略、计划的拟定、实施和改进。 负责市场调研、市场分析工作,制定业务推进计划。 负责如实向客户介绍产品、与顾客洽谈、签订合同,确保所签合同规范、有效和可行,负责合同、评审记录的及时传递和保存。 了解客户的基本情况及与本企业有关的数据资料,建立和运用客户资料库。 协助客户服务部对顾客满意程度的调查。 负责公司形象设计以及公共关系的建立、往来与联系等,对公司品牌进行策划、推广等。 对行业进行深入研究,适时向公司提出调整投资策略(如地域选择、城市选择等)的建议。 通过广泛的渠道寻找优质项目,进行前期谈判和商务条款的谈判。 对项目进行分析、调查和论证,提交投资可行性报告。 对已投资项目的管理,及时发现问题并提交应对方案,及时采取应对措施。 根据投资管理部的项目研究成果,设计、推出新的基金产品类型,设计产品结构与思路,与其他部门紧密联系,设计产品宣传资料、设计相关法律文本。 负责基金的日常管理实务,办理相关的登记、注册、备案、银行对接事宜。实时跟踪基金项目的运作,监督项目的实施,按公司的要求提交基金运作报告,并就基金运作过程中所发生的情况及时向公司报告。 负责客户的咨询服务、接待,保管客户资料,处理客户投诉。 与营销人员紧密配合,保管客户档案,接受客户的投诉并处理,制定不同

人力资源部组织架构调整方案

人力资源部组织架构及职责

相关职位岗位职责: (一)培训发展组: 培训发展经理(1名): 1、负责协助人力资源部总监构建公司培训体系并逐步完善; 2、负责培训制度、工作流程的拟定、执行、维护及完善等工作; 3、负责根据公司经营战略及年度培训需求,制定年/季/月度培训计划及费用预算方案,主导组织实施、考核跟踪、检讨并完善; 4、根据公司战略规划,不断为公司培养各类基、中、高层管理人才及技术性人才,搭建公司人才梯队,主导组织职业生涯规划管理工作; 5、负责各项目培训档案的分类管理,以及门店培训室、培训设施的管理; 6、负责教材库/试题库的建立与完善等管理工作; 7、负责实施和监管培训过程中的奖罚与纪律; 8、负责公司讲师师资的建设及管理提升工作; 9、完成上级领导交办的临时性工作。 培训讲师(5名): 1、跟进公司的培训计划在门店的执行情况就执行效果及时向上汇报; 2、组织进行员工入职/转正/晋升考核并将及时反馈结果情况; 3、初拟部门各岗位转正/晋升试卷及初步审核各部门提交的试卷资料并跟进审批过程,汇总、分类相关试题形成试题库并进行日常管理; 4、负责初级培训教材的初步审核,对已审批的教材分类,形成教材库并进行日常管理;

5、负责对各单位的培训情况按周期进行检查,并形成书面检查报告; 6、负责完成培训组各类报表的初步分析并向上提供有价值的数据信息内容; 7、对负责区域分店的培训进行业务指导、授课、稽查、督促改进并提升等; 8、负责相关文字资料、报表资料、培训信息的收集、整理及归档等工作; 9、负责对培训档案(包括系统记录)进行管理与维护,包括录入、统计、整理、更新、销毁与存档等工作; 10、负责项目性培训课程现场的助教与服务工作; 11、完成上级领导交办的其它工作。 (二)薪酬激励组: 薪酬激励主管(1名): 1、负责协助人力资源总监对公司人力资源管理薪酬体系的构建及完善; 2、负责人员异动手续的审核与办理,含人事动态与结构分析及离职管理等工作,人事类报表的提报与审核; 3、负责员工试用期管理、员工转正/晋升等相关管理体系的建立、执行及完善; 4、负责员工考勤、值/排班、加班/调班、请/休假等日常人事工作管理; 5、负责人事系统的维护,相关数据统计、分析功能的增加方案提报; 6、负责公司奖惩体系的建立、执行及完善工作; 7、负责公司人事制度/流程/规范的制定、推行、检讨、修订等工作; 8、负责组织架构及工作设计,检讨设计编制及人力成本控制管理定编等工作及工作分析,编写工作职务说明书; 9、负责制定、检讨、修订门店人事行政部日常工作规范,并督促执行,提高人事工作人员日常业务技能; 10、完成上级领导临时交办工作。 专员(1名): 1、协助薪酬经理对公司人力资源管理薪酬体系的构建及完善; 2、负责定期收集行业薪酬信息和数据,为薪酬主任完成公司薪酬福利方案的过程提供相关参考数据资料等事务性工作; 3、负责收集、汇总公司人事制度/流程/规范在执行过程中的问题点,为薪酬主任检讨、修订相关制度/流程/规范提供相关参考依据等; 4、根据公司发展情况和行业水平,起草制定合理薪酬调整实施办法;

早教管理体系组织结构

早教管理体系组织结构 Document number:NOCG-YUNOO-BUYTT-UU986-1986UT

●组织结构 ●岗位职能 园长(总经理,执行总监) 职权:组织并制定公司的各项发展规划

指挥直接下属,尽量通过直接下属指指挥、指导日常工作(自己解脱,让中层得到锻炼,让中层得到重视,用监管问责制合理分配工作压力) 对整体的管控,组织,战略目标,财务规划等工作的任务分配,指导,成果考核与审批:(仅)对重点工作的指挥与指导,组织并达成目标 对各个部门,各个层次的调研与视察工作 带头遵守各项规章制度,激励全员工作热情 激励员工努力完成当前工作目标,不断强化完成战略目标的信心与决心 出席各类员工表彰大会 在充分尊重直属下属的前提下,对各类大小事务的最终决断权 职责: 给企业一个交代:公司投资人回报收益规划 给跟你干的人一个交代:企业个人人均收入规划,优秀员工收入规划 给社会一个交代:老百姓如何花更少的钱,得到更好的服务产品

让员工的工作状态更好,更开心,更享受这份工作 让员工在这里能更快的成长,更快的能够在管理,专业技能,执行力等方面快速提高 让员工更好的体会到创业精神:艰苦、热情等拼搏精神;相互关爱,帮助等团队精神;组织,管控,梦想等职业精神 让投资者获得收益的同时,享受到行业的认可,社会的尊重,消费者的赞扬 让同行佩服 让消费者满意,百分百满意 具体工作:(战略,指示直接下属,视察越级下属,重点问题指挥,) 制定企业各阶段,各个方向的目标,制定战略规划 规划及分配各项资源,并审批各种计划方案指导实施以完成目标 激励各阶层领导及全员的工作热情 亲身进行基础视察与调研,根据情况的严重程度对重点问题进行直属或者越级问责;对好人好事及时进行嘉奖和表彰

关于完善公司组织架构优化管理流程的建议

关于完善公司组织架构优化管理流程的建议 整体思路: 组织架构设计,应该是在公司经营目标的基础上,考虑经营环境等的影响,充分利用公司资源,确定公司的职能模块,选择适用的组织模式,实现岗位的合理设置,确定组织架构,运用业务流程检验完善组织架构。 原则:精简高效、专业分工、责权对等、执行与监督分设、客户服务导向及流程管理导向适应公司未来的健康高速发展 目标:建立完善的组织架构,明确三级管理的岗位职责 推行标准化、规范化管理制度,(后期有必要贯彻ISO9001标准) 重视业务培训,提高管理人员素质 加大教训总结力度 加强职业道德、职业精神教育 一、企业现有组织经营管理问题: 企业组织架构的设置,应该强调管理职能的有效行使和管理流程的顺畅高效。通过近段时间的调研,发现公司现有的组织架构存在以下问题: 1、基础管理体系不完善、节点不清晰、职责不明确。在现阶段弊端尚未完全显现,但在公司生产基地投产运行后,将会导致公司整体运营不顺畅,不能实现公司期望的达成目标,对公司战略目标的实现缺少有效支撑。 2、从目前组织机构看,许多部门空缺(办公室、人力部、市场部、研发部),导致公司相关人员多头管理,职责不明,无法有效的进行系统工作的推进,造成关键职能弱化甚至缺失,不能体现“精简高效、专业分工、责权对等、执行与监督分设、客户服务导向及流程管理导向”的基本原则。 3、缺少公司整体资源配置、组织的管理职能,尤其是综合计划管理、人力资源管理基本缺失。 4、无技术研发部门,没有符合企业发展要求的设计研发师。目前仅仅停留在模仿阶段,模仿出来的东西缺乏市场竞争力。企业新品设计规划缺。 5、营销系统的指挥、调度、监管、策划人员严重缺失。营销系统的销售部虽然存在,但市场部缺失,因为缺乏管理人员,职能工作全部由营销副总来负责。营销副总深陷日常职能工作之中,无法对产品的产品定位、市场定位、渠道选择等营销战略工作进行有效的规划与实施。

公司组织架构调整流程

公司组织架构调整流程
1.组织架构调整流程与风险控制图 组织架构调整流程与风险控制 不相容责任部门/责任人的职责分工与审批权限划分 业务风险
董事会 总经理 总经办 人力资源部 相关部门
阶 段
如果现有组织架构存 在缺陷,就会影响组 织的运行效率 参与评估
开始 1 组织架构运行 效果评估 2 参与 D1
如果组织架构调整方 案不符合企业自身特 点及实际情况,就会 影响企业运作效率 审批 审核
提出建议
征求相关人员 的建议 3 编制《组织架构 调整方案》
提出建议 D2
如果新的《组织架构 图》 《业务流程图》 、 、 《岗位说明书》等文 件编制混乱,就会影 审批 响企业经营活动的顺 利开展;如果新的组 织架构运行得不到企 业内部员工的积极支 持,也会影响企业经 营目标的实现 审核
发布 《组织架构 调整方案》 4 编制《组织架构 图》《业务流程 、 图》《岗位职责 、 说明书》
组织架构调整 及人员任命 5 新的组织架构 运行效果分析
D3
结束

2.组织架构调整流程控制表 组织架构调整流程控制
控制事项 详细描述及说明 1.人力资源部应当定期对组织架构设计与运行的效率及效果进行全面评估。组织架构运 D1 行效果评估的内容主要包括现有组织架构是否有利于企业战略目标的实现、是否与企 业内部主导业务流程相符、是否满足企业内部高效管理的要求
阶 段 控 制 D2
2.组织架构在调整之前应广泛征求董事、监事、高级管理人员和其他员工的意见 3.企业应根据组织架构设计规范对现有治理结构和内部机构设置进行全面梳理,确保其 符合现代企业制度要求;企业设置内部机构,应当重点关注内部机构设置的合理性和 运行的高效性等,一旦发现内部机构设置和运行中存在职能交叉或运行低效现象时, 应及时解决;企业《组织架构调整方案》应按规定权限和程序进行决策审批
4. 《组织架构图》《业务流程图》和《岗位说明书》等文件资料应按照统一的规范编写 、 D3 5.新的组织架构运行时,应及时查找运行中存在的问题和缺陷,以便进一步改进和优化
相 关 规 范
应建 规范
? 《组织架构设计规范》 ? 《岗位说明书编写规范》 ? 《企业内部控制应用指引》 ? 《中华人民共和国公司法》 ? 《组织架构图》
参照 规范
文件资料
? 《业务流程图》 ? 《岗位说明书》
责任部门 及责任人
? 人力资源部、相关部门 ? 总经理、人力资源部经理、相关部门负责人

公司组织架构管理制度

公司组织架构管理制度

一、部门核心职责 填写说明: 请描述本部门在公司层面所承担的核心业务方面职责、与公司其他职能部门协作及对所负有的主要管理、协调职能。 (一)职责一: (二)职责二: (三)职责三: (四)职责四: ………… 二、部门组织架构 填写说明: 请绘制本部门组织结构图(现有班组或模块、下设岗位)及人员配置编制。部门可根据自身对部门核心职能的理解提出组织结构及岗位设置、编制设想,具体设置及标准待人力资源部完成“三定”工作并报请公司领导批准后再行确定。 (一)部门组织结构图 (二)岗位编制

三、各相关岗位工作说明书 填写说明: (1)请对部门设置的每一岗位职责进行描述或归纳,例如xxx部经理岗位、xxx部xx主管岗位、xxx 部xx专员岗位等。您可以对相关岗位职责归纳也可以描述核心工作内容。 (2)结合部门专业要求,请您对相关岗位任职资格提出标准或要求,您所提供的标准或要求不作为现阶段招聘或人员配置依据,具体标准及要求依据“三定”后报经领导批示文件为准。 岗位工作说明书

四、需要建立的制度(规定、流程、办法)(可只填名称) 填写说明: 请结合公司要求,考虑您所在部门业务模块需要出台的的管理制度(规定、流程、办法),例如外派人员管理制度、会议制度、项目合同管理制度等,以及您部门内管理制度及业务流程,例如招聘流程、财务报销流程等。 (一)公司层面制度 1、 2、 3、 …… (二)部门层面制度 1、 2、 3、 ……

示例:集团人力资源部(仅为形式示例)一、部门核心职责 职责一:负责集团成熟人才及所需大学生后备人员招聘管理工作; 职责二:指导子公司人力资源部开展招聘工作; 职责三:新开分店班子搭配; 职责四:负责集团干部考核与选拔工作; 职责五:负责集团员工关系管理工作; 职责六:负责集团员工职业发展规划引导、培训管理工作; 二、部门组织架构 (一)部门组织结构图 (二)岗位编制

组织架构调整管理制度(新)

XXXXX有限公司 组织架构调整管理制度 第一章总则 第一条为了加强公司的组织及部门架构设置的规范性,确保组织架构满足公司战略的发展要求,保障公司的正常运营,特 制定本办法。 第二条组织架构调整原则 1.反映公司战略:反映公司的五年发展战略定位及经营目 标; 2.体现业务流程:按流程进行专业分工; 3.明确各自职责:部门、个人职责界定清晰; 4.提高运作效率:扁平化,有效授权,减少责任重叠。 第三条组织架构包括两个层面:公司架构和部门架构。 1.公司架构:为保证公司战略目标的达成而设置的部门; 2.部门架构:为保证部门职能目标的达成而设置的岗位及 其相互关系。 第二章组织架构调整 第四条公司架构调整依据 正常情况下,每年对组织架构进行一次回顾,当遇到以下情况时,可以进行调整: 1.公司战略目标发生变化、业务发生重大转型、经营环境

发生剧烈变化及发生并购、重组等情况; 2.公司因生产经营需要进行的业务流程再造、管理创新、 新技术引进及裁减人员等情况; 3.其他需要调整组织架构的因素出现。 第五条公司架构调整的责任部门与流程 ?总经理:公司架构调整的审核者,主要监督公司架构运行情况。 ?办公室:公司架构调整的实施机构,主要职责包括: 收集、整理、分析公司架构运营情况中存在的问题,并 提交专项报告,为上级提供决策依据;并根据总经理提 出的公司架构调整建议,撰写公司架构调整的文本文件; 组织开展公司架构调整工作。 第六条各部门架构调整依据 正常情况下,部门架构根据公司架构调整进行同步调整,但 是当遇到以下情况时,可临时进行调整: 1.部门职能发生变化; 2.国家政策、市场环境等因素发生重大变化导致岗位职责 发生变化; 3.其他需要调整的情况。 第七条各部门架构调整的责任部门与流程 ?总经理:部门架构调整的决策者,主要对部门架构调整做出最终决策。 ?办公室:部门架构调整的审核机构及组织机构,主要

公司组织管理体系的管理办法

******建设有限责任公司 组织体系与管理文件的管理办法 第一章总则 第一条为了规范总公司与各部门各子公司之间的组织管理,更高效地实现公司战略目标和各项经营目标,进一步明确股东大会、监事会、董事会、经营层和企业内部各层级机构设置、职责权限、工作程序,特制定本制度。 第二章公司组织架构 第二条公司按照有关规定设有股东大会、监事会、董事会、经营层和职能机构。 第三条股东大会由全体股东组成,是公司的权力机构。按照《公司章程》和《股东大会议事规则》的有关规定履行其相关权限。 第四条监事会由5名监事组成。监事会按《公司章程》和《监事会议事规则》的有关规定产生并履行其相关权限。 第五条董事会由7名董事组成。董事会按《公司章程》和《董事会议事规则》的有关规定产生并履行其相关权限。 第六条经营层由总经理及其他高级管理人员组成,经营层按《公司章程》和《总经理及高级管理人员职责与工作细则》的有关规定产生并履行其相关权限。 第七条职能部门的设置。公司根据业务发展需要合理设置职能部门。公司职能部门的设置及职责由公司董事会确定。 第三章组织架构的运行机制 第八条公司应当制定组织结构图、业务流程、职位说明书、绩效考核办法和

权限指引等内部管理制度或相关文件,使员工了解和掌握组织架构设计及权责分配情况,正确履行职责。 第九条公司应不断梳理企业治理结构,完善决策、执行和监督职能,重点关注: 1、董事会是否按时定期或不定期召集股东大会并向股东大会报告;是否严格认真地执行股东大会的所有决议;是否合理地聘任或解聘总经理及其他高级管理人员等。 2、监事会是否按照规定对董事、高级管理人员行为进行监督;在发现违反相关法律法规或损害公司利益时,是否能够对其提出罢免建议或制止纠正其行为等。 3、经营层是否认真有效地组织实施董事会决议;是否认真有效地组织实施董事会制定的年度生产经营计划和投资方案;是否能够完成董事会确定的生产经营计划和绩效目标等。 4、在重点关注过程中一经发现问题,将及时按规定的权限和程序进行调整。第十条公司应不断完善内部机构设置,根据公司战略发展,进行内部职能架构的优化调整。 第十一条公司不定期对组织架构设计与运行的效率和效果进行评估,发现组织架构设计与运行过程中存在职能交叉、缺失或不清晰的,应当及时进行优化调整。公司组织架构调整应当充分听取董事、监事、高级管理人员及其他员工的意见,并按照规定的程序由董事会进行审批。 第十二条公司建立《子公司管理制度》,通过合法有效的形式履行出资人职责、维护出资人权益,关注子公司的发展战略、年度财务预决算、重大投融资、重大担保、大额资金使用、主要资产处置、重要人事任免、内部控制体系建设

QEHS一体化管理体系组织结构及职能分配对照表

部门职责: (一)综合部 1、负责公司的行政及后勤管理 2、负责公司的人力资源管理 3、负责公司的计划管理 4、负责公司的财务管理 5、负责公司办公用品、行政后勤用品的采购管理 6、内、外部文件的管理 7、负责文件的分发、回收 8、负责规定质量记录保存年限及记录的管理 (二)技术部 1、负责公司的工艺技术管理 2、负责公司的设计管理 3、负责公司的研发管理 4、负责公司的检化验管理,管辖试验室、化验室 5、负责监视和测量设备的管理 6、负责原辅材料、半成品、成品的检验。 7、负责本部门环境因素、危害源辩识的识别、评价。(三)工程部 1、负责公司项目的实施 2、负责项目所需设备(含非标设备)、材料的米购 3、负责项目的投标活动 4、负责项目的预决算 5、负责项目的售后服务 6、负责本部门环境因素、危害源辩识的识别、评价。(四)经营部 1、负责公司产品的销售 2、负责开拓污水处理项目市场

3、负责市场调研 4、负责组织合同的评审、签订 5、负责外部的沟通 6、负责本部门环境因素、危害源辩识的识别、评价。 (五)工程部 1、负责膜材料的生产及完善 2、负责膜组件的生产及研发 3、负责新型膜材料的研发 4、负责膜材料、膜组件生产所需原材料的采购管理 5、负责生产设备的管理 6、负责车间环境因素的识别和危险源辩识。 (六)总经理 a)制定公司的发展规划与本年度应完成的各项工作指标; b )主持公司的全面工作,对生产经营、工程质量、财务状况、安全工作负责; c)组织、领导公司各职能部门编制,制定建筑公司发展规划及实施细则与具体工作方案; d)根据市场的竞争法则,建立统一、高效的组织管理体系; e)建立企业激励机制,弘扬企业文化,为员工搭建施展才能的平■台; f)确保公司内各层次的职责和权限得到规定,负责公司人事任免、劳动报酬、奖惩的决定;并在公司内部得到有效的沟通; g)主持制定公司管理方针,审批颁布公司《管理手册》,主持公司管理体系管理评审,承担公司管理体系的建立、完善、实施和保持的决策责任; h)接受员工所提出的各种合理化意见、建议。形成具有科学决策、民主管理等特点的现代化企业管理模式。 (七)副总经理 a)负责公司日常工作,监管财务资金合理流向,使公司管理逐步实现科学化、规范化、制度化; b)组织职工进行业务学习,检查、考核落实公司各项规章制度的执行; c)负责公司各种会议、各种活动的筹备、组织、安排工作; d)负责公司的对外联络、接待工作,安排好活动日程和生活; e)负责公司总经理办公会议决定的事项监督落实; f)负责完成总经理交办的其它各项工作。 g)组织、指导各主管部门的环境、职业健康安全管理体系有效运行控制; (八)总工程师 a)在公司经理的领导下,负责生产经营、质量安全、工程部的工作

公司组织架构管理制

公司组织架构管理制度1 管理制度标题:公司组织机构管理制度 编号:ZZJG-001 版次:A/0 发布日期: 制定: 审核: 顾问: 批准: XXXX有限公司(管理部) XX年XX月 公司组织机构管理制度 1、目的:为了更好的完善企业管理工作,明确企业管理组织程序,达到提高企业经营效率的目的。 2、范围:本制度规范了公司组织机构的管理模式、功能、程序,部门和岗位设置、职责等,适用于企业内部的管理运作。 3、职责 3.1公司组织管理制度由管理部负责制定,管理部负责根据公

司的发展需要,对公司组织机构进 行制定、修改、发放、检查,并根据组织机构的设置,制定各部门的职责及岗位职责,以及工作流程等。 3.2其他部门配合综合部做好公司组织机构的管理工作,并根据组织机构所规定的部门职责及 岗位职责的要求做好本职工作。 4、组织机构管理办法 4.1 组织机构图 4.2 组织机构设置 4.2.1公司组织管理在总经理的领导下,设立总经理负责制。 4.2.2公司组织管理层分为高层、中层、基层三个层次。 4.2.3管理程序分别为总经理、副总经理。 4.2.4根据组织机构管理原则下设岗位及部门为: ①高层:总经理、副总经理。 ②中层:部门主管。 ③部门:管理部、技术研发部、工程项目部、工程维护部、业务部。 4.2.5 部门设置的功能:

①管理部:负责建立公司的各项行政管理制度,并对各项管理制度实施情况进行检 查。根据公司目前的管理要求,公司行政事务及财务、仓库、合同管理等统一由管理部管理。 ②技术研发部:负责公司技术研发。 ③工程维护部:负责公司产品的维护,退换货及客诉的处理。 ④工程项目部:负责公司项目的安装指导、调试,下设调试和设计。 ⑤业务部:负责公司项目的业务开拓和应收账款的追踪,分业务员和业务助理。 5、部门职责、岗位职责 5.1总经理职责 5.1.1负责公司全面经营管理工作; 5.1.2制订公司发展规划,组织实施公司经营计划和投资方案; 5.1.3组织实施公司内部人事、财务经营管理的设置方案; 5.1.4组织实施公司章程; 5.1.5公共社会关系处理; 5.1.6负责公司采购管理工作;

6 现场组织机构及管理体系、技术力量配备

六、现场组织机构及管理体系、 技术力量配备

目录 1现场组织机构及管理体系 (3) 1.1 现场项目组织管理体系 (3) 1.2各岗位职责 (4) 2项目管理部 (5) 2.1 项目管理部设备配置 (5) 2.2 项目管理部职责 (5) 3主要管理人员配置 (6) 3.1 项目主要管理人员配置表 (6) 3.2 主要管理人员简介 (7)

1 现场组织机构及管理体系 1.1 现场项目组织管理体系 针对本工程的工程规模及工程特点,本着有利于施工组织管理的原则,组建现场项目管理部,组成矩阵式施工管理体系,实行项目经理负责制,全面履行合同。项目施工组织机构见下图: 如上图,项目部将配员27人,设置项目经理、项目付经理、总工程师等职务。根据本工程共有7个分项工程,每个分项工程专业不同的特点,设置7个分项的负责人,每个分项负责人另配备2名技术人员,组成分项工程小组。项目经理部另设置相应的职能部门。 本工程地处上海,本投标人又是本地企业,因此,本投标人公司本部的软件部和系统方案部将参与本工程的联合设计和应用软件的开发,保证本工程系统先进性。我们将派出精干队伍,由具有丰富经验的高级工程师担任项目经理;下属

多位具有丰富工程实施经验的软硬件工程人员组成阵容强大的专业团队,具体负责该项目的实施。参加本工程实施的主要人员都为本公司的技术骨干,具有在本行业丰富的技术经验。 1.2各岗位职责 1.2.1项目经理 项目经理是我们集团公司承包工程项目中的授权代表,由公司法人代表任命,行使并承担工程承包合同方的权利和义务。项目经理负责按合同规定的承包工作范围、内容和约定的建设工期、质量标准、费用限额全面完成项目建设任务。项目经理部按照我们公司的制度和授权,全面组织主持项目经理部的工作。在工程项目中代表我们公司与业主和监理工程师联系,在合同条款、我公司规定的范围内对承包的工程实施全面的负责,严格履行合同或协议,维护本投标人的信誉和利益。确定项目工作分解结构、组织分解机构、组建项目经理部,决定项目经理部组织机构和组织形式、任命主要成员,有效地开展项目管理工作。确定项目实施的基本工作方法和程序、组织编制项目计划,明确项目的总体目标和阶段目标,进行目标分解,使各项工作协调进行,确保项目建设按合同要求完成。拟订与业主、监理工程师及我公司内外协调程序,建立与业主、监理工程师以及合作部门的协调关系,为项目实施创造良好的合作环境。适时进行项目决策,制定工作目标、标准程序、督促质量管理、财务管理、安全管理、行政管理等各项任务全面完成。建立并完善项目经理部内部及对外信息管理系统,包括会议和报告制度,保证信息交流畅通。定期向我公司领导和业主、监理工程师及有关主管部门汇报工程进展情况,以便使问题得到处理和解决。工程竣工后,组织工程交接、试运行考核、财务结算等工作,办理工程验收的正式文件。做好项目总结和文件、资料的整理归档工作,提交项目完工报告。 1.2.2总工程师 负责高速公路系统方案的制定,具体组织编制施工组织设计和施工方案,执行合同中有关规范和现行国家标准,组织编制质量计划,制定工程技术管理体系,随时检查施工组织设计和施工方案的执行情况,如有偏差及时进行调整,同时解决施工中出现的问题,确保总体技术指标达到初步设计要求。

组织架构调整流程模板

组织架构调整流程 模板 1 2020年4月19日

第一章-HR01_组织架构调整流程 1.流程说明 该流程主要描述了依据企业目标策略的调整及业务环境需求的变化而重新确定组织架构时, 人力资源依照经核准的《组织系统图》在系统中修改或定义组织架构。 ●该流程主要涉及到的部门是总部人力资源, 其具有创立、修 改及显示的权限, 区公司及营业的人力资源只具有显示权限 ●创立组织架构包括: 创立组织单元、职位、分配成本中心; 组织单元与组织单元之间的关系是: 一对一或一对多, 组织 单元与职位之间的关系是: 一对一或一对多; 即一个组织单 元下可建一个或多个组织单元, 也可建一个或多个职位。由 于在业务中财务需要对各个组织单元、人员的成本费用进 行成本核算, 因此需要给组织单元分配成本中心, 或给职位 分配成本中心, 便于同财务的集成。组织单元的编码是由系 统外部给号, 由8位数字构成, 分成四层, 编码范围是 00000000~49999999, 例: 01000000~01009999用于总经理, 01010000~01019999用于策略, 0 000~49999999用于其它各 级组织单元。( 见附件三十四)

组织架构创立完后, 经过Graphic,打印出组织系统图 ( 参见报表样例”26组织系统图”) 2.流程图 3 2020年4月19日

3.系统操作 3.1.操作范例 3.1.1.创立 3.1.1.1.创立组织单元对象、关系 例1: 创立组织单元营业, 组织代码为1 000 例2: 创立组织单元销售行政, 组织代码为1 000 3.1.1.1.1. 系统菜单及交易代码 人力资源组织管理专家模式组织单位 交易代码: P010 4 2020年4月19日

组织机构体系与管理措施

目录 一、机构设置 (1) 二、机构人员组织与保证体系 (1) 三、项目部部门职责和权限 (2) 1、项目经理 (2) 2、项目生产经理职责 (2) 3、项目技术经理职责 (2) 4、工程技术组 (3) 5、质量安全组 (4) 6、材料组 (4) 7、综合办 (4) 五、工程进度计划与措施 (5) 1、管理措施 (5) 2、技术及组织措施 (5) 六、质量目标与保证措施 (6) 七、工程质量管理措施 (6) 八、施工技术管理措施 (8) 1、图纸的熟悉、审查的管理制度 (8) 2、施工组织设计制度 (8) 3、技术交底制度 (8) 4、材料检验制度 (8) 5、工程质量检查和验收制度 (9) 6、工程技术档案制度 (9) 7、技术复核制度 (9) 8、技术责任制 (9) 九、安全目标、安全保证体系与措施 (9) 1、安全管理目标 (9) 2、安全防护措施 (9) 3、安全保证措施 (10) 十、资源供应配备计划与管理措施 (13) 1、材料设备供应 (13) 2、材料工具管理 (13) 3、机械、设备管理措施 (14)

项目 组织机构与工程主要管理措施 一、机构设置 为了提高施工管理水平,本工程实行项目法施工。成立“项目工程项目部”,代表公司对本项目实施全方位管理。项目部管理机构设三部一办,各部室、施工队负责人由公司具有施工组织、管理和技术管理能力的骨干力量组成。同时,为了保证工程管理的延续性和有效性,本工程项目经理和项目管理人员在施工过程中始终坚持现场工作,不兼职,不调换。 二、机构人员组织与保证体系 1、组织结构分为公司和项目部两个阶层。公司对项目进行全面管理和指导,并设指挥长一人,对工程现场进行管理和对甲方、监理进行沟通,并做好上级领导安排的工作任务。 2、项目部在上级领导的安排下,主要负责工程的生产、进度、质量、安全文明施工等具体工作,对工程进行全面管理和施工,对工程总体的具体任务和目标进行实施,确保工程按照既定计划完成。 3、项目部组织机构

相关主题