Debian编译Ruby

1、首先要安装两个依赖项

#apt-get install zlib1g zlib1g-dev
#apt-get install libssl libssl-dev

2、然后下载Ruby源码
https://www.ruby-lang.org/en/

./configure --prefix=usr/ruby/ruby_2.2.3
make
make install

3、配置环境变量
编辑/etc/profile

export RUBY_HOME=/usr/ruby/ruby_2.2.3
export RUBYLIB=$RUBY_HOME/lib/ruby/2.2.0:$RUBY_HOME/lib/ruby/2.2.0/x86_64-linux:$RUBY_HOME/share/ri/2.2.0:$RUBYLIB
export PATH=$RUBY_HOME/bin:$PATH

更新环境变量

source /etc/profile

4、切换为国内源

gem sources --add https://ruby.taobao.org/
gem sources --remove https://rubygems.org/
gem sources -l

5、安装rails

$ gem install rails

Winform引用Activex控件

今天写了两个简单的Activex控件,一个用的MFC,一个用的ATL

用MFC的控件,编译后,直接引用就可以使用了。

用ATL写的控件,编译后,可以添加到VC程序中使用,但在WinForm程序中不可以使用,从工具箱拖拽到form后会报下面的错误:

Failed to create component 'AxHost'.  The error message follows:
 'System.InvalidOperationException: Unable to initialize component.
   at System.Windows.Forms.AxHost.DepersistControl()
   at System.Windows.Forms.AxHost.ActivateAxControl()
   at System.Windows.Forms.AxHost.TransitionUpTo(Int32 state)
   at System.Windows.Forms.AxHost.CreateHandle()
   at System.Windows.Forms.Control.CreateControl(Boolean fIgnoreVisible)
   at System.Windows.Forms.Control.CreateControl()
   at System.Windows.Forms.Control.ControlCollection.Add(Control value)
   at System.Windows.Forms.Form.ControlCollection.Add(Control value)
   at System.Windows.Forms.Design.ParentControlDesigner.AddChildControl(Control newChild)
   at System.Windows.Forms.Design.ParentControlDesigner.AddControl(Control newChild, IDictionary defaultValues)
   at System.Windows.Forms.Design.ControlDesigner.InitializeNewComponent(IDictionary defaultValues)
   at System.Windows.Forms.Design.AxHostDesigner.InitializeNewComponent(IDictionary defaultValues)'

查找了半天,有人说用AxImp.exe生产一个代理类可以解决这个问题。
尝试了SDK7.0,SDK7.1,SDK8.0,SDK8.1的AxImp.exe,可以成功生成dll,但是仍然没法使用。

也有人说,可以通过降低.NetFramework版本解决这个问题,2.0,3.0,3.5我都试了下,都不行。

试了VS2010和VS2013都不行,累了,回去了。。。

明天有空再弄吧。。。

今天试了一下,微软你大爷的,同样的操作,VS2008上(XP和Win7)就是好的。。。
真够坑爹啊。。。

再次测试表明:
1、VS2008的ATL控件在高版本的VS上可以插入到WinForm
2、VS2010以上的ATL控件,不能插入到VS2008以上任何版本的WinForm

VS2010以上的ATL控件,插入VS2008时,报的错误与上面不同

Debug Assertion Failed!
Program:.......
File:......vc\atlmfc\include\atlctl.h

Expression:pClientSite == 0 || m_spClientSite == 0

For information on how ....

微软,你自己的产品,兼容性做好一些,你能死啊。。。

ActiveX控件使用SDI特性(下)

放假回来,接着写:)

这两个类的使用步骤如下:
1、使用向导生成MFC ActiveX控件,(假设控件类为NControlCtrl)
2、工程中添加上面两个文件,ActivDoc.cpp和ActivDoc.h
3、将控件的基类,从COleControl换为CActiveXDocControl,在NControlCtrl.h中添加ActivDoc.h的引用
4、将NControlCtrl控件类中的COleControl全部替换为CActiveXDocControl
5、去掉NControlCtrl的OnDraw函数
5、将自己的Document类,View类,Frame类,添加到项目中,(假设为NDocument,NView,NFrame)
6、在NControlCtrl类中,添加NDocument,NView,NFrame的引用
7、在类的构造函数中,添加一行代码

	AddDocTemplate(new CActiveXDocTemplate(
		RUNTIME_CLASS(NDocument), 
		RUNTIME_CLASS(NMainFrame), 
		RUNTIME_CLASS(NView)));

8、这样SDI就可以用了。如果你原来的项目比较复杂的话,就要将资源文件进行拷贝及合并了,注意ID不要重复哦。

后记:
尝试了直接将NMainFrame进行分栏,但整个框架对于NDocument和NView比较依赖,会有报错。
最近比较忙,只好有空再搞下了。

