C++小知识——VS2013 MFC基于对话框编程

转载自:https://blog.csdn.net/wokaowokaowokao12345/article/details/53173966
前言
一直利用Qt库做Ui设计,但针对于一些MFC项目,掌握一些必要的MFC开发技巧还是很有必要的。这篇博客里就将自己所学的一些MFC浅显知识记录一下,方便今后的学习。博客里只记录关键步骤。
一、新建MFC项目
选择:基于对话框
MFC的使用:
在共享DLL中使用MFC (程序运行需要dll)
在静态库中使用MFC (程序较大,运行时不需要dll)
C++小知识——VS2013 MFC基于对话框编程
文章图片

设置MFC程序主框架样式和标题
C++小知识——VS2013 MFC基于对话框编程
文章图片

高级功能
若是用不上“ActiveX控件”可以去掉勾选,若要涉及到网络编程就把“windows嵌套字”选上
C++小知识——VS2013 MFC基于对话框编程
文章图片

完成
C++小知识——VS2013 MFC基于对话框编程
文章图片

二、MFC程序执行流程
每创建一个MFC项目,默认包含3个类,“关于”对话框、主对话框类、初始化项目的App类。
项目生成后,都会有一个属于App类的theApp对象,对本应用程序实例化。

// CMFCTest1App 构造 CMFCTest1App::CMFCTest1App() { // 支持重新启动管理器 m_dwRestartManagerSupportFlags = AFX_RESTART_MANAGER_SUPPORT_RESTART; // TODO:在此处添加构造代码, // 将所有重要的初始化放置在 InitInstance 中 } // 唯一的一个 CMFCTest1App 对象 CMFCTest1App theApp;

应用程序创建完成,程序开始运行,进入消息循环,windows程序的事件都是消息驱动的,每产生一个消息就触发一个响应事件,消息和事件通过声明消息映射DECLARE_MESSAGE_MAP()联系在一起。
默认包含三个消息:
BEGIN_MESSAGE_MAP(CMFCTest1Dlg, CDialogEx) ON_WM_SYSCOMMAND()//响应控制指令 ON_WM_PAINT()//响应绘图消息,用于刷新窗口 ON_WM_QUERYDRAGICON() //当用户拖动最小化窗口时取得光标 END_MESSAGE_MAP()

当应用程序关闭时,会发送WM_CLOSE消息,程序相应后结束。在类向导中可以添加消息处理函数。
C++小知识——VS2013 MFC基于对话框编程
文章图片

