关于vs2010 MFC Activex 控件开发
之前一直做C#,最近2周由于工作需要开始学习VC++ MFC ActiveX 制作控件。写一些最近遇到的问题,希望对大家有帮助。
使用工具 vs2010, 在安装的时候需要安装C++模块
我们要先创建一个MFC ActiveX项目,在新建项目页的左侧选择Visual C++ —— MFC,
在右侧选择MFC ActiveX 控件,
然后选择需要运行许可证,项目有需要的可以加,由于我们是公司内部使用所以就不加。跳到项目中所有页面的名称。一般不改直接点完成。
我们运行程序报错,
解决办法: 项目——属性——链接器——注册输出改成否——确定。再生成就没有错了。
打开类视图
下面这个很重要,不然做项目的时候会遇到各种类型转换,转换后值缺损。
项目——属性——常规
找到字符集,把"使用Unicode字符集"更改为"使用多字节字符集"
生成 regsvr32 C:\Users\ MFCTEST4\Debug\MFCTest4Ctrl.ocx win7用管理员权限打开运行即(cmd)。
为了其他人使用方便也可以把ocx放到C:\Windows\SysWOW64中集成脚本(bat文件)例:regsvr32 EBFTermManCtrl.ocx –s (具体还没有试过,不过可以执行是肯定的。)
添加方法
这是该控件类的外部接口,我们如果在外部需要访问这个方法就需要在这里面进行添加方法。
选中右击——添加——添加方法——添加参数(没有不填)——确定
内部名称就是控件内部的方法体如果只想添加控件内部使用的方法那么就只需要在类视图中的DMFCTEST4中右击——添加——添加方法 即可。
属性和方法的添加一样,就不做说明啦。
由于目前我没有找到好的MFC调试方法。网上说的啥添加测试工具是不可以单步调试的。所以我用2种方法调试。
1 添加记日志的组件,然后再载体上运行,查看日志
2 把代码移植到MFC应用程序上单步调试,不过也遇到了相对路径在应用程序可以到了控件程序就不行的情况。具体我还没有时间去细究。
这里就介绍下记日志吧
首先添加头文件LogTrace.h
代码如下
/********************************************************************
filename: LogTrace.h
author: Wang Qiang
created: 2010/08/04 16:26
purpose:
*********************************************************************/
#ifndef __LOGTRACE_H__
#define __LOGTRACE_H__
#define LOG_LEVEL_ERROR 0x0001 // (出错)
#define LOG_LEVEL_NORMAL 0x0002 // (正常)
#define LOG_LEVEL_DEBUG 0x0003 // (调试)
#define LOG_LEVEL_NOTIFY 0x0100 // 可以向指定窗口传递错误消息
#define WM_LOG_NOTIFY 0x0400 + 1011 // 通知界面错误信息
#define SINGLE_ID -1 // 只记录一个日志文件
// 日志输出类
class CLogTrace
{
public:
CLogTrace();
~CLogTrace();
protected:
// 日志通知窗口
HWND m_hNotifyWnd;
// 日志记录激活级别
int m_nActiveLevel;
// 指定日志目录
char m_szLogPath[MAX_PATH];
// Operations
// 以日期为文件夹,ID号为文件名记录日志
void TraceLine(int nLogLevel, int nID, LPCTSTR pszLine);
// 以日期为文件名记录日志
void TraceLineSingle(int nLogLevel, LPCTSTR pszLine);
// 输出字符串日志
void WriteString(int nLogLevel, int nID, LPCTSTR pszTipText, LPCTSTR pszStringData);
// 输出整型日志
void WriteInt(int nLogLevel, int nID, LPCTSTR pszTipText, int nIntData);
// 输出16机制数据日志
void WriteHex(int nLogLevel, int nID, LPCTSTR pszTipText, LPCTSTR pszHexData, int nLen);
public:
// 设置消息通知窗口
void SetNotifyWnd(HWND hWndNotify)
{
m_hNotifyWnd = hWndNotify;
}
// 设置日志记录警告等级
void SetActiveLevel(int nActiveLevel)
{
m_nActiveLevel = nActiveLevel;
}
// 设置日志输出目录
void SetLogPath(LPCTSTR pszPath)
{
memset(m_szLogPath, 0x00, sizeof(m_szLogPath));
strncpy(m_szLogPath, (LPSTR)(LPCTSTR)pszPath, sizeof(m_szLogPath));
}
// 输出格式化数据日志
void WriteFormatString(int nLogLevel, int nID, LPCTSTR pszFormat, ...);
//---------------------------------
// 函数重载
// 输出字符串日志
void WriteLog(int nLogLevel, int nID, LPCTSTR pszTipText, LPCTSTR pszStringData);
// 输出整型日志
void WriteLog(int nLogLevel, int nID, LPCTSTR pszTipText, int nIntData);
// 输出16机制数据日志
void WriteLog(int nLogLevel, int nID, LPCTSTR pszTipText, LPCTSTR pszHexData, int nLen);
};
#endif // __LOGTRACE_H__
添加LogTrace.cpp
代码如下:
/********************************************************************
filename: LogTrace.cpp
author: Wang Qiang
created: 2010/08/04 16:26
purpose:
*********************************************************************/
#include "stdafx.h"
#include <stdio.h>
#include <stdarg.h>
#include <io.h>
#include <direct.h>
#define DEFAULT_PATH ".\\DateLog"
CLogTrace::CLogTrace()
{
m_hNotifyWnd = NULL;
m_nActiveLevel = LOG_LEVEL_DEBUG;
}
CLogTrace::~CLogTrace()
{
}
// 输出字符串日志
void CLogTrace::WriteString(int nLogLevel, int nID, LPCTSTR pszTipText, LPCTSTR pszStringData)
{
WriteFormatString(nLogLevel, nID, (LPCTSTR)"%s=\"%s\"", pszTipText, pszStringData);
}
// 输出整型日志
void CLogTrace::WriteInt(int nLogLevel, int nID, LPCTSTR pszTipText, int nIntData)
{
WriteFormatString(nLogLevel, nID, (LPCTSTR)"%s=[%d]", pszTipText, nIntData);
}
// 输出16机制数据日志
void CLogTrace::WriteHex(int nLogLevel, int nID, LPCTSTR pszTipText, LPCTSTR pszHexData, int nLen)
{
int nBufLen = nLen * 3 + nLen / 16 + 1;
char * pszTemp = new char[nBufLen];
memset(pszTemp, 0x00, nBufLen);
char * ptrDest = pszTemp;
for(int i = 0; i < nLen; i++, pszHexData++)
{
sprintf(ptrDest,"%02X ",(*pszHexData) & 0xFF);
ptrDest += 3;
if((i + 1) % 16 == 0)
{
*ptrDest = '\n';
ptrDest++;
}
}
WriteFormatString(nLogLevel, nID, (LPCTSTR)"%s\n%s", pszTipText, pszTemp);
delete[] pszTemp;
}
void CLogTrace::WriteLog(int nLogLevel, int nID, LPCTSTR pszTipText, LPCTSTR pszStringData)
{
WriteString(nLogLevel, nID, pszTipText, pszStringData);
}
void CLogTrace::WriteLog(int nLogLevel, int nID, LPCTSTR pszTipText, int nIntData)
{
WriteInt(nLogLevel, nID, pszTipText, nIntData);
}
void CLogTrace::WriteLog(int nLogLevel, int nID, LPCTSTR pszTipText, LPCTSTR pszHexData, int nLen)
{
WriteHex(nLogLevel, nID, pszTipText, pszHexData, nLen);
}
void CLogTrace::WriteFormatString(int nLogLevel, int nID, LPCTSTR pszFormat, ...)
{
// 日志警告级别大于激活级别则不记录
if (nLogLevel > m_nActiveLevel)
{
return;
}
va_list args;
va_start(args, pszFormat);
int nLen = vsnprintf(NULL, 0,(char*)pszFormat, args);
char * pszArgs = new char[nLen + 1];
memset(pszArgs, 0x00, nLen);
vsprintf(pszArgs, (char*)pszFormat, args);
va_end(args);
if (SINGLE_ID == nID)
{
TraceLineSingle(nLogLevel, (LPCTSTR)pszArgs);
}
else
{
TraceLine(nLogLevel, nID, (LPCTSTR)pszArgs);
}
delete[] pszArgs;
}
// 以日期为文件夹,ID号为文件名记录日志
void CLogTrace::TraceLine(int nLogLevel, int nID, LPCTSTR pszLine)
{
char szFolder[32];
char szTime[16];
char szFile[MAX_PATH];
char szLevel[16];
memset(szFolder, 0x00, sizeof(szFolder));
memset(szTime, 0x00, sizeof(szTime));
memset(szFile, 0x00, sizeof(szFile));
memset(szLevel, 0x00, sizeof(szLevel));
char szTempPath[MAX_PATH];
memset(szTempPath, 0x00, sizeof(szTempPath));
strcpy(szTempPath,strlen(m_szLogPath)? m_szLogPath : DEFAULT_PATH);
SYSTEMTIME tmCur;
GetLocalTime(&tmCur);
sprintf(szFolder, "%s\\%04d%02d%02d", szTempPath
, tmCur.wYear, tmCur.wMonth, tmCur.wDay);
sprintf(szTime, "--%02d:%02d:%02d:%03d"
, tmCur.wHour, tmCur.wMinute, tmCur.wSecond, tmCur.wMilliseconds);
int nNotify = nLogLevel & 0xFF00;
if (LOG_LEVEL_NOTIFY == nNotify && m_hNotifyWnd != NULL)
{
::SendMessage(m_hNotifyWnd, WM_LOG_NOTIFY, (WPARAM)pszLine, (LPARAM)nID);
}
switch (nLogLevel & 0x00FF)
{
case LOG_LEVEL_ERROR:
{
strcpy(szLevel, "(出错)");
}
break;
case LOG_LEVEL_NORMAL:
{
strcpy(szLevel, "(正常)");
}
break;
case LOG_LEVEL_DEBUG:
{
strcpy(szLevel, "(调试)");
}
break;
default:
{
strcpy(szLevel, "");
}
}
// DateLog文件夹不存在
if (_access(szTempPath, 0) != 0)
{
return;
}
// 当日日志文件夹是否存在
if (_access(szFolder, 0) != 0)
{
_mkdir(szFolder);
}
sprintf(szFile, "%s\\%02d.log", szFolder, nID);
FILE * pFile = NULL;
pFile = fopen(szFile, "at");
if (NULL == pFile)
{
return;
}
fprintf(pFile,"%s %s %s\n", szTime, szLevel, pszLine);
fclose(pFile);
}
// 以日期为文件名记录日志
void CLogTrace::TraceLineSingle(int nLogLevel, LPCTSTR pszLine)
{
char szFolder[32];
char szTime[16];
char szFile[MAX_PATH];
char szLevel[16];
memset(szFolder, 0x00, sizeof(szFolder));
memset(szTime, 0x00, sizeof(szTime));
memset(szFile, 0x00, sizeof(szFile));
memset(szLevel, 0x00, sizeof(szLevel));
char szTempPath[MAX_PATH];
memset(szTempPath, 0x00, sizeof(szTempPath));
strcpy(szTempPath,strlen(m_szLogPath)? m_szLogPath : DEFAULT_PATH);
SYSTEMTIME tmCur;
GetLocalTime(&tmCur);
strcpy(szFolder, szTempPath);
sprintf(szTime, "--%02d:%02d:%02d:%03d"
, tmCur.wHour, tmCur.wMinute, tmCur.wSecond, tmCur.wMilliseconds);
int nNotify = nLogLevel & 0xFF00;
if (LOG_LEVEL_NOTIFY == nNotify && m_hNotifyWnd != NULL)
{
::SendMessage(m_hNotifyWnd, WM_LOG_NOTIFY, (WPARAM)pszLine, (LPARAM)0);
}
switch (nLogLevel & 0x00FF)
{
case LOG_LEVEL_ERROR:
{
strcpy(szLevel, "(出错)");
}
break;
case LOG_LEVEL_NORMAL:
{
strcpy(szLevel, "(正常)");
}
break;
case LOG_LEVEL_DEBUG:
{
strcpy(szLevel, "(调试)");
}
break;
default:
{
strcpy(szLevel, "");
}
}
// DateLog文件夹不存在
if (_access(szTempPath, 0) != 0)
{
return;
}
sprintf(szFile, "%s\\%04d%02d%02d.log", szFolder, tmCur.wYear, tmCur.wMonth, tmCur.wDay);
FILE * pFile = NULL;
pFile = fopen(szFile, "at");
if (NULL == pFile)
{
return;
}
fprintf(pFile,"%s %s %s\n", szTime, szLevel, pszLine);
fclose(pFile);
}
stdafx.h 添加
#pragma warning (disable : 4996)
#include "LogTrace.h"
extern CLogTrace g_logTrace;
stdafx.cpp添加
CLogTrace g_logTrace;
在主类中的构造函数中添加
// TODO: 在此初始化控件的实例数据。
g_logTrace.SetActiveLevel(LOG_LEVEL_DEBUG);
//记日志组件获取地址
g_logTrace.SetLogPath(LOG_FILE_PATH);
如果在方法中加载了dll的在析构函数中可以清理FreeLibrary(dll);
添加 #define LOG_FILE_PATH "C:\\Log" //记日志地址,需记日志请创建Log文件夹。
然后就可以在添加的方法中使用了
g_logTrace.WriteLog(LOG_LEVEL_ERROR, SINGLE_ID, _T("成功"), "Dll");