Windows服务模板

最近写了几个Windows服务,整理了一下服务模板,以备以后使用。
说实话,这些代码是n年前写的了,用了也n久了,但还是发现了一个明显的bug。
其中,有些内容,写的并不好,如静态指针pThis,大家还是尽量不要使用了。

1、服务入口myXXX.cpp

//===================================================
//XXX入口函数

//===================================================
#include <windows.h>
#include <tchar.h>
#include <stdio.h>

#include "XXX.h"

//===================================================
//入口函数
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow)
{
	UNREFERENCED_PARAMETER(hInstance);
	UNREFERENCED_PARAMETER(hPrevInstance);
	UNREFERENCED_PARAMETER(nCmdShow);

	//获取可执行文件路径
	TCHAR szPath[MAX_PATH];
	TCHAR szLog[MAX_PATH];
	GetModuleFileName(NULL,szPath,MAX_PATH);

	//生成日志目录
	TCHAR *p = _tcsrchr(szPath, '\\');
	if(p!=NULL)*p='\0';
	if (_tcslen(szPath) + _tcslen(TEXT("Log\\")) <= MAX_PATH)
	{
		_stprintf_s(szLog, TEXT("%s\\%s"), szPath, TEXT("Log\\"));
	}
	else
	{
		return -1;
	}

	//判断运行参数
	XXX myService(szLog, true);
	myService.ParseParameters(lpCmdLine);

	return 0;
}

//===================================================

&#91;/code&#93;

2、服务类XXX.h
&#91;code lang="cpp"&#93;
//===================================================
//XXX 服务类封装
#include <windows.h>

//===================================================
//预定义
#define MAX_THREAD_COUNT 64

//===================================================
//XXX CLASS
class XXX
{
private:
	HANDLE	hSemaphore;
	CRITICAL_SECTION cs;

	bool		m_bLog;
	const		TCHAR	*m_szLogPath;
	LPCTSTR		lpServiceName;
	LPCTSTR		lpDisplayName;
	
	SERVICE_STATUS_HANDLE	gSvcStatusHandle;
	SERVICE_STATUS		gSvcStatus;
	HANDLE			ghSvcStopEvent;

	static	XXX	*pThis;
	bool	m_bFinished;

//构造与析构函数
public:
	XXX();
	XXX(const TCHAR *cLogPath,const bool bLog);
	~XXX();

//服务相关函数
private:
	static	void WINAPI ServiceMain(DWORD dwArgc,LPTSTR *lpszArgv);
	static	void WINAPI SvcCtrlHandler(DWORD dwCtrl);

	void	SvcInitAndRun(DWORD dwArgc,LPTSTR *lpszArgv);
	void	Show_Me_Err();

public:
	int		AddService();
	int		DelService();
	void	LogEvent(LPCTSTR lpMsg);
	void	ParseParameters(LPSTR lpCmdLine);
};

//===================================================

2、服务类XXX.cpp

//===================================================
//XXX服务类的封装实现

//===================================================
//头文件
#include "XXX.h"

//===================================================
//静态成员
XXX *XXX::pThis = NULL;

//===================================================
//构造函数
XXX::XXX(const TCHAR *cLogPath,const bool bLog)
{
	hSemaphore=NULL;

	m_bLog=bLog;
	lpServiceName=TEXT("XXX");
	lpDisplayName=TEXT("XXX");

	ghSvcStopEvent=NULL;
	m_szLogPath=cLogPath;
	m_bFinished = false;

	pThis=this;
}

//===================================================
//析构函数
XXX::~XXX()
{
}

//===================================================
//入口函数
void XXX::ParseParameters(LPSTR lpCmdLine)
{
	//判断运行参数
	//设置SERVICE_TABLE_ENTRY
	SERVICE_TABLE_ENTRY DispatchTable[]=
	{
		{TEXT("XXX"),(LPSERVICE_MAIN_FUNCTION)ServiceMain},
		{NULL,NULL}
	};

	//处理输入参数
	if((0==_stricmp(lpCmdLine,"/i")) || 0==_stricmp(lpCmdLine,"-i"))
	{
		//安装服务"/i -i"
		AddService();
		return;
	}
	else if((0==_stricmp(lpCmdLine,"/u")) || 0==_stricmp(lpCmdLine,"-u"))
	{
		//删除服务"/u -u"
		DelService();
		return;
	}
	else if((0==_stricmp(lpCmdLine,"/h")) || 0==_stricmp(lpCmdLine,"-h"))
	{
		//提示运行参数"/h -h"
		MessageBox(NULL,TEXT(" Install Service  : -i /i\n UnInstall Service: -u /u"),TEXT("XXX"),MB_OK);
		return;
	}
	else
	{
		//设置调试断点
		//DebugBreak();

		//StartServiceCtrlDispatcher运行服务
		if(!StartServiceCtrlDispatcher(DispatchTable))
		{
			LogEvent(TEXT("XXX: Failed To Start!"));
		}
		else
		{
			LogEvent(TEXT("XXX: Started!"));
		}
	}

	return;
}