void CMFCTest1Dlg::OnClose() { // TODO:在此添加消息处理程序代码和/或调用默认值 if (MessageBox(_T("确定退出吗"),_T("提示"),MB_YESNO|MB_ICONWARNING)==IDNO) { return; } CDialogEx::OnClose(); }

C++小知识——VS2013 MFC基于对话框编程
文章图片

5.应用程序通过定义,初始化,由winmain开始,注册、创建、显示窗口,消息响应,程序终止,结束运行周期
三、对话框类
afx_msg宏
afx_msg宏没有任何语法上的实际意义。afx_msg宏表示声明的是一个消息响应函数。
DoDataExchange函数
用于存放各类控件的变量信息
OnInitDialog函数
用于初始化对话框
OnSysCommand系统指令响应函数,默认处理窗口最小化和最大化指令等
OnPaint绘图消息响应函数
调出类向导
项目->类向导,快捷键Ctrl+shilft+X
四、添加按钮
将默认对话框中的静态文本和原有按钮删除,添加新的按钮1和按钮2,在属性页中可以查看并设置。一般只需要修改两个属性,“Caption”和“ID”,前者是按钮的文本,后者是其唯一标识。
C++小知识——VS2013 MFC基于对话框编程
文章图片

为按钮添加事件处理函数
实现按钮的功能
添加按钮的控件型变量,变量命名一般以“m_”开头,后面部分为按钮功能简要说明。
C++小知识——VS2013 MFC基于对话框编程
文章图片

在初始化函数OnInitDialog中修改Exit对话框不可用
// TODO:在此添加额外的初始化代码 m_Exit.EnableWindow(FALSE);

添加处理事件
void CMFCTest1Dlg::OnBnClickedButton1() { // TODO:在此添加控件通知处理程序代码 CString str; m_Enable.GetWindowTextW(str); if (str=="使能") { m_Exit.EnableWindow(TRUE); m_Enable.SetWindowTextW(_T("使不能")); } else { m_Exit.EnableWindow(FALSE); m_Enable.SetWindowTextW(_T("使能")); } } void CMFCTest1Dlg::OnBnClickedButton2() { // TODO:在此添加控件通知处理程序代码 SendMessage(WM_CLOSE, 0, 0); }

显示VS大括号/花括号折叠按钮
这个功能默认是关闭的,打开路径如下:
C++小知识——VS2013 MFC基于对话框编程
文章图片

将大纲语句块改为“True”
C++小知识——VS2013 MFC基于对话框编程
文章图片

Cairo在windows+vs2013编译
1、下载地址:https://github.com/DomAmato/Cairo-VS,https://www.cairographics.org/releases/
下载后一个链接,解压后,将源文件放在第一个链接下载后的工程中,编译。
转载自:https://blog.csdn.net/u011417605/article/details/53468382
2、Cairo开发环境安装与在VC++2013中简单实现
https://blog.csdn.net/Shixi_vivian/article/details/52831619
3、Windows 下安装图形库 Cairo 教程
http://www.nodercms.com/help/installation/windows-xia-an-zhuang-tu-xing-ku-cairo-jiao-cheng
4、windows下成功编译Cairo,Compiling Cairo for Windows
https://blog.csdn.net/kuikuijia/article/details/48242705
windows下成功编译Cairo,Compiling Cairo for Windows
Boost_1_66_0在VS2013下的安装使用 一:
主要转载自:https://blog.csdn.net/sunshinecj/article/details/52598488
安装boost库的初衷
boost库是一个C++'准’标准库,对于一个C++程序员来说,了解强大的boost库是很有必要的。当然,在学习使用这样一个强大的库之前,首先要学会安装。本文讲述了boost_1.60.0版本在win10,VS2013环境下的安装过程。
下载boost库
boost官方网站:http://www.boost.org/
boost_1_60_0下载页:http://www.boost.org/users/history/version_1_60_0.html
C++小知识——VS2013 MFC基于对话框编程
文章图片

安装boost库
1、解压缩
2、以管理员身份运行cmd
3、进入解压缩好的文件夹下面
4、在cmd窗口运行bootstrap.bat脚本文件,等一分钟左右,会在该目录生成bjam.exe文件
5、cmd窗口下运行bjam.exe文件,该步骤可能需要十几分钟
6、到此,boost库安装完成
4、生成bjam.exe:
C++小知识——VS2013 MFC基于对话框编程
文章图片

第一个使用boost库的程序
1、打开VS2013,新建一个控制台程序
2、在boosttest工程中包含目录添加I:\boost_1_60_0
库目录添加I:\boost_1_60_0\stage\lib
3、新建一个main.cpp对boost库进行测试
C++小知识——VS2013 MFC基于对话框编程
文章图片

#include #include #include using namespace boost; int main() { array n = { 10, 5, 8, 3, 9 }; array::iterator it = n.begin(); for (; it != n.end(); it++) { std::cout << *it << std::endl; } std::cin.get(); return 0; }

C++小知识——VS2013 MFC基于对话框编程
文章图片

注:boost库的安装测试到此完成,接下来就是学习使用了,加油!
二:Windows下boost安装及其在VS2013中配置
https://blog.csdn.net/u013777351/article/details/50733974
三、Boost安装出错, 遇到“编译器中发生内部错误”的解决方法
https://blog.csdn.net/alpine_climbing/article/details/52621528?winzoom=1
Lapack在VS2013中的安装 一、如何在Windows环境下编译Lapack
转载自:https://blog.csdn.net/xdsjlpld123/article/details/78821953
我并没有成功运行,不知道咋回事,我暂时不用这个了。。如果有成功调试好的,请在评论下给出你博客的链接。谢谢。
预备工作1:两个介绍Lapack的编译过程
国外官网介绍:
http://icl.cs.utk.edu/lapack-for-windows/lapack/#libraries
国内详细介绍:
http://blog.csdn.net/github_19765307/article/details/38719047#reply
预备工作2:准备本机软件
整个编译过程需要使用Cmake、MinGW、Microsoft VisualStudio 2010
在安装MinGW之后需要在MinGWInstallation Manager中安装gcc和gfortran两个选项的功能,最终查看在MinGW的bin目录下是否有gcc和gfortran以及make的执行文件;
对于Lapack3.7版本及其以上版本,windows需要在编译过程使用Visual Studio 2015的编译工具;
对于Lapack3.5版本,windows需要指定在编译过程使用Visual Studio 2010的编译工具;
剩余的就可以直接按照前两个教程的工作直接开始。
安装过程以结果测试
在generate的过程中,应该能看到进度百分比持续不断的前进:
C++小知识——VS2013 MFC基于对话框编程
文章图片

最终应该能看到100%的画面:
C++小知识——VS2013 MFC基于对话框编程
文章图片

在lapack的根目录下,打开cmd窗口,运行mingw32-make.exe test 或者 make.exe test(取决于你的MinGW/bin目录下make的名字),查看结果:
C++小知识——VS2013 MFC基于对话框编程
文章图片

编译成功,其后,查看编译目录(一般为build,自己命名)下的lib和bin目录,编译好的文件已存放其中。编译过程中,如遇到VC工具无法找到等问题,请查看环境变量的path中是否存在VC2010工具的路径,如有,再查看C:\Windows\System32的路径是否存在,没有,则添加该路径至path中。
C/C++执行外部程序(调用外部exe程序) 转载自:https://blog.csdn.net/dongpanshan/article/details/7835722,其中我只用到了ShellExecute函数,根据下面的示例以及介绍的其中的参数进行了调整,实现了对外部exe的调用
C中的函数:
1.exec() 函数家族:
exec() 家族的函数将会创建一个新的进程来执行程序。(不能设置权限,只是单纯的传值执行exe)
_execl, _wexecl
_execv, _wexecv
_execle, _wexecle
_execve, _wexecve
_execlp, _wexeclp
_execvp, _wexecvp
_execlpe, _wexeclpe
_execvpe, _wexecvpe
具体使用例子msdn:ms-help://MS.MSDNQTR.v90.chs/dv_vccrt/html/a261df93-206a-4fdc-b8ac-66aa7db83bc6.htm
2.spawn()函数家族:
spawn() 家族的函数将会创建一个新的进程来执行程序。(不能设置权限,只是单纯的传值执行exe)
_spawnl, _wspawnl
_spawnv, _wspawnv
_spawnle, _wspawnle
_spawnve, _wspawnve
_spawnlp, _wspawnlp
_spawnvp, _wspawnvp
_spawnlpe, _wspawnlpe
_spawnvpe, _wspawnvpe
具体使用例子msdn:ms-help://MS.MSDNQTR.v90.chs/dv_vccrt/html/bb47c703-5216-4e09-8023-8cf25bbf2cf9.htm
3.system()函数
可用于执行控制台命令(DOS命令),比如
system(“cls”); //清屏,等于在DOS上使用cls命令
WIN32 API
1.WinExec()函数
只提供16位windows程序使用。(不能设置权限,只是单纯的传值执行exe)
⑴ 函数原型: UINT Win Exec(LPCSTR lpCmdLine, UINT uCmdShow);
⑵ 参数:
lpCmdLine:指向一个空结束的字符串,串中包含将要执行的应用程序的命令行(文件名加上可选参数)。
uCmdShow:定义Windows应用程序的窗口如何显示,并为CreateProcess函数提供STARTUPINFO参数的wShowWindow成员的值。
⑶ 返回值:
若函数调用成功,则返回值大于31。若函数调用失败,则返回值为下列之一:
① 0:系统内存或资源已耗尽。
② ERROR_BAD_FORMAT:EXE文件无效(非Win32.EXE或.EXE影像错误)。
③ ERROR_FILE_NOT_FOUND:指定的文件未找到。
④ ERROR_PATH_NOT_FOUND:指定的路径未找到。
虽然Microsoft认为WinExec已过时,但是在许多时候,简单的WinExec函数仍是运行新程序的最好方式。简单地传送作为第一个参数的 命令行,还需要决定如何显示程序(该程序也许会忽视它)的第二个参数。通常,将其设置为SW_SHOW,也可尝试SW_MINIMIZED或 SW_MAXIMIZED。WinExec不允许用CreateProcess获得的所有选项,而它的确简单。
2.ShellExecute() 、ShellExecuteEx() 后者可以设置以管理员权限运行(已运行)
ShellExecute不仅可以运行EXE文件,也可以运行已经关联的文件。
⑴标准用法
ShellExecute函数原型及参数含义如下:
HINSTANCE ShellExecute(HWND hwnd, LPCTSTR lpOperation, LPCTSTR lpFile, LPCTSTR lpParameters, LPCTSTR lpDirectory, INT nShowCmd);
●hWnd:用于指定父窗口句柄。当函数调用过程出现错误时,它将作为Windows消息窗口的父窗口。例如,可以将其设置为应用程序主窗口句柄,即Application.Handle,也可以将其设置为桌面窗口句柄(用GetDesktopWindow函数获得)。
●lpOperation:用于指定要进行的操作。其中“open”操作表示执行由FileName参数指定的程序,或打开由FileName参数指定的文件或文件夹;“print”操作表示打印由FileName参数指定的文件;“explore”操作表示浏览由FileName参数指定的文件夹。当参数设为nil时,表示执行默认操作“open”。
●lpFileName:用于指定要打开的文件名、要执行的程序文件名或要浏览的文件夹名。
●lpParameters:若FileName参数是一个可执行程序,则此参数指定命令行参数,否则此参数应为nil或PChar(0)。
●lpDirectory:用于指定默认目录。
●lpShowCmd:若FileName参数是一个可执行程序,则此参数指定程序窗口的初始显示方式,否则此参数应设置为0。
#include
#include
#include
#include
int main( void )
{
HINSTANCE hNewExe = ShellExecuteA(NULL, “open”, “d:\tese.log”, NULL, NULL, SW_SHOW);
if ((DWORD)hNewExe <= 32)
{
printf(“return value:%d\n”, (DWORD)hNewExe);
}
else
{
printf(“successed!\n”);
}
printf(“GetLastError: %d\n”, GetLastError());
system(“pause”);
return 1;
}
当“D:\test.log”文件不存在是,执行结果如下:
这里若函数执行错误, GetLastError()不一定能捕获到错误代码,例如当“d:\tese.log”文件存在,将记事本"notepad.exe"命名为其他名字时:
另外两个函数的返回值就不列出了。
(2) 特殊用法
1)如果将FileName参数设置为“http:”协议格式,那么该函数将打开默认浏览器并链接到指定的URL地址。若用户机器中安装了多个浏览器,则该函数将根据Windows 9x/NT注册表中http协议处理程序(Protocols Handler)的设置确定启动哪个浏览器。
格式一:http://网站域名。如:ShellExecute(handle, “open”, “http://www.neu.edu.cn”, nil, nil, SW_SHOWNORMAL);
格式二:http://网站域名/网页文件名。如:ShellExecute(handle, “open”, “http://www.neu.edu.cn/default.htm”, nil, nil, SW_SHOWNORMAL);
2)如果将FileName参数设置为“mailto:”协议格式,那么该函数将启动默认邮件客户程序,如Microsoft Outlook(也包括Microsoft Outlook Express)或Netscape Messanger。若用户机器中安装了多个邮件客户程序,则该函数将根据Windows 9x/NT注册表中mailto协议处理程序的设置确定启动哪个邮件客户程序。
格式一:mailto:如:ShellExecute(handle, “open”, “mailto:”, nil, nil, SW_SHOWNORMAL); 打开新邮件窗口。
格式二:mailto:用户账号@邮件服务器地址 如:ShellExecute(handle, “open”, “mailto:who@mail.neu.edu.cn”, nil, nil, SW_SHOWNORMAL);
打开新邮件窗口,并自动填入收件人地址。若指定多个收件人地址,则收件人地址之间必须用分号或逗号分隔开(下同)
如:ShellExecute(this->m_hWnd, “open”, “mailto:nishinapp@yahoo.com”, “”, “”, SW_SHOW);
格式三:mailto:用户账号@邮件服务器地址?subject=邮件主题&body=邮件正文
如:ShellExecute(handle, “open”, “mailto:who@mail.neu.edu.cn?subject=Hello&Body=This is a test”, nil, nil, SW_SHOWNORMAL);
打开新邮件窗口,并自动填入收件人地址、邮件主题和邮件正文。若邮件正文包括多行文本,则必须在每行文本之间加入换行转义字符%0a。
例子(delphi):
在一个应用程序调用c:Project1.exe;
ShellExecute(handle, ’open’,’c:Project1.exe’,’字串内容’,nil, SW_SHOWNORMAL);
在Project1.exe里可以调用:
procedure TForm1.FormCreate(Sender: TObject);
var i:integer;
begin
for i:=1 to paramcount do
if ParamStr(i)〈〉’’ then showmessage(ParamStr(i));
end;
最后的那个参数,为窗口指定可视性方面的一个命令。 请用下述任何一个常数
SW_HIDE 隐藏窗口,活动状态给令一个窗口
SW_MINIMIZE 最小化窗口,活动状态给令一个窗口
SW_RESTORE 用原来的大小和位置显示一个窗口,同时令其进入活动状态
SW_SHOW 用当前的大小和位置显示一个窗口,同时令其进入活动状态
SW_SHOWMAXIMIZED 最大化窗口,并将其激活
SW_SHOWMINIMIZED 最小化窗口,并将其激活
SW_SHOWMINNOACTIVE 最小化一个窗口,同时不改变活动窗口
SW_SHOWNA 用当前的大小和位置显示一个窗口,不改变活动窗口
SW_SHOWNOACTIVATE 用最近的大小和位置显示一个窗口,同时不改变活动窗口
SW_SHOWNORMAL 与SW_RESTORE相同
3、深入浅出ShellExecute 译者:徐景周(原作:Nishant S)
Q: 如何打开一个应用程序? 正如您所看到的,我并没有传递程序的完整路径。
ShellExecute(this->m_hWnd, “open”, “calc.exe”, “”, “”, SW_SHOW);
或ShellExecute(this->m_hWnd, “open”, “notepad.exe”, “c:\MyLog.log”, “”, SW_SHOW);
Q: 如何打开一个同系统程序相关连的文档?
ShellExecute(this->m_hWnd, “open”, “c:\abc.txt”, “”, “”, SW_SHOW);
Q: 如何打开一个网页?
ShellExecute(this->m_hWnd, “open”, “http://www.google.com”, “”, “”, SW_SHOW);
Q: 如何激活相关程序,发送EMAIL?
ShellExecute(this->m_hWnd,“open”, “mailto:nishinapp@yahoo.com”,"","", SW_SHOW );
Q: 如何用系统打印机打印文档?
ShellExecute(this->m_hWnd, “print”, “c:\abc.txt”, “”, “”, SW_HIDE);
Q: 如何用系统查找功能来查找指定文件?
ShellExecute(m_hWnd, “find”, “d:\nish”, NULL, NULL, SW_SHOW);
Q: 如何启动一个程序,直到它运行结束?
SHELLEXECUTEINFO ShExecInfo = {0};
ShExecInfo.cbSize = sizeof(SHELLEXECUTEINFO);
ShExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
ShExecInfo.hwnd = NULL;
ShExecInfo.lpVerb = NULL; //当设置为"runas"时,表示以管理员权限运行
ShExecInfo.lpFile = “c:\MyProgram.exe”;
ShExecInfo.lpParameters = “”;
ShExecInfo.lpDirectory = NULL;
ShExecInfo.nShow = SW_SHOW;
ShExecInfo.hInstApp = NULL;
ShellExecuteEx(&ShExecInfo);
WaitForSingleObject(ShExecInfo.hProcess,INFINITE);
或:
PROCESS_INFORMATION ProcessInfo;
STARTUPINFO StartupInfo; //This is an [in] parameter
ZeroMemory(&StartupInfo, sizeof(StartupInfo));
StartupInfo.cb = sizeof(StartupInfo); //Only compulsory field
if(CreateProcess(“c:\winnt\notepad.exe”, NULL, NULL,NULL,FALSE,0,NULL, NULL,&StartupInfo,&ProcessInfo))
{
WaitForSingleObject(ProcessInfo.hProcess,INFINITE);
CloseHandle(ProcessInfo.hThread);
CloseHandle(ProcessInfo.hProcess);
}
else
{
MessageBox(“The process could not be started…”);
}
Q: 如何显示文件或文件夹的属性?
SHELLEXECUTEINFO ShExecInfo = {0};
ShExecInfo.cbSize = sizeof(SHELLEXECUTEINFO);
ShExecInfo.fMask = SEE_MASK_INVOKEIDLIST;
ShExecInfo.hwnd = NULL;
ShExecInfo.lpVerb = “properties”;
ShExecInfo.lpFile = “c:\”; //can be a file as well
ShExecInfo.lpParameters = “”;
ShExecInfo.lpDirectory = NULL;
ShExecInfo.nShow = SW_SHOW;
ShExecInfo.hInstApp = NULL;
ShellExecuteEx(&ShExecInfo);
3.CreateProcess函数 可以设置继承父进程权限和句柄
函数原型:
BOOL CreateProcess
(
LPCTSTR lpApplicationName, [in]:
LPTSTR lpCommandLine,
LPSECURITY_ATTRIBUTES lpProcessAttributes。
LPSECURITY_ATTRIBUTES lpThreadAttributes,
BOOL bInheritHandles,
DWORD dwCreationFlags,
LPVOID lpEnvironment,
LPCTSTR lpCurrentDirectory,
LPSTARTUPINFO lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation
);
参数:
lpApplicationName:指向一个NULL结尾的、用来指定可执行模块的字符串。
这个字符串可以使可执行模块的绝对路径,也可以是相对路径,在后一种情况下,函数使用当前驱动器和目录建立可执行模块的路径。
这个参数可以被设为NULL,在这种情况下,可执行模块的名字必须处于 lpCommandLine 参数的最前面并由空格符与后面的字符分开。
这个被指定的模块可以是一个Win32应用程序。如果适当的子系统在当前计算机上可用的话,它也可以是其他类型的模块(如MS-DOS 或 OS/2)。
lpCommandLine:指向一个NULL结尾的、用来指定要运行的命令行。
这个参数可以为空,那么函数将使用参数指定的字符串当作要运行的程序的命令行。
如果lpApplicationName和lpCommandLine参数都不为空,那么lpApplicationName参数指定将要被运行的模块,lpCommandLine参数指定将被运行的模块的命令行。新运行的进程可以使用GetCommandLine函数获得整个命令行。C语言程序可以使用argc和argv参数。
如果lpApplicationName参数为空,那么这个字符串中的第一个被空格分隔的要素指定可执行模块名。如果文件名不包含扩展名,那么.exe将被假定为默认的扩展名。如果文件名以一个点(.)结尾且没有扩展名,或文件名中包含路径,.exe将不会被加到后面。如果文件名中不包含路径,Windows将按照如下顺序寻找这个可执行文件:
lpProcessAttributes:指向一个SECURITY_ATTRIBUTES结构体,这个结构体决定是否返回的句柄可以被子进程继承。如果lpProcessAttributes参数为空(NULL),那么句柄不能被继承
lpThreadAttributes:指向一个SECURITY_ATTRIBUTES结构体,这个结构体决定是否返回的句柄可以被子进程继承。如果lpThreadAttributes参数为空(NULL),那么句柄不能被继承
bInheritHandles:指示新进程是否从调用进程处继承了句柄。如果参数的值为真,调用进程中的每一个可继承的打开句柄都将被子进程继承。被继承的句柄与原进程拥有完全相同的值和访问权限。
dwCreationFlags:指定附加的、用来控制优先类和进程的创建的标志。以下的创建标志可以以除下面列出的方式外的任何方式组合后指定。
值:CREATE_DEFAULT_ERROR_MODE
含义:新的进程不继承调用进程的错误模式。CreateProcess函数赋予新进程当前的默认错误模式作为替代。应用程序可以调用SetErrorMode函数设置当前的默认错误模式。
这个标志对于那些运行在没有硬件错误环境下的多线程外壳程序是十分有用的。
对于CreateProcess函数,默认的行为是为新进程继承调用者的错误模式。设置这个标志以改变默认的处理方式。
值:CREATE_NEW_CONSOLE
含义:新的进程将使用一个新的控制台,而不是继承父进程的控制台。这个标志不能与DETACHED_PROCESS标志一起使用。
值:CREATE_NEW_PROCESS_GROUP
含义:新进程将使一个进程树的根进程。进程树种的全部进程都是根进程的子进程。新进程树的用户标识符与这个进程的标识符是相同的,由lpProcessInformation参数返回。进程树经常使用GenerateConsoleCtrlEvent函数允许发送CTRL+C或CTRL+BREAK信号到一组控制台进程。
值:CREATE_SEPARATE_WOW_VDM
含义:(只适用于Windows NT)这个标志只有当运行一个16位的Windows应用程序时才是有效的。如果被设置,新进程将会在一个私有的虚拟DOS机(VDM)中运行。另外,默认情况下所有的16位Windows应用程序都会在同一个共享的VDM中以线程的方式运行。单独运行一个16位程序的优点是一个应用程序的崩溃只会结束这一个VDM的运行;其他那些在不同VDM中运行的程序会继续正常的运行。同样的,在不同VDM中运行的16位Windows应用程序拥有不同的输入队列,这意味着如果一个程序暂时失去响应,在独立的VDM中的应用程序能够继续获得输入。
值:CREATE_SHARED_WOW_VDM
含义:(只适用于Windows NT)这个标志只有当运行一个16位的Windows应用程序时才是有效的。如果WIN.INI中的Windows段的DefaultSeparateVDM选项被设置为真,这个标识使得CreateProcess函数越过这个选项并在共享的虚拟DOS机中运行新进程。
值:CREATE_SUSPENDED
含义:新进程的主线程会以暂停的状态被创建,直到调用ResumeThread函数被调用时才运行。
值:CREATE_UNICODE_ENVIRONMENT
含义:如果被设置,由lpEnvironment参数指定的环境块使用Unicode字符,如果为空,环境块使用ANSI字符。
值:DEBUG_PROCESS
含义:如果这个标志被设置,调用进程将被当作一个调试程序,并且新进程会被当作被调试的进程。系统把被调试程序发生的所有调试事件通知给调试器。
如果你使用这个标志创建进程,只有调用进程(调用CreateProcess函数的进程)可以调用WaitForDebugEvent函数。
值:DEBUG_ONLY_THIS_PROCESS
含义:如果此标志没有被设置且调用进程正在被调试,新进程将成为调试调用进程的调试器的另一个调试对象。如果调用进程没有被调试,有关调试的行为就不会产生。
值:DETACHED_PROCESS
含义:对于控制台进程,新进程没有访问父进程控制台的权限。新进程可以通过AllocConsole函数自己创建一个新的控制台。这个标志不可以与CREATE_NEW_CONSOLE标志一起使用。
dwCreationFlags参数还用来控制新进程的优先类,优先类用来决定此进程的线程调度的优先级。如果下面的优先级类标志都没有被指定,那么默认的优先类是NORMAL_PRIORITY_CLASS,除非被创建的进程是IDLE_PRIORITY_CLASS。在这种情况下子进程的默认优先类是IDLE_PRIORITY_CLASS。
可以下面的标志中的一个:
优先级:HIGH_PRIORITY_CLASS
含义:指示这个进程将执行时间临界的任务,所以它必须被立即运行以保证正确。这个优先级的程序优先于正常优先级或空闲优先级的程序。一个例子是Windows任务列表,为了保证当用户调用时可以立刻响应,放弃了对系统负荷的考虑。确保在使用高优先级时应该足够谨慎,因为一个高优先级的CPU关联应用程序可以占用几乎全部的CPU可用时间。
优先级:IDLE_PRIORITY_CLASS
含义:指示这个进程的线程只有在系统空闲时才会运行并且可以被任何高优先级的任务打断。例如屏幕保护程序。空闲优先级会被子进程继承。
优先级:NORMAL_PRIORITY_CLASS
含义:指示这个进程没有特殊的任务调度要求。
优先级:REALTIME_PRIORITY_CLASS
含义:指示这个进程拥有可用的最高优先级。一个拥有实时优先级的进程的线程可以打断所有其他进程线程的执行,包括正在执行重要任务的系统进程。例如,一个执行时间稍长一点的实时进程可能导致磁盘缓存不足或鼠标反映迟钝。
lpEnvironment:指向一个新进程的环境块。如果此参数为空,新进程使用调用进程的环境。
一个环境块存在于一个由以NULL结尾的字符串组成的块中,这个块也是以NULL结尾的。每个字符串都是name=value的形式。
因为相等标志被当作分隔符,所以它不能被环境变量当作变量名。
与其使用应用程序提供的环境块,不如直接把这个参数设为空,系统驱动器上的当前目录信息不会被自动传递给新创建的进程。对于这个情况的探讨和如何处理,请参见注释一节。
环境块可以包含Unicode或ANSI字符。如果lpEnvironment指向的环境块包含Unicode字符,那么dwCreationFlags字段的CREATE_UNICODE_ENVIRONMENT标志将被设置。如果块包含ANSI字符,该标志将被清空。
请注意一个ANSI环境块是由两个零字节结束的:一个是字符串的结尾,另一个用来结束这个快。一个Unicode环境块石油四个零字节结束的:两个代表字符串结束,另两个用来结束块。
lpCurrentDirectory:指向一个以NULL结尾的字符串,这个字符串用来指定子进程的工作路径。这个字符串必须是一个包含驱动器名的绝对路径。如果这个参数为空,新进程将使用与调用进程相同的驱动器和目录。这个选项是一个需要启动启动应用程序并指定它们的驱动器和工作目录的外壳程序的主要条件。
lpStartupInfo:指向一个用于决定新进程的主窗体如何显示的STARTUPINFO结构体。
lpProcessInformation:指向一个用来接收新进程的识别信息的PROCESS_INFORMATION结构体。
返回值:
如果函数执行成功,返回非零值。
如果函数执行失败,返回零,可以使用GetLastError函数获得错误的附加信息。
注释:
CreateProcess函数用来运行一个新程序。WinExec和LoadModule函数依旧可用,但是它们同样通过调用CreateProcess函数实现。
另外CreateProcess函数除了创建一个进程,还创建一个线程对象。这个线程将连同一个已初始化了的堆栈一起被创建,堆栈的大小由可执行文件的文件头中的描述决定。线程由文件头处开始执行。
新进程和新线程的句柄被以全局访问权限创建。对于这两个句柄中的任一个,如果没有安全描述符,那么这个句柄就可以在任何需要句柄类型作为参数的函数中被使用。当提供安全描述符时,在接下来的时候当句柄被使用时,总是会先进行访问权限的检查,如果访问权限检查拒绝访问,请求的进程将不能使用这个句柄访问这个进程。
这个进程会被分配给一个32位的进程标识符。直到进程中止这个标识符都是有效的。它可以被用来标识这个进程,或在OpenProcess函数中被指定以打开这个进程的句柄。进程中被初始化了的线程一样会被分配一个32位的线程标识符。这个标识符直到县城中止都是有效的且可以用来在系统中唯一标识这个线程。这些标识符在PROCESS_INFORMATION结构体中返回。
当在lpApplicationName或lpCommandLine参数中指定应用程序名时,应用程序名中是否包含扩展名都不会影响运行,只有一种情况例外:一个以.com为扩展名的MS-DOS程序或Windows程序必须包含.com扩展名。
调用进程可以通过WaitForInputIdle函数来等待新进程完成它的初始化并等待用户输入。这对于父进程和子进程之间的同步是极其有用的,因为CreateProcess函数不会等待新进程完成它的初始化工作。举例来说,在试图与新进程关联的窗口之前,进程应该先调用WaitForInputIdle。
首选的结束一个进程的方式是调用ExitProcess函数,因为这个函数通知这个进程的所有动态链接库(DLLs)程序已进入结束状态。其他的结束进程的方法不会通知关联的动态链接库。注意当一个进程调用ExitProcess时,这个进程的其他县城没有机会运行其他任何代码(包括关联动态链接库的终止代码)。
ExitProcess, ExitThread, CreateThread, CreateRemoteThread,当一个进程启动时(调用了CreateProcess的结果)是在进程中序列化进行的。在一段地址空间中,同一时间内这些事件中只有一个可以发生。这意味着下面的限制将保留:
*在进程启动和DLL初始化阶段,新的线程可以被创建,但是直到进程的DLL初始化完成前它们都不能开始运行。
*在DLL初始化或卸下例程中进程中只能有一个线程。
*直到所有的线程都完成DLL初始化或卸下后,ExitProcess函数才返回。
在进程中的所有线程都终止且进程所有的句柄和它们的线程被通过调用CloseHandle函数终止前,进程会留在系统中。进程和主线程的句柄都必须通过调用CloseHandle函数关闭。如果不再需要这些句柄,最好在创建进程后立刻关闭它们。
当进程中最后一个线程终止时,下列的事件发生:
*所有由进程打开的对象都会关闭。
*进程的终止状态(由GetExitCodeProcess函数返回)从它的初始值STILL_ACTIVE变为最后一个结束的线程的结束状态。
*主线程的线程对象被设置为标志状态,供其他等待这个对象的线程使用。
*进程对象被设置为标志状态,供其他等待这个对象的线程使用。
假设当前在C盘上的目录是\MSVC\MFC且有一个环境变量叫做C:,它的值是C:\MSVC\MFC,就像前面lpEnvironment中提到过的那样,这样的系统驱动器上的目录信息在CreateProcess函数的lpEnvironment参数不为空时不会被自动传递到新进程里。一个应用程序必须手动地把当前目录信息传递到新的进程中。为了这样做,应用程序必须直接创建环境字符串,并把它们按字母顺序排列(因为Windows NT和Windows 95使用一种简略的环境变量),并把它们放进lpEnvironment中指定的环境块中。类似的,他们要找到环境块的开头,又要重复一次前面提到的环境块的排序。
一种获得驱动器X的当前目录变量的方法是调用GetFullPathName(“x:”,…)。这避免了一个应用程序必须去扫描环境块。如果返回的绝对路径是X:\,就不需要把这个值当作一个环境数据去传递了,因为根目录是驱动器X上的新进程的默认当前目录。
由CreateProcess函数返回的句柄对于进程对象具有PROCESS_ALL_ACCESS的访问权限。
由lpcurrentDirectory参数指定的当前目录室子进程对象的当前目录。lpCommandLine参数指定的第二个项目是父进程的当前目录。
对于Windows NT,当一个进程在指定了CREATE_NEW_PROCESS_GROUP的情况下被创建时,一个对于SetConsoleCtrlHandler(NULL,True)的调用被用在新的进程上,这意味着对新进程来说CTRL+C是无效的。这使得上层的外科程序可以自己处理CTRL+C信息并有选择的把这些信号传递给子进程。CTRL+BREAK依旧有效,并可被用来中断进程/进程树的执行。
安全注释:
第一个参数lpApplicationName可能是空,这种情况下,可执行文件的名字必须在lpCommandLine中,lpCommandLine参数中可以包含空格。如果可执行文件或路径中包含空格,那么就会有执行不正确文件的风险,这是由于这个函数解析空格的方法引起的。例如:下边这个例子就很危险,因为它试图运行Program.exe文件,如果这个文件存在,它就会代替MyApp.exe文件的运行。
CreateProcess(NULL,”C:\Program Files\MyApp.exe”,…….)
如果有恶意的用户在系统编写了一个名为Program.exe的文件,那么任何调用CreateProcess函数,且在文件路径中使用Program Files文件夹的参数,都有可能会运行Program.exe文件,而不是运行本来打算运行的文件。
要避免这个问题,可以不要将NULL值传递给lpApplicationName参数,或者在lpCommandLine中使用双引号(转义符)括起可执行文件的全路径名,如下所示:
CreateProcess(NULL,”\”C:\Program Files\MyApp.exe\” -L -S”,…….)
-L和-S是MyApp.exe可执行文件的参数。
最后要说明的一点是:在lpApplicationName中的参数和lpCommandLine中的第一个参数是一样的,有人说显得有些重复,其实这样做纯粹是一种被公认化了习惯!
此外还有CreateProcessAsUser函数
Eigen库的基本使用方法、PCL计算协方差矩阵 转载自:https://blog.csdn.net/r1254/article/details/47418871
以及https://blog.csdn.net/wokaowokaowokao12345/article/details/53397488
第一部分:
1.1前言
Eigen是一个高层次的C ++库,有效支持 得到的线性代数,矩阵和矢量运算,数值分析及其相关的算法。
1.2配置
关于Eigen库的配置只需要在属性表包含目录中添加Eigen路径即可。
C++小知识——VS2013 MFC基于对话框编程
文章图片

1.3例子
Example 1:
#include #include void main() { Eigen::MatrixXd m(2, 2); //声明一个MatrixXd类型的变量,它是2*2的矩阵,未初始化 m(0, 0) = 3; //将矩阵第1个元素初始化3 m(1, 0) = 2.5; //将矩阵第3个元素初始化3 m(0, 1) = -1; m(1, 1) = m(1, 0) + m(0, 1); std::cout << m << std::endl; }

Eigen头文件定义了很多类型,但对于简单的应用程序,可能只使用MatrixXd类型。 这表示任意大小的矩阵(MatrixXd中的X),其中每个条目是双精度(MatrixXd中的d)。 Eigen / Dense头文件定义了MatrixXd类型和相关类型的所有成员函数。 在这个头文件中定义的所有类和函数都在特征名称空间中。
C++小知识——VS2013 MFC基于对话框编程
文章图片

Example 2:
#include #include using namespace Eigen; using namespace std; int main() { MatrixXd m = MatrixXd::Random(3,3); //使用Random随机初始化3*3的矩阵 m = (m + MatrixXd::Constant(3,3,1.2)) * 50; cout << "m =" << endl << m << endl; VectorXd v(3); //这表示任意大小的(列)向量。 v << 1, 2, 3; cout << "m * v =" << endl << m * v << endl; }

#include #include using namespace Eigen; using namespace std; int main() { Matrix3d m = Matrix3d::Random(); //使用Random随机初始化固定大小的3*3的矩阵 m = (m + Matrix3d::Constant(1.2)) * 50; cout << "m =" << endl << m << endl; Vector3d v(1,2,3); cout << "m * v =" << endl << m * v << endl; }

Matrix&Vector
Example 3:
#include #include using namespace Eigen; int main() { MatrixXd m(2,2); m(0,0) = 3; m(1,0) = 2.5; m(0,1) = -1; m(1,1) = m(1,0) + m(0,1); std::cout << "Here is the matrix m:\n" << m << std::endl; VectorXd v(2); v(0) = 4; v(1) = v(0) - 1; std::cout << "Here is the vector v:\n" << v << std::endl; }

逗号初始化
Example 4:
Matrix3f m; m << 1, 2, 3,4, 5, 6,7, 8, 9; std::cout << m;

通过Resize调整矩阵大小
矩阵的当前大小可以通过rows(),cols()和size()检索。 这些方法分别返回行数,列数和系数数。 通过resize()方法调整动态大小矩阵的大小。
Example 5:
#include #include using namespace Eigen; int main() { MatrixXd m(2,5); //初始化大小2*5 m.resize(4,3); //重新调整为4*3 std::cout << "The matrix m is of size "<< m.rows() << "x" << m.cols() << std::endl; std::cout << "It has " << m.size() << " coefficients" << std::endl; VectorXd v(2); v.resize(5); std::cout << "The vector v is of size " << v.size() << std::endl; std::cout << "As a matrix, v is of size "<< v.rows() << "x" << v.cols() << std::endl; }

通过赋值调整矩阵大小
Example 6:
MatrixXf a(2, 2);
std::cout << "a is of size " << a.rows() << “x” << a.cols() << std::endl;
MatrixXf b(3, 3);
a = b;
std::cout << "a is now of size " << a.rows() << “x” << a.cols() << std::endl;
Eigen + - * 等运算
Eigen通过通用的C ++算术运算符(例如+, - ,)或通过特殊方法(如dot(),cross()等)的重载提供矩阵/向量算术运算。对于Matrix类(矩阵和向量) 只被重载以支持线性代数运算。 例如,matrix1 matrix2表示矩阵矩阵乘积。
Example 7:
#include
#include
using namespace Eigen;
int main()
{
Matrix2d a; a << 1, 2, 3, 4;
MatrixXd b(2,2);
b << 2, 3, 1, 4;
std::cout << “a + b =\n” << a + b << std::endl;
std::cout << “a - b =\n” << a - b << std::endl;
std::cout << “Doing a += b; ” << std::endl;
a += b;
std::cout << “Now a =\n” << a << std::endl;
Vector3d v(1,2,3);
Vector3d w(1,0,0);
std::cout << “-v + w - v =\n” << -v + w - v << std::endl;
}
Example 8:
#include
#include
using namespace Eigen;
int main()
{
Matrix2d a;
a << 1, 2, 3, 4;
Vector3d v(1,2,3);
std::cout << “a * 2.5 =\n” << a * 2.5 << std::endl;
std::cout << “0.1 * v =\n” << 0.1 * v << std::endl;
std::cout << “Doing v *= 2; ” << std::endl; v *= 2;
std::cout << “Now v =\n” << v << std::endl;
}
矩阵转置、共轭和伴随矩阵
MatrixXcf a = MatrixXcf::Random(2,2);
cout << “Here is the matrix a\n” << a << endl;
cout << “Here is the matrix a^T\n” << a.transpose() << endl;
cout << “Here is the conjugate of a\n” << a.conjugate() << endl;
cout << “Here is the matrix a^*\n” << a.adjoint() << endl;
禁止如下操作:
a = a.transpose(); // !!! do NOT do this !!!
但是可以使用如下函数:
a.transposeInPlace();
此时a被其转置替换。
#include
#include
using namespace Eigen;
int main()
{
Matrix2i a;
a << 1, 2, 3, 4;
std::cout << “Here is the matrix a:\n” << a << std::endl;
a = a.transpose(); // !!! do NOT do this !!!
std::cout << “and the result of the aliasing effect:\n” << a << std::endl;
}
矩阵* 矩阵和矩阵* 向量操作
#include
#include
using namespace Eigen;
int main()
{
Matrix2d mat; mat << 1, 2, 3, 4;
Vector2d u(-1,1), v(2,0);
std::cout << "Here is matmat:\n" << matmat << std::endl;
std::cout << "Here is matu:\n" << matu << std::endl;
std::cout << "Here is u^Tmat:\n" << u.transpose()mat << std::endl;
std::cout << "Here is u^T
v:\n" << u.transpose()v << std::endl;
std::cout << "Here is u
v^T:\n" << u
v.transpose() << std::endl;
std::cout << “Let’s multiply mat by itself” << std::endl;
mat = mat*mat; std::cout << “Now mat is mat:\n” << mat << std::endl;
}
点乘和叉乘
对于点积和叉乘积,需要使用dot()和cross()方法。
#include
#include
using namespace Eigen;
using namespace std;
int main()
{
Vector3d v(1,2,3);
Vector3d w(0,1,2);
cout << "Dot product: " << v.dot(w) << endl;
double dp = v.adjoint()*w; // automatic conversion of the inner product to a scalar
cout << "Dot product via a matrix product: " << dp << endl;
cout << “Cross product:\n” << v.cross(w) << endl;
}
#include
#include
using namespace std;
int main()
{
Eigen::Matrix2d mat;
mat << 1, 2, 3, 4;
cout << "Here is mat.sum(): " << mat.sum() << endl;
cout << "Here is mat.prod(): " << mat.prod() << endl;
cout << "Here is mat.mean(): " << mat.mean() << endl;
cout << "Here is mat.minCoeff(): " << mat.minCoeff() << endl;
cout << "Here is mat.maxCoeff(): " << mat.maxCoeff() << endl;
cout << "Here is mat.trace(): " << mat.trace() << endl;
}
数组的运算(未完待续)
Eigen最小二乘估计
最小平方求解的最好方法是使用SVD分解。 Eigen提供一个作为JacobiSVD类,它的solve()是做最小二乘解。式子为Ax=b
经过和Matlab对比。
#include
#include
using namespace std;
using namespace Eigen;
int main()
{
MatrixXf A = MatrixXf::Random(3, 2);
cout << “Here is the matrix A:\n” << A << endl;
VectorXf b = VectorXf::Random(3);
cout << “Here is the right hand side b:\n” << b << endl;
cout << “The least-squares solution is:\n” << A.jacobiSvd(ComputeThinU | ComputeThinV).solve(b) << endl;
}
C++小知识——VS2013 MFC基于对话框编程
文章图片

第二部分:
矩阵、向量初始化
#include
#include “Eigen/Dense”
using namespace Eigen;
int main()
{
MatrixXf m1(3,4); //动态矩阵,建立3行4列。
MatrixXf m2(4,3); //4行3列,依此类推。
MatrixXf m3(3,3);
Vector3f v1; //若是静态数组,则不用指定行或者列 /* 初始化 */ Matrix3d m = Matrix3d::Random(); m1 = MatrixXf::Zero(3,4); //用0矩阵初始化,要指定行列数 m2 = MatrixXf::Zero(4,3); m3 = MatrixXf::Identity(3,3); //用单位矩阵初始化 v1 = Vector3f::Zero(); //同理,若是静态的,不用指定行列数m1 << 1,0,0,1,//也可以以这种方式初始化 1,5,0,1, 0,0,9,1; m2 << 1,0,0, 0,4,0, 0,0,7, 1,1,1; //向量初始化,与矩阵类似 Vector3d v3(1,2,3); VectorXf vx(30);

}
C++数组和矩阵转换
使用Map函数,可以实现Eigen的矩阵和c++中的数组直接转换,语法如下:
//@param MatrixType 矩阵类型
//@param MapOptions 可选参数,指的是指针是否对齐,Aligned, or Unaligned. The default is Unaligned.
//@param StrideType 可选参数,步长
/*
Map int MapOptions,
typename StrideType>
*/
int i;
//数组转矩阵
double *aMat = new double[20];
for(i =0; i<20; i++)
{
aMat[i] = rand()%11;
}
//静态矩阵,编译时确定维数 Matrix
Eigen:Map > staMat(aMat);
//输出 for (int i = 0; i < staMat.size(); i++) std::cout << *(staMat.data() + i) << " "; std::cout << std::endl << std::endl; //动态矩阵,运行时确定 MatrixXd Map dymMat(aMat,4,5); //输出,应该和上面一致 for (int i = 0; i < dymMat.size(); i++) std::cout << *(dymMat.data() + i) << " "; std::cout << std::endl << std::endl; //Matrix中的数据存在一维数组中,默认是行优先的格式,即一行行的存 //data()返回Matrix中的指针 dymMat.data();

矩阵基础操作
eigen重载了基础的+ - * / += -= = /= 可以表示标量和矩阵或者矩阵和矩阵
#include
#include
using namespace Eigen;
int main()
{
//单个取值,单个赋值
double value00 = staMat(0,0);
double value10 = staMat(1,0);
staMat(0,0) = 100;
std::cout << value00 <
Matrix2d a;
a << 1, 2,
3, 4;
MatrixXd b(2,2);
b << 2, 3,
1, 4;
Matrix2d c = a + b; std::cout<< c<

点积和叉积
#include
#include
using namespace Eigen;
using namespace std;
int main()
{
//点积、叉积(针对向量的)
Vector3d v(1,2,3);
Vector3d w(0,1,2);
std::cout< */
转置、伴随、行列式、逆矩阵
小矩阵(4 * 4及以下)eigen会自动优化,默认采用LU分解,效率不高
#include
#include
using namespace std;
using namespace Eigen;
int main()
{
Matrix2d c;
c << 1, 2,
3, 4;
//转置、伴随
std::cout< std::cout << "行列式: " << c.determinant() << std::endl;
std::cout << “逆矩阵\n” << c.inverse() << std::endl;
}
计算特征值和特征向量
#include
#include
using namespace std;
using namespace Eigen;
int main()
{
//特征向量、特征值
std::cout << “Here is the matrix A:\n” << a << std::endl;
SelfAdjointEigenSolver eigensolver(a);
if (eigensolver.info() != Success) abort();
std::cout << “特征值:\n” << eigensolver.eigenvalues() << std::endl;
std::cout << “Here’s a matrix whose columns are eigenvectors of A \n”
<< “corresponding to these eigenvalues:\n”
<< eigensolver.eigenvectors() << std::endl;
}
解线性方程
#include
#include
using namespace std;
using namespace Eigen;
int main()
{
//线性方程求解 Ax =B;
Matrix4d A;
A << 2,-1,-1,1,
1,1,-2,1,
4,-6,2,-2,
3,6,-9,7;
Vector4d B(2,4,4,9); Vector4d x = A.colPivHouseholderQr().solve(B); Vector4d x2 = A.llt().solve(B); Vector4d x3 = A.ldlt().solve(B); std::cout << "The solution is:\n" << x <<"\n\n"<
}
除了colPivHouseholderQr、LLT、LDLT,还有以下的函数可以求解线性方程组,请注意精度和速度: 解小矩阵(4*4)基本没有速度差别
最小二乘求解
最小二乘求解有两种方式,jacobiSvd或者colPivHouseholderQr,4*4以下的小矩阵速度没有区别,jacobiSvd可能更快,大矩阵最好用colPivHouseholderQr
#include
#include
using namespace std;
using namespace Eigen;
int main()
{
MatrixXf A1 = MatrixXf::Random(3, 2);
std::cout << “Here is the matrix A:\n” << A1 << std::endl;
VectorXf b1 = VectorXf::Random(3);
std::cout << “Here is the right hand side b:\n” << b1 << std::endl;
//jacobiSvd 方式:Slow (but fast for small matrices)
std::cout << “The least-squares solution is:\n”
<< A1.jacobiSvd(ComputeThinU | ComputeThinV).solve(b1) << std::endl;
//colPivHouseholderQr方法:fast
std::cout << “The least-squares solution is:\n”
<< A1.colPivHouseholderQr().solve(b1) << std::endl;
}
稀疏矩阵
稀疏矩阵的头文件包括:
#include
typedef Eigen::Triplet T;
std::vector tripletList;
triplets.reserve(estimation_of_entries); //estimation_of_entries是预估的条目
for(…)
{
tripletList.push_back(T(i,j,v_ij)); //第 i,j个有值的位置的值
}
SparseMatrixType mat(rows,cols);
mat.setFromTriplets(tripletList.begin(), tripletList.end());
// mat is ready to go!
2.直接将已知的非0值插入
SparseMatrix mat(rows,cols);
mat.reserve(VectorXi::Constant(cols,6));
for(…)
{
// i,j 个非零值 v_ij != 0
mat.insert(i,j) = v_ij;
}
mat.makeCompressed(); // optional
稀疏矩阵支持大部分一元和二元运算:
sm1.real() sm1.imag() -sm1 0.5*sm1
sm1+sm2 sm1-sm2 sm1.cwiseProduct(sm2)
二元运算中,稀疏矩阵和普通矩阵可以混合使用
//dm表示普通矩阵
dm2 = sm1 + dm1;
也支持计算转置矩阵和伴随矩阵
参考以下链接
点击这里跳转查看更多
第三部分:
其他相关博客:
1、单独下载与安装:https://blog.csdn.net/augusdi/article/details/12907341
2、一篇较详细的教程:https://blog.csdn.net/wzaltzap/article/details/79501856
3、计算特征值特征向量:https://blog.csdn.net/wokaowokaowokao12345/article/details/47375427
Eigen介绍及简单使用(PCL库实现) 转载自:https://blog.csdn.net/fengbingchun/article/details/47378515,
Eigen是可以用来进行线性代数、矩阵、向量操作等运算的C++库,它里面包含了很多算法。它的License是MPL2。它支持多平台。 Eigen采用源码的方式提供给用户使用,在使用时只需要包含Eigen的头文件即可进行使用。之所以采用这种方式,是因为Eigen采用模板方式实现,由于模板函数不支持分离编译,所以只能提供源码而不是动态库的方式供用户使用。 我是使用PCL做的,对头文件 略有改动。

一、 矩阵的定义
Eigen中关于矩阵类的模板函数中,共有六个模板参数,常用的只有前三个。其前三个参数分别表示矩阵元素的类型、行数和列数。
矩阵定义时可以使用Dynamic来表示矩阵的行列数为未知。Eigen中无论是矩阵还是数组、向量,无论是静态矩阵还是动态矩阵都提供默认构造函数,也就是定义这些数据结构时都可以不用提供任何参数,其大小均由运行时来确定。矩阵的构造函数中只提供行列数、元素类型的构造参数,而不提供元素值的构造,对于比较小的、固定长度的向量提供初始化元素的定义。

二、 矩阵类型
Eigen中的矩阵类型一般都是用类似MatrixXXX来表示,可以根据该名字来判断其数据类型,比如”d”表示double类型,”f”表示float类型,”i”表示整数,”c”表示复数;Matrix2f,表示的是一个2*2维的,其每个元素都是float类型。
三、 数据存储
Matrix创建的矩阵默认是按列存储,Eigen在处理按列存储的矩阵时会更加高效。如果想修改可以在创建矩阵的时候加入参数,如:
Matrix Acolmajor;
Matrix Arowmajor;
四、 动态矩阵和静态矩阵
动态矩阵是指其大小在运行时确定,静态矩阵是指其大小在编译时确定。
MatrixXd:表示任意大小的元素类型为double的矩阵变量,其大小只有在运行时被赋值之后才能知道。Matrix3d:表示元素类型为double大小为3*3的矩阵变量,其大小在编译时就知道。在Eigen中行优先的矩阵会在其名字中包含有row,否则就是列优先。Eigen中的向量只是一个特殊的矩阵,其维度为1而已。

五、 矩阵元素的访问
在矩阵的访问中,行索引总是作为第一个参数,Eigen中矩阵、数组、向量的下标都是从0开始。矩阵元素的访问可以通过”()”操作符完成。例如m(2, 3)既是获取矩阵m的第2行第3列元素。
针对向量还提供”[]”操作符,注意矩阵则不可如此使用。

六、设置矩阵的元素
在Eigen中重载了”<<”操作符,通过该操作符即可以一个一个元素的进行赋值,也可以一块一块的赋值。另外也可以使用下标进行赋值。
七、重置矩阵大小
当前矩阵的行数、列数、大小可以通过rows()、cols()和size()来获取,对于动态矩阵可以通过resize()函数来动态修改矩阵的大小。注意:(1)、固定大小的矩阵是不能使用resize()来修改矩阵的大小;(2)、resize()函数会析构掉原来的数据,因此调用resize()函数之后将不能保证元素的值不改变;(3)、使用”=”操作符操作动态矩阵时,如果左右两边的矩阵大小不等,则左边的动态矩阵的大小会被修改为右边的大小。
八、如何选择动态矩阵和静态矩阵
对于小矩阵(一般大小小于16)使用固定大小的静态矩阵,它可以带来比较高的效率;对于大矩阵(一般大小大于32)建议使用动态矩阵。注意:如果特别大的矩阵使用了固定大小的静态矩阵则可能会造成栈溢出的问题。
九、 矩阵和向量的算术运算
在Eigen中算术运算重载了C++的+、-、*
(1)、矩阵的运算
提供+、-、一元操作符”-”、+=、-=;二元操作符+/-,表示两矩阵相加(矩阵中对应元素相加/减,返回一个临时矩阵);一元操作符-表示对矩阵取负(矩阵中对应元素取负,返回一个临时矩阵);组合操作法+=或者-=表示(对应每个元素都做相应操作);矩阵还提供与标量(单一数字)的乘除操作,表示每个元素都与该标量进行乘除操作;
(2)、求矩阵的转置、共轭矩阵、伴随矩阵
可以通过成员函数transpose()、conjugate()、adjoint()来完成。注意:这些函数返回操作后的结果,而不会对原矩阵的元素进行直接操作,如果要让原矩阵进行转换,则需要使用响应的InPlace函数,如transpoceInPlace()等;
(3)、矩阵相乘、矩阵向量相乘
使用操作符*,共有=两种操作符;
下面这一段参考博客:https://blog.csdn.net/yang_q_x/article/details/52383289
需要注意的是,在做矩阵计算是,用的是循环语句,所以是串行计算的方式。
Eigen还提供了一些常用的变换函数:transpose(),转置操作:conjugata(),共轭操作;adjoint(),共轭转置操作;需要注意的是这些是非原位操作,例如a = [1, 2; , 3, 4] 那么a = a.transpose() 得到的a为[1, 2, 2, 4],这样就产生了所粗。原位转置操作可以使用transposeInPlace() 函数。

矩阵乘法是一个特殊的运算,为了防止上述的错误,矩阵与矩阵相乘都会使用临时变量,例如m = m* m; 在实际编译的时候是tem = m* m; m = tem; 如果在乘法中你可以确定不会有错误的产生,那么可以使用noaliasd()函数来避免产生临时变量,例如:c.noalias() += a * b;
Eigen还提供了dot()点乘函数和cross()叉乘函数。其中dot可以针对任意两个长度相等的向量,而叉乘只能是两个三维向量,例如Vector3d v(1, 2, 3); Vector3d w(0, 1, 2); 那么v.dot(w) 得到的结果是8(等价于v.adjoint() * w),v.corss(w)得到的结果是(1; -2; 1)。

(4)、矩阵的块操作
有两种使用方法:
matrix.block(i,j, p, q) : 表示返回从矩阵(i, j)开始,每行取p个元素,每列取q个元素所组成的临时新矩阵对象,原矩阵的元素不变;matrix.block(i, j) :可理解为一个p行q列的子矩阵,该定义表示从原矩阵中第(i, j)开始,获取一个p行q列的子矩阵,返回该子矩阵组成的临时矩阵对象,原矩阵的元素不变;

(5)、向量的块操作
获取向量的前n个元素:vector.head(n);
获取向量尾部的n个元素:vector.tail(n); 获取从向量的第i个元素开始的n个元素:vector.segment(i,n); Map类:在已经存在的矩阵或向量中,不必拷贝对象,而是直接在该对象的内存上进行运算操作。

  1. 从http://eigen.tuxfamily.org/index.php?title=Main_Page下载最新稳定版本3.2.5,解压缩;

  2. 新建一个vs2013 TestEigen控制台工程,将Eigen文件所在目录加入到工程属性的C/C++附加包含目录中,这样就可以使用Eigen中的函数了;

  3. TestEigen.cpp文件中的内容为:

//#include “stdafx.h”//原博客中用的是这个,但是我的电脑无法找到,于是用下面这三行替换。
#include
#include “stdlib.h”
#include
#include
#include
//十、eigen的使用
using namespace std;
using namespace Eigen;
template
static void matrix_mul_matrix(T* p1, int iRow1, int iCol1, T* p2, int iRow2, int iCol2, T* p3)
{
if (iRow1 != iRow2) return;
//列优先 //Eigen::Map< Eigen::Matrix > map1(p1, iRow1, iCol1); //Eigen::Map< Eigen::Matrix > map2(p2, iRow2, iCol2); //Eigen::Map< Eigen::Matrix > map3(p3, iCol1, iCol2); //行优先 Eigen::Map< Eigen::Matrix > map1(p1, iRow1, iCol1); Eigen::Map< Eigen::Matrix > map2(p2, iRow2, iCol2); Eigen::Map< Eigen::Matrix > map3(p3, iCol1, iCol2); map3 = map1 * map2;

}
int main(int argc, char* argv[])
{
//1. 矩阵的定义
cout << “1. 矩阵的定义” << endl;
Eigen::MatrixXd m(2, 2);
Eigen::Vector3d vec3d;
Eigen::Vector4d vec4d(1.0, 2.0, 3.0, 4.0);
//2. 动态矩阵、静态矩阵 cout << "2. 动态矩阵、静态矩阵" << endl; Eigen::MatrixXd matrixXd; Eigen::Matrix3d matrix3d; //3. 矩阵元素的访问 cout << "3. 矩阵元素的访问" << endl; m(0, 0) = 1; m(0, 1) = 2; m(1, 0) = m(0, 0) + 3; m(1, 1) = m(0, 0) * m(0, 1); std::cout << m << std::endl << std::endl; //4. 设置矩阵的元素 cout << "4. 设置矩阵的元素" << endl; m << -1.5, 2.4, 6.7, 2.0; std::cout << m << std::endl << std::endl; int row = 4; int col = 5; Eigen::MatrixXf matrixXf(row, col); matrixXf << 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20; std::cout << matrixXf << std::endl << std::endl; matrixXf << Eigen::MatrixXf::Identity(row, col); //Identity是单位矩阵的意思:Identity matrix std::cout << matrixXf << std::endl << std::endl; //5. 重置矩阵大小 cout << "5. 重置矩阵大小" << endl; Eigen::MatrixXd matrixXd1(3, 3); m = matrixXd1; std::cout << m.rows() << "" << m.cols() << std::endl << std::endl; //6. 矩阵运算 cout << "6. 矩阵运算" << endl; m << 1, 2, 7, 3, 4, 8, 5, 6, 9; std::cout << m << std::endl; matrixXd1 = Eigen::Matrix3d::Random(); m += matrixXd1; std::cout << m << std::endl << std::endl; m *= 2; std::cout << m << std::endl << std::endl; std::cout << -m << std::endl << std::endl; std::cout << m << std::endl << std::endl; //7. 求矩阵的转置、共轭矩阵、伴随矩阵 cout << "7. 求矩阵的转置、共轭矩阵、伴随矩阵" << endl; std::cout << m.transpose() << std::endl << std::endl; std::cout << m.conjugate() << std::endl << std::endl; std::cout << m.adjoint() << std::endl << std::endl; std::cout << m << std::endl << std::endl; m.transposeInPlace(); std::cout << m << std::endl << std::endl; //8. 矩阵相乘、矩阵向量相乘 cout << "8. 矩阵相乘、矩阵向量相乘" << endl; std::cout << m*m << std::endl << std::endl; vec3d = Eigen::Vector3d(1, 2, 3); std::cout << m * vec3d << std::endl << std::endl; std::cout << vec3d.transpose()*m << std::endl << std::endl; //9. 矩阵的块操作 cout << "9. 矩阵的块操作" << endl; std::cout << m << std::endl << std::endl; std::cout << m.block(1, 1, 2, 2) << std::endl << std::endl; std::cout << m.block<1, 2>(0, 0) << std::endl << std::endl; std::cout << m.col(1) << std::endl << std::endl; std::cout << m.row(0) << std::endl << std::endl; //10. 向量的块操作 cout << "10. 向量的块操作" << endl; Eigen::ArrayXf arrayXf(10); arrayXf << 1, 2, 3, 4, 5, 6, 7, 8, 9, 10; std::cout << vec3d << std::endl << std::endl; std::cout << arrayXf << std::endl << std::endl; std::cout << arrayXf.head(5) << std::endl << std::endl; std::cout << arrayXf.tail(4) * 2 << std::endl << std::endl; //11. 求解矩阵的特征值和特征向量 cout << "11. 求解矩阵的特征值和特征向量" << endl; Eigen::Matrix2f matrix2f; matrix2f << 1, 2, 3, 4; Eigen::SelfAdjointEigenSolver eigenSolver(matrix2f); //形式就是这个形式,遇到高维的就直接用高维的替换掉matrix2f。 if (eigenSolver.info() == Eigen::Success) { std::cout << eigenSolver.eigenvalues() << std::endl << std::endl; std::cout << eigenSolver.eigenvectors() << std::endl << std::endl; }//12. 类Map及动态矩阵的使用 cout << "12. 类Map及动态矩阵的使用" << endl; int array1[4] = { 1, 2, 3, 4 }; int array2[4] = { 5, 6, 7, 8 }; int array3[4] = { 0, 0, 0, 0 }; matrix_mul_matrix(array1, 2, 2, array2, 2, 2, array3); for (int i = 0; i < 4; i++) std::cout << array3[i] << std::endl; return 0;

}
参考文献:
  1. http://blog.csdn.net/augusdi/article/details/12907341

  2. http://www.docin.com/p-863098431.html

  3. http://www.360doc.com/content/15/0325/15/21172899_457946100.shtml

  4. http://www.360doc.com/content/15/0413/22/21172899_463003614.shtml

【C++小知识——VS2013 MFC基于对话框编程】GitHub:https://github.com/fengbingchun/Eigen_Test

    推荐阅读