//===================================================
//添加服务
int XXX::AddService()
{
	//SCMD与Service的句柄
	SC_HANDLE	hSCManager=NULL;
	SC_HANDLE	hService=NULL;

	//连接到SCM,打开SCMD
	hSCManager=OpenSCManager(NULL,NULL,SC_MANAGER_CREATE_SERVICE);
	if(NULL==hSCManager)
	{
		MessageBox(NULL,TEXT("OpenSCManager Failed"),TEXT("XXX"),MB_OK);
		Show_Me_Err();
		return 1;
	}

	//检查服务是否安装
	hService=OpenService(hSCManager,lpServiceName,SERVICE_ALL_ACCESS);
	if(NULL==hService)
	{
		//若服务不存在,创建服务
		TCHAR szFilePath[MAX_PATH];
		GetModuleFileName(GetModuleHandle(NULL),szFilePath,MAX_PATH);

		//自动启动
		hService=CreateService(hSCManager,lpServiceName,lpDisplayName,SERVICE_ALL_ACCESS,
				SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS,
				SERVICE_AUTO_START,SERVICE_ERROR_NORMAL,szFilePath,NULL,NULL,NULL,NULL,NULL);

		if(NULL==hService)
		{
			MessageBox(NULL,TEXT("CreateService Failed"),TEXT("XXX"),MB_OK);
			Show_Me_Err();
			CloseServiceHandle(hSCManager);
			return 1;
		}
	}
	else
	{
		MessageBox(NULL,TEXT("Service Already Installed!"),TEXT("XXX"),MB_OK);
		CloseServiceHandle(hService);
		CloseServiceHandle(hSCManager);
		return 1;
	}

	//关闭句柄
	CloseServiceHandle(hService);
	CloseServiceHandle(hSCManager);

	LogEvent(TEXT("XXX: AddService Successed!"));
	//ForDebug
	//MessageBox(NULL,TEXT("AddService Successed!"),TEXT("XXX"),MB_OK);
	return 0;
}

//===================================================
//删除服务
int XXX::DelService()
{
	//SCMD与Service的句柄
	SC_HANDLE	hSCManager=NULL;
	SC_HANDLE	hService=NULL;
	SERVICE_STATUS	ServiceStatus;

	//获取SCM句柄,打开SCMD
	hSCManager=OpenSCManager(NULL,NULL,SC_MANAGER_CREATE_SERVICE);
	if(NULL==hSCManager)
	{
		MessageBox(NULL,TEXT("OpenSCManager Failed"),TEXT("XXX"),MB_OK);
		Show_Me_Err();
		return 1;
	}

	//打开服务句柄
	hService=OpenService(hSCManager,lpServiceName,SERVICE_ALL_ACCESS|DELETE);
	if(NULL==hService)
	{
		MessageBox(NULL,TEXT("OpenService Failed"),TEXT("XXX"),MB_OK);
		Show_Me_Err();
		CloseServiceHandle(hSCManager);
		return 1;
	}

	//查询服务状态
	if(0==QueryServiceStatus(hService,&ServiceStatus))
	{
		MessageBox(NULL,TEXT("QueryServiceStatus Failed"),TEXT("XXX"),MB_OK);
		Show_Me_Err();
		CloseServiceHandle(hService);
		CloseServiceHandle(hSCManager);
		return 1;
	}
	else
	{
		//如果服务正在运行,则停止
		if(SERVICE_STOPPED!=ServiceStatus.dwCurrentState)
		{
			if(0==ControlService(hService,SERVICE_CONTROL_STOP,&ServiceStatus))
			{
				MessageBox(NULL,TEXT("ControlService Failed"),TEXT("XXX"),MB_OK);
				Show_Me_Err();
				CloseServiceHandle(hService);
				CloseServiceHandle(hSCManager);
				return 1;
			}
		}

		//删除服务
		if(0==DeleteService(hService))
		{
			MessageBox(NULL,TEXT("DeleteService Fialed!"),TEXT("XXX"),MB_OK);
			Show_Me_Err();
			CloseServiceHandle(hService);
			CloseServiceHandle(hSCManager);
			return 1;
		}
	}

	CloseServiceHandle(hService);
	CloseServiceHandle(hSCManager);

	LogEvent(TEXT("XXX: DelService Successed!"));
	//ForDebug
	//MessageBox(NULL,TEXT("DelService Successed!"),TEXT("XXX"),MB_OK);
	return 0;
}

//===================================================
//服务入口函数
void WINAPI XXX::ServiceMain(DWORD dwArgc,LPTSTR *lpszArgv)
{
	//注册服务控制程序
	pThis->gSvcStatusHandle=RegisterServiceCtrlHandler(pThis->lpServiceName,SvcCtrlHandler);
	if(0==pThis->gSvcStatusHandle)
	{
		//注册失败,返回
		pThis->LogEvent(TEXT("XXX: RegisterServiceCtrlHandler Failed"));
		return;
	}

	//设置服务状态SERVICE_START_PENDING
	pThis->gSvcStatus.dwServiceType=SERVICE_WIN32_OWN_PROCESS;
	pThis->gSvcStatus.dwCurrentState=SERVICE_START_PENDING;
	pThis->gSvcStatus.dwControlsAccepted=0;
	pThis->gSvcStatus.dwWin32ExitCode=NO_ERROR;
	pThis->gSvcStatus.dwServiceSpecificExitCode=0;
	pThis->gSvcStatus.dwCheckPoint=0;
	pThis->gSvcStatus.dwWaitHint=10000;
	SetServiceStatus(pThis->gSvcStatusHandle,&(pThis->gSvcStatus));

	//运行服务函数
	pThis->SvcInitAndRun(dwArgc, lpszArgv);

	//停止服务
	pThis->gSvcStatus.dwCurrentState=SERVICE_STOPPED;
	pThis->gSvcStatus.dwWaitHint=0;
	pThis->gSvcStatus.dwControlsAccepted=SERVICE_ACCEPT_STOP;
	pThis->gSvcStatus.dwCheckPoint=0;
	SetServiceStatus(pThis->gSvcStatusHandle,&(pThis->gSvcStatus));
}

//===================================================
//服务函数
void XXX::SvcInitAndRun(DWORD dwArgc,LPTSTR *lpszArgv)
{
	UNREFERENCED_PARAMETER(dwArgc);
	UNREFERENCED_PARAMETER(lpszArgv);

	//创建事件
	ghSvcStopEvent=CreateEvent(NULL,TRUE,FALSE,NULL);
	if(ghSvcStopEvent==NULL)
	{
		//创建事件失败,停止服务,返回
		gSvcStatus.dwCurrentState=SERVICE_STOPPED;
		gSvcStatus.dwWaitHint=0;
		gSvcStatus.dwControlsAccepted=SERVICE_ACCEPT_STOP;
		gSvcStatus.dwCheckPoint=0;
		SetServiceStatus(gSvcStatusHandle,&gSvcStatus);
		return;
	}

	//设置服务状态SERVICE_RUNNING
	gSvcStatus.dwCurrentState=SERVICE_RUNNING;
	gSvcStatus.dwWaitHint=0;
	gSvcStatus.dwControlsAccepted=SERVICE_ACCEPT_STOP;
	gSvcStatus.dwCheckPoint=0;
	SetServiceStatus(gSvcStatusHandle,&gSvcStatus);

	//设置断点
	while (!IsDebuggerPresent()) 
	{ 
		Sleep(100); 
	} 
	DebugBreak();

	//创建信号量
	hSemaphore=CreateSemaphore(NULL,MAX_THREAD_COUNT,MAX_THREAD_COUNT,TEXT("NAS_TEST_SEMAPHORE"));
	if(NULL==hSemaphore)  
	{
		return;
	}

	//初始化关键区
	InitializeCriticalSection(&cs);

	//处理请求
	while(!m_bFinished)
	{
		//进入关键区
		EnterCriticalSection(&cs);
		while (!m_bFinished)
		{
			if(WAIT_TIMEOUT==WaitForSingleObject(ghSvcStopEvent,100))
			{
				//这里处理你的线程逻辑
				//每个线程启动的时候WaitForSingleObject占用一个信号量
				//线程退出时ReleaseSemaphore释放信号量

			}
			else
			{
				LogEvent(TEXT("XXX is gonging down."));
				m_bFinished = true;
			}
		}
		//退出关键区
		LeaveCriticalSection(&cs);

		if (!m_bFinished)
		{
			//等待线程0.2秒
			Sleep(200);
		}
	}

	//等待所有线程结束
	WaitForMultipleObjects(MAX_THREAD_COUNT, &hSemaphore, true, 10000L);
	//WaitForMultipleObjects(1,&hSemaphore,true,INFINITE);

	//释放信号量
	CloseHandle(hSemaphore);
	
	//释放关键区
	DeleteCriticalSection(&cs);

	return;
}

//===================================================
//服务控制函数
void WINAPI XXX::SvcCtrlHandler(DWORD dwCtrl)
{
	switch(dwCtrl)
	{
		case SERVICE_CONTROL_STOP:
			//设置服务状态SERVICE_ACCEPT_STOP
			pThis->gSvcStatus.dwCurrentState=SERVICE_STOP_PENDING;
			pThis->gSvcStatus.dwControlsAccepted=SERVICE_ACCEPT_STOP;
			pThis->gSvcStatus.dwCheckPoint=0;
			pThis->gSvcStatus.dwWaitHint=10000;
			SetServiceStatus(pThis->gSvcStatusHandle,&(pThis->gSvcStatus));
			//触发事件
			SetEvent(pThis->ghSvcStopEvent);
			break;
		case SERVICE_CONTROL_PAUSE:
			break;
		case SERVICE_CONTROL_CONTINUE:
			break;
		case SERVICE_CONTROL_INTERROGATE:
			break;
		case SERVICE_CONTROL_SHUTDOWN:
			break;
		default:
			pThis->LogEvent(TEXT("XXX: Bad Service Request!"));
	}
}

//===================================================
//在事件查看器中记录消息
void XXX::LogEvent(LPCTSTR lpMsg)
{
	HANDLE	hEventSource;
	LPCTSTR	lpszStrings[1];

	lpszStrings[0]=lpMsg;

	//在“事件查看器->应用程序->信息”中进行记录
	hEventSource=RegisterEventSource(NULL,lpServiceName);
	if(NULL!=hEventSource)
	{
		ReportEvent(hEventSource,EVENTLOG_INFORMATION_TYPE,0,0,NULL,1,0,lpszStrings,NULL);
		DeregisterEventSource(hEventSource);
	}
}

//===================================================
//输出GetLastErr()信息
void XXX::Show_Me_Err()
{
	if(!m_bLog)return;

	DWORD	dwErrNo;
	LPTSTR	lpBuffer;
	dwErrNo=GetLastError();
	FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_IGNORE_INSERTS|FORMAT_MESSAGE_FROM_SYSTEM,
		NULL,dwErrNo,LANG_NEUTRAL,(LPTSTR)&lpBuffer,0,NULL);
	MessageBox(NULL,lpBuffer,TEXT("XXX GetLastError"),MB_OK);
	LocalFree(lpBuffer);
}

//===================================================

C#写WindowsService

1、新建一个Windows Service项目,重命名服务类名

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.ServiceProcess;
using System.Threading;

namespace ServiceTestCS
{
    public partial class ServiceTestCS : ServiceBase
    {
        //安装卸载时,最好用绝对路径哦
        //Installutil NASTestCS
        //Installutil -u NASTestCS

        private const int waitInterval = 200;
        private AutoResetEvent stopEvent = new AutoResetEvent(false);
        private AutoResetEvent pauseContinueEvent = new AutoResetEvent(false);
        private Thread workingThread = null;

        public NASTestCS()
        {
            InitializeComponent();
            this.CanPauseAndContinue = true;
            this.CanShutdown = true;
        }

        protected override void OnStart(string[] args)
        {
            #if DEBUG
            /*
            //等待调试器,但调试Windows服务时,提示没有加载符号
            while (!Debugger.IsAttached)
            {
                Thread.Sleep(waitInterval);
            }
            */
            Debugger.Launch();
            #endif

            workingThread = new Thread(new ThreadStart(MaiLoop));
            workingThread.Start();
        }

        protected override void OnStop()
        {
            stopEvent.Set();
        }

        protected override void OnShutdown()
        {
            stopEvent.Set();
        }

        protected override void OnPause()
        {
            pauseContinueEvent.Set();
        }

        protected override void OnContinue()
        {
            pauseContinueEvent.Set();
        }

        protected void MaiLoop()
        {
            Boolean bEnd = false;
            while (!bEnd)
            {
                //处理你的正常事务
                //但要保证下面的代码,可以定期被调用到
                //......

                //截获停止事件
                if(stopEvent.WaitOne(waitInterval))
                {
                    bEnd = true;
                    break;
                }

                //截获暂停事件
                if (pauseContinueEvent.WaitOne(waitInterval))
                {
                    //等待继续时间
                    while (!pauseContinueEvent.WaitOne(waitInterval))
                    {
                        //少占用一些资源
                        Thread.Sleep(waitInterval);

                        //暂停时也可以退出
                        if (stopEvent.WaitOne(waitInterval))
                        {
                            bEnd = true;
                            break;
                        }
                    }
                }
            }
        }
    }
}

2、服务设计界面右击,添加Service Installer
配置Service Installer,配置服务类名称,显示名称,启动类型,登录用户,服务依赖等
但如果要可以与桌面交互的话,需要添加代码实现。
双击serviceInstaller,添加下面方法:

        using System.Management;

        private void serviceInstaller_AfterInstall(object sender, InstallEventArgs e)
        {
            //要用LocalSystem用户登录才有效哦
            ManagementObject wmiService = new ManagementObject(string.Format("Win32_Service.Name='{0}'", this.serviceInstaller.ServiceName));
            ManagementBaseObject changeMethod = wmiService.GetMethodParameters("Change");
            changeMethod["DesktopInteract"] = true;
            ManagementBaseObject OutParam = wmiService.InvokeMethod("Change", changeMethod, null);
        }

3、安装与反安装,用命令行实现

rem 安装服务
%PATH_TO_INSTALLUTIL%\installutil.exe %PATH_TO_SERVICE%\NASTestCS.exe
rem 卸载服务
%PATH_TO_INSTALLUTIL%\installutil.exe -u %PATH_TO_SERVICE%\NASTestCS.exe

ActiveX控件使用SDI特性(上)

大家都知道,使用微软的MFC ActiveX控件向导生成的控件类,是基于COleControl的,而COleControl是基于CWnd类。这样很多MFC的特性,如CFrameWnd的特性,CSingleDocTemplate(SDI)的特性等就无法使用了。如果要把用到这些类的MFC程序封装为ActiveX插件,就会有不少麻烦。

其实这个问题,在上个世纪MFC诞生不久,就有人解决了,并提供了完整的示例代码。微软官方的这篇文章《Designing ActiveX Components with the MFC Document/View Model》,在原地址http://www.microsoft.com/mind/0497/mfc.asp已经无法找到了。

但好在这里还有完整的备份《Designing ActiveX Components with the MFC Document/View Model》

原文的作者,实现了CActiveXDocTemplate和CActiveXDocControl两个类,而用户只需要将控件的基类从COleControl换为CActiveXDocControl,并做简单修改,就可以方便的使用SDI的特性了。

整体思路其实是使用CActiveXDocControl扩展了COleControl。在CActiveXDocControl中,作者初始化了CDocManager,使用CActiveXDocTemplate控制了document、view、frame的生成,处理了OnSize事件,并使用Timer定时获取消息处理更新。

我们使用的时候,主要就是用这两个类,代码如下(两个类相互引用,所以放到了同一文件中):

1、ActivDoc.h

class CActiveXDocTemplate : public CSingleDocTemplate
{
    enum { IDR_NOTUSED = 0x7FFF };

    CWnd* m_pParentWnd;
    CFrameWnd* m_pFrameWnd;
    CString m_docFile;

public:
    CActiveXDocTemplate(CRuntimeClass* pDocClass,
        CRuntimeClass* pFrameClass, CRuntimeClass* pViewClass);

    CFrameWnd* CreateDocViewFrame(CWnd* pParentWnd);
    void SaveDocumentFile();

    virtual CFrameWnd* CreateNewFrame(CDocument* pDoc,
        CFrameWnd* pOther);
    virtual CDocument* OpenDocumentFile(
        LPCTSTR lpszPathName, BOOL bVerifyExists = TRUE);
};

//===================================================

class CActiveXDocControl : public COleControl
{
    enum { WM_IDLEUPDATECMDUI = 0x0363 };

    static BOOL m_bDocInitialized;
    CActiveXDocTemplate* m_pDocTemplate;
    CFrameWnd* m_pFrameWnd;

    DECLARE_DYNAMIC(CActiveXDocControl)

protected:
    void AddDocTemplate(CActiveXDocTemplate* pDocTemplate);
    CDocTemplate* GetDocTemplate() { return m_pDocTemplate; }

    //{{AFX_MSG(CActiveXDocControl)
    afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
    afx_msg void OnSize(UINT nType, int cx, int cy);
    afx_msg void OnTimer(UINT nIDEvent);
    afx_msg void OnDestroy();
    //}}AFX_MSG
    //{{AFX_DISPATCH(CActiveXDocControl)
    //}}AFX_DISPATCH
    //{{AFX_EVENT(CActiveXDocControl)
    //}}AFX_EVENT

    DECLARE_MESSAGE_MAP()
    DECLARE_DISPATCH_MAP()
    DECLARE_EVENT_MAP()

public:
    CActiveXDocControl();
    virtual ~CActiveXDocControl();

    enum {
    //{{AFX_DISP_ID(CActiveXDocControl)
    //}}AFX_DISP_ID
    };
};

2、ActivDoc.cpp

// ActivDoc.cpp : implementation file
//

#include "stdafx.h"
#include "ActivDoc.h"

CActiveXDocTemplate::CActiveXDocTemplate(CRuntimeClass* pDocClass,
    CRuntimeClass* pFrameClass, CRuntimeClass* pViewClass)
        : CSingleDocTemplate(IDR_NOTUSED, pDocClass, pFrameClass,
            pViewClass)
{
    ASSERT(pFrameClass);
}

CFrameWnd* CActiveXDocTemplate::CreateDocViewFrame(CWnd* pParentWnd)
{
    ASSERT(pParentWnd && IsWindow(*pParentWnd));
    ASSERT_KINDOF(CActiveXDocControl, pParentWnd);
    m_pParentWnd = pParentWnd;
    m_pFrameWnd = NULL;

    // OpenDocumentFile is a virtual method (implemented in
    // the CSingleDocTemplate base class) that creates
    // the document (either empty or loaded from the specified
    // file) and calls our CreateNewFrame function. Passing
    // NULL to the function creates a new document. Incidentally,
    // the view is created by the CFrameWnd's OnCreateClient()
    // method.

    if (!OpenDocumentFile(NULL))
        return NULL;

    // Since OpenDocumentFile sets m_pFrame, we can now use it.

    ASSERT(m_pFrameWnd);
    ASSERT_KINDOF(CFrameWnd, m_pFrameWnd);
    m_pFrameWnd->ShowWindow(SW_SHOWNORMAL);
    return m_pFrameWnd;
}

CFrameWnd* CActiveXDocTemplate::CreateNewFrame(CDocument* pDoc,
        CFrameWnd* pOther)
{
    ASSERT(pOther == NULL);
    ASSERT(m_pFrameClass != NULL);
    if (pDoc != NULL)
        ASSERT_VALID(pDoc);

    // Create a frame wired to the specified document

    CCreateContext context;
    context.m_pCurrentFrame = pOther;
    context.m_pCurrentDoc = pDoc;
    context.m_pNewViewClass = m_pViewClass;
    context.m_pNewDocTemplate = this;

    m_pFrameWnd = (CFrameWnd*)m_pFrameClass->CreateObject();
    if (m_pFrameWnd == NULL)
    {
        TRACE1("Warning: Dynamic create of frame %hs failed.\n",
            m_pFrameClass->m_lpszClassName);
        return NULL;
    }
    ASSERT_KINDOF(CFrameWnd, m_pFrameWnd);

    if (context.m_pNewViewClass == NULL)
        TRACE0("Warning: creating frame with no default view.\n");

    // The frame is created as a menu-less child of the
    // CActiveXDocControl in which it will reside.

    ASSERT_KINDOF(CActiveXDocControl, m_pParentWnd);
    if (!m_pFrameWnd->Create(NULL, "", WS_CHILD|WS_VISIBLE,
        CFrameWnd::rectDefault, m_pParentWnd, NULL, 0, &context))
    {
        TRACE0("Warning: CDocTemplate couldn't create a frame.\n");
        return NULL;
    }

    return m_pFrameWnd;
}

CDocument* CActiveXDocTemplate::OpenDocumentFile(
    LPCTSTR lpszPathName, BOOL bVerifyExists)
{
    SaveDocumentFile();
    m_docFile = lpszPathName;

    if (bVerifyExists)
    {
        DWORD dwAttrib = GetFileAttributes(m_docFile);
        if (dwAttrib == 0xFFFFFFFF ||
            dwAttrib == FILE_ATTRIBUTE_DIRECTORY)
        {
            lpszPathName = NULL;
        }
    }

    return CSingleDocTemplate::OpenDocumentFile(
        lpszPathName, TRUE);
}

void CActiveXDocTemplate::SaveDocumentFile()
{
    if (m_pOnlyDoc != NULL)
    {
        if (!m_docFile.IsEmpty())
            m_pOnlyDoc->OnSaveDocument(m_docFile);
        else
            m_pOnlyDoc->SetModifiedFlag(FALSE);
    }
}

//===================================================
// CActiveXDocControl

IMPLEMENT_DYNAMIC(CActiveXDocControl, COleControl)
BEGIN_MESSAGE_MAP(CActiveXDocControl, COleControl)
    //{{AFX_MSG_MAP(CActiveXDocControl)
    ON_WM_CREATE()
    ON_WM_SIZE()
    ON_WM_TIMER()
    ON_WM_DESTROY()
    //}}AFX_MSG_MAP
    ON_OLEVERB(AFX_IDS_VERB_PROPERTIES, OnProperties)
END_MESSAGE_MAP()
BEGIN_DISPATCH_MAP(CActiveXDocControl, COleControl)
    //{{AFX_DISPATCH_MAP(CActiveXDocControl)
    //}}AFX_DISPATCH_MAP
END_DISPATCH_MAP()
BEGIN_EVENT_MAP(CActiveXDocControl, COleControl)
    //{{AFX_EVENT_MAP(COleFrameCtrl)
    //}}AFX_EVENT_MAP
END_EVENT_MAP()

int CActiveXDocControl::m_bDocInitialized = FALSE;

CActiveXDocControl::CActiveXDocControl()
{
    m_pDocTemplate = NULL;
    m_pFrameWnd = NULL;

    // Since we're in an OCX, CWinApp::InitApplication() is
    // not called by the framework. Unfortunately, that method
    // performs CDocManager initialization that is necessary
    // in order for our DocTemplate to clean up after itself.
    // We simulate the same initialization by calling the
    // following code the first time we create a control.

    if (!m_bDocInitialized)
    {
        CDocManager docManager;
        docManager.AddDocTemplate(NULL);
        m_bDocInitialized = TRUE;
    }
}

CActiveXDocControl::~CActiveXDocControl()
{
    // Note that the frame, the document, and the view are
    // all deleted automatically by the framework!
    
    delete m_pDocTemplate;
}

void CActiveXDocControl::AddDocTemplate(CActiveXDocTemplate* pDocTemplate)
{
    // I've decided to call this function AddDocTemplate to
    // be consistent with naming of CWinApp::AddDocTemplate.
    // However, only one DocTemplate is allowed per control.
    
    ASSERT(pDocTemplate);
    ASSERT(m_pDocTemplate == NULL);
    m_pDocTemplate = pDocTemplate;
}

int CActiveXDocControl::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{
    if (COleControl::OnCreate(lpCreateStruct) == -1)
        return -1;

    // The CActiveXDocTemplate object will create the
    // document, the view, and the frame inside the
    // control. The reason we need a handle to the frame
    // is so that we can resize it when the control is
    // resized.
    
    ASSERT(m_pDocTemplate);    // Set in call to AddDocTemplate
    m_pFrameWnd = m_pDocTemplate->CreateDocViewFrame(this);
    ASSERT_KINDOF(CFrameWnd, m_pFrameWnd);

    // By default, we'll create the control with a border,
    // since it looks better for frames containing a toolbar.

    SetBorderStyle(TRUE);
    SetTimer(WM_IDLEUPDATECMDUI, 300, NULL);
    return 0;
}

void CActiveXDocControl::OnSize(UINT nType, int cx, int cy) 
{
    COleControl::OnSize(nType, cx, cy);

    // The CFrameWnd should always fill up the entire client
    // area of the control.

    if (m_pFrameWnd != NULL)
    {
        ASSERT(IsWindow(*m_pFrameWnd));
        CRect area;
        GetClientRect(area);
        m_pFrameWnd->MoveWindow(area.left, area.top, area.right,
            area.bottom);
    }
}

void CActiveXDocControl::OnTimer(UINT nIDEvent) 
{
    // Since we're in an OCX, we don't control the message loop,
    // so CWinThread::OnIdle is never called. That means we have
    // to periodically pump the ON_UPDATE_COMMAND_UI messages
    // by hand.
    
    SendMessageToDescendants(WM_IDLEUPDATECMDUI, TRUE);
    COleControl::OnTimer(nIDEvent);
}


void CActiveXDocControl::OnDestroy() 
{
    AfxGetApp()->m_pMainWnd = NULL;
    m_pDocTemplate->SaveDocumentFile();
    COleControl::OnDestroy();
}

困了,回去再写。。。

Build Jetty Lesson101

1. Download source code from Eclipse.
For example, I used this one:

From here: http://download.eclipse.org/jetty/
Get this one: jetty-8.1.15.v20140411

2. Read this:

http://docs.codehaus.org/display/JETTY/Building+from+Source

3. Prepare JDK and Maven:

SET JAVA_HOME=C:\Languages\Java\JDK\jdk_x86_1.6.0_34
SET MAVEN_HOME=C:\Languages\Java\JavaTools\apache-maven-3.0.4
SET PATH=%MAVEN_HOME%\bin;%JAVA_HOME%\bin;%PATH%
CMD

4. Run “mvn install”

5. Use eclipse to import maven project

Build Tomcat Lesson101

1. Download one source tag from Apache
For example, I used this tag:

http://svn.apache.org/repos/asf/tomcat/tc6.0.x/tags/TOMCAT_6_0_41

2. Read this:

http://tomcat.apache.org/tomcat-6.0-doc/building.html

3. Prepare JDK and Ant

SET JAVA_HOME=C:\Languages\Java\JDK\jdk_x86_1.6.0_34
SET ANT_HOME=C:\Languages\Java\JavaTools\apache-ant-1.9.0
SET PATH=%ANT_HOME%\bin;%JAVA_HOME%\bin;%PATH%
CMD

4. Copy build.properties.default to build.properties

5. Edit build.properties and set base.path

base.path=the path to store thirdpart libs

6. Run “Ant download”

7. Run “Ant”

8. Rename files

move eclipse.classpath .classpath
move eclipse.project .project

9. Use eclipse to import this project

10. Set break point and debug