windows核心编程(第5版)读书笔记三

第六章节 线程基础
创建线程,要使用_beginthreadex来代替WAPI提供的CreateThread。因为,要从编译器角度来创建。从用户角度至少看起来没有依赖OS。但事实上,里面还是用了CreateThread.
同样,杀线程,使用_endthreadex.
注:用以上两个库函数的原因是,因为,如果你用了signal函数,那么就要用_end函数来清理资源,可是那样,你就画不圆上下文了。同时使用时要注意有EX来标识的,因为存在着旧的弃用的函数。
CloseHandle是可以传已经被清理的或伪句柄的,只是它会返回false,并且对error置成ERROR_INVALID_HANDLE。
TerminalThread是异步的,只是发信号。要确定被杀的线程死了,要用WaitForSingleObject,向其传递线程句柄来守候。原理就是,线程的内核对象,当引用计数减为0时,会变成激发状态,有信号状态。
GetExitCodeThread是检查线程退出代码的。如果线程还没有退出,返回是STILL_ACTIVE宏的值。如果已经退出,返回true,并有相应值。
微软提供的C/C++库用于本机的开发。
libCMt.lib
库的静态链接发行版本
libCMtD.lib
库的静态链接调试版本
MSVCRt.lib
导入库,用于动态链接MSVCR80.dll(默认库)
MSVCRtD.lib
导入库,用于动态链接MSVCR80D.dll
MSVCMRt.lib
导入库,.net的托管/本机代码混合
MSVCURt.lib
导入库,.net的MSIL代码
线程句柄自获函数:
几乎所有的WAPI函数都要在第一参数传句柄的,所以,当你突然眼前一亮,想用WAPI了,这第一个参数必须难不住你呀。
HANDLE GetCurrentProcess();
HANDLE GetCurrentThread();
注意:以上两函数返回的是“伪句柄”
原因:
1)它们不会在进程句柄表中新建句柄,当然也不会影响引用计数。当然,CloseHandle()多释放一次,程序不死,只是它返回false。
2)它们返回的句柄要根据运行所在的进程和线程来关联。比如,在父线程中调用了,返回的句柄即使以参数传给子进程,则其指向仍然是子线程的。所以这一点有些像虚函数中的虚指针,只能意会不能言传了。
当然,有时用线程ID做些逻辑时,可以使用:
DWORD GetCurrentProcessId();
DWORD GetCurrentThreadId();
当然,如果你有了ID,你还可以换成句柄。
OpenThread(),下面示例一下转换办法并且,给出一个对进程优先级操作的技巧。
VOID SuspendProcess(DWORD dwProcessID, BOOL fSuspend)
{
     HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD,dwProcessID);
     if(hSnapshot != INVALID_HANDLE_VALUE)
     {
          //walk the list of threads
          THREADENTRY32 te =  {sizeof(te)};
          BOOL fOK = Thread32First(hSnapshot, &te);
          for(; fOK; fOK = Thread32Next(hSnapshot, &te))
          {
              if(te.th32OwnerProcessID == dwProcessID)
               {
                    //主角登场
                    HANDLE hThread = OpenThread(THREAD_SUSPEND_RESUME, FALSE, te.th32ThreadID);
                    //略过对hThread的判断
                    if(fSuspend)
                         SuspendThread(hThread);
                    else
                         ResumeThread(hThread);
                    CloseHandle(hThread);
               }
          }//endfor
          CloseHandle(hSnapshot);
     }
}
最后,再赠送两个函数用于获取进程,线程运行的时间。
GetProcessTimes(),GetThreadTimes()
第七章节 线程调度,优先级和关联性
线程可以自己挂起,但不能自己恢复,并且,挂几次要应该恢复几次(ResumeThread)。挂起可以在线程生成时以参数传入,也可以用SuspendThread来人工自由操作。
第八章节 用户模式下的线程同步
技巧:
原子操作的系列WAPI函数:InterLocked*
+ExchangeAdd
+Increment
+ExchangePointer
volatile关键字,用来声明,后面的变量不能被优化,要去不断从内存来读取。
进阶一段:CRITICAL_SECTION结构和EnterCriticalSection和LeaveCriticalSection
要声明个全局的CS变量,然后用前初始,用后删除。
TryEnterCriticalSection比较灵活,做人当如此,能锁定就锁定段,没有段可用时,就立刻通知调用者。
同时,也不要把初始化关键段看低,因为,能避免交给内核态就晚点交,不然,上下文切换的步骤很耗时,耗资源的。所以,给初始化传值或用Set来设置抢段的重试时间,InitializeCriticalSectionAndSpinCount(p1,p2),p1是句柄了,p2大约4000。
注意:
线程抢锁的顺序要一致,否则死锁,即在锁包锁的情况下。
关键段的使用只能在一个进程内来控制其中众线程的同步,并且不能根据时间来等待。
进阶二段:条件变量
线程想把锁释放并把自己阻塞,就使用条件变量。
注意,这时,你得玩两个内核对象才行,即条件变量,必须配合锁。
首先看看这个阻塞函数,我特喜欢微软用sleep来前缀,因为,可读性很高。体现了两层意思:1,这是阻塞的,2,这是有时间参数的,时间到了没拿到条件变量就是false.
SleepConditionVariableSRW或SleepConditionVariableCS看吧,后缀又说明了要配合的锁。够意思。
我不够意思了,不列参数,自己去查手册喽。
有了Sleep就得有Wake吧。它会使等待同一个条件变量被触发的线程得到锁并返回。然后就干活呗,但得到锁了就得释放它。但它不会同时唤醒其它正在等待同一个条件变量的线程。
要看自己的实际需要。反正也是有WakeAll*和共享锁和独占锁来设计。
第九章节 内核态用内核对象进行线程同步
进程和线程内核对象在操作系统的处理上一样设计的。见笔记二的进程描述。
本章节介绍了另外的内核对象来帮助我们玩转线程同步。
1,事件
2,可等待的计时器
3,信号量
4,互斥量
头大吧,不过,我们要想掌握它,必须用不同的维度和结构去3D它。
首先,了解基础,或者说这个是第一个维度。
前进了解了进程和线程,有信号和无信号的规则,那么,这四个对象呢,look
事件:
引用计数器
自动重置/手动重置———–初始参数方式,CreateEvent
是否被触发——————-函数控制,SetEvent,ResetEvent
手动重置事件:
被触发时:等待此事件的所有线程都是会变成可调度状态。
自动重置事件:
被触发时:等待此事件的一个线程,只有一个线程会变成可调度状态。
因为自动重置会在一个线程得到事件对象后,自动把自己变成未触发状态。系统代劳的。
可等待的计时器:
指定时间或每隔一定时间触发
引用计数器
自动重置/手工重置——-初始化方式,CreateWaitableTimer,和事件一样没有其它的设置方式
SetWaitTimer是生成了内核对象后,需要进一步应用时的必经之路。因为,创建后,计时器都是属于未触发状态。
信号量:
引用计数器
最大资源量————-池里的资源总数
当前资源数————-目前应用了资源的数量,用RealseSemaphore来递增
互斥量:
引用计数器
线程ID———–内部自己管理,当计数为1时,则用调用的当前线程ID来填充。
递归计数———是否要触发

windows核心编程(第5版)读书笔记四

第19–20章节 dll的基础和高级技术
入口点函数:DllMain()
一般用来执行一些进程,线程有关的初始化和清理工作。要么不实现它,要么实现正常,返回true,否则,dll可能就不能被使用。
注意:
区分大小写的,否则就是无用的。
隐式调用dll时,系统启动时就会用到DllMain(),而显式调用时,在LoadLibraryex中来调用。并且,切入点是DLL_PROCESS_ATTACH
当引用了dll的exe要建立个新线程时,会检查所以已经被调入进程空间的dll的DllMain。并传入DLL_THREAD_ATTACH。有一个例外就是主线程切入仍以process来通知dll.

VC6工程项目改名

首先,网上找了个工具改名的,VCRename用了一下成功,注意新生成的目录中,dsw和dsp文件一定要改过来了。
然后,用新的改名后的工程编译出新程序。
但是,如果你的旧程序是个互斥的机制,即只能启动一个实例的情况。
那么,你会发现,虽然,你用改名工具把文件和工程都改了,但是新程序和改名前的程序不能同时启动。
差在哪里呢。
就是app_title.往细了说是,底层的m_pszAppname还在共同一个,并没有变化成功,所以把这个变量改名了,程序才不会被互斥的。那么什么会关联这个变量呢。就是资源文件。但有人说改名工具已经把资源文件的名字改了。可是其中的内容并没有变,这是原理了。
所以,打开资源文件的页签,找”String Table”.
在表格中找到,afx_ids_app_title 把它的值改名同于你的新名字,然后再编译后,新旧两程序同时可启动并不互斥了。

window开发之项目宏定义

转来一个文章,对VC6下项目建立和解决编译问题时,很有帮助。
常见的编译参数VC建立项目时总会定义”Win32″。控制台程序会定义”_CONSOLE”,否则会定义”_WINDOWS”。Debug版定义”_DEBUG”,Release版定义”NDEBUG”
  与MFC DLL有关的编译常数包括:
  _WINDLL 表示要做一个用到MFC的DLL
  _USRDLL 表示做一个用户DLL(相对MFC扩展DLL而言)
  _AFXDLL 表示使用MFC动态链接库的 regular DLL
  _AFXEXT 表示要做一个MFC扩展DLL
  所以:
  Regular, statically linked to MFC _WINDLL,_USRDLL
  Regular, using the shared MFC DLL _WINDLL,_USRDLL,_AFXDLL
  Extension DLL _WINDLL,_AFXDLL,_AFXEXT
Building Your DLL
When compiling regular DLLs that statically link to MFC, the symbols “_USRDLL” and “_WINDLL” must be defined. Your DLL code must also be compiled with the following compiler switches:
•/D_WINDLL      signifies the compilation is for a DLL
•/D_USRDLL      specifies you are building a regular DLL
When compiling regularDLLs that statically link to MFC, the symbols “_USR DLL” and”_WINDLL” must be defined. Your DLL code must also be compile dwith the following compiler switches:
When compiling regular DLLs that dynamicallylink to MFC, you must define t he above symbols and use the above compilerswitches. Additionally, the sy mbol “_AFXDLL” must be definedand your DLL code must be compiled with:
•/D_AFXDLL     specifies that you are building a regular DLL that dynamicall y links to MFC
The interfaces (APIs) between the application and the DLL must beexplicitlyexported. It is recommended that you define your interfaces to be lowbandw idth, sticking to C interfaces where possible. More direct C interfaces areeasi er to maintain than more complex C++ classes.
Place your APIs in aseparate header that can be included by both C and C++files (that way you won’tlimit your DLL customers to C++ programmers). Se e the header ScreenCap.h in theMFC Advanced Concepts sample DLLScreen Cap for an example. To export yourfunctions, enter them in theEXPORTSs ection of your moduledefinition file (.DEF) or include__declspec(dllexpor t)on yourfunction definitions. Use__declspec(dllimport)to import thesefunctions into the client executable.
You must add theAFX_MANAGE_STATEmacro at the beginning of all the e xportedfunctions in regular DLLs that dynamically link to MFC to set the curr ent modulestate to the one for the DLL. This is done by adding the followingline of codeto the beginning of functions exported from the DLL:
AFX_MANAGE_STATE(AfxGetStaticModuleState( ))
WinMain->DllMain
The MFC library defines the standard Win32DllMain entry point that initializ es yourCWinAppderived object as in a normal MFC application. Placeall DLL-specific initialization in theInitInstancememberfunction as in a normal MFC application.

最近碰到问题是,一个静态库,没有编译成多线程选项,致使在console中使用正常,新建一个mfc app中使用就不成了。
提示了一堆和CTYPE.h中定义的pctype,timezone,mb_*类的错误。
后来,把静态库,用多线程重编译,并且,用“不定义所有宏”选项,置了一下,然后,静态库就可以被mfc exe来使用了,虽然库并不依赖MFC。当然,此前有winsock的重定义的问题。后来在stdafx.h中加了winsock2.h的引用后,就解决了。

VC6的环境小结

安装:
现在主要有win7,win10,但后者还没听说可以装成功。不过好在有虚机嘛。所以,只聊下win7的VC6安装。
VC6的安装源你总应该拿到,最好是SP6的。
如果是英文版本,安装会少些步骤,有一个是overwrite JIT setting的对话框,网查后我选择了否。
如果是中文版本,请寻找帖子,名为:彻底解决兼容问题:Windows 7下载安装 Visual C++ 6_0(VC6) 全程图解
一步步安装即可,VSS和MSDN都可跳过不安装。
最重要的就是插件了,这个才是彰显尊贵的手段。
filetool,wndtab,VA,VC6lineNumber
一个都不能少,全破解版(自己搜吧)。
配置:
1,用标准库,要注意<>的内容两边加空格 ,并且#pragma   warning(disable:4786)来屏闭VC6中的使用标准库的警告。
2,用C++运行程序时总是出现这个错误BSCMAKE: error BK1510 : corrupt .SBR file ‘.\Debug\StdAfx.sbr’,在C/C++—>gernal中取消生成浏览信息的选项。
3,PROJECT->SETING->C/C++->PREPROCESSOR->定义 _AFXDLL,也就是C/C++选项中定义了宏  用_AFCDLL 取代 USERDLL 能解决很多nafxcwn.lib开头的链接错误。
4,Link选项中ignore default lib,根据方式设定,手工加/NODEFAULTLIB:或者填库名。
5,VC6下导出类中的静态成员需要“壳子”才可以调用,而在VS2012中,却直接可用。当不同的环境生成的dll或客户端相互调用时,要注意字符集问题,VC6并不是unicode的。
6,要声明通用函数时,可以不加;在{}后面,但应该声明为static,这样可以避免重复定义的报错。
7,string 的split算法,replace,trim需要自己写算法,最后找到使用模板的。
8,在有unicode的项目中,在循环中使用W2A()可能会有报错,或者提示为,run-time check fail #2 stack …,内存操作越界之类,在VS2012中项目–C\C++设置中,改掉一个设置,“基本运行时检查”从“两者(/RTC1,等同于 /RTCsu) (/RTC1)”换成默认值。其实出现它的问题,还是在于使用scanf时,“%02x”的操作数组应该至少是3,要包含个’\0’的。
9,项目是要供别人调用的dll,要在配置中使用/MD.
10,要通过exe来调度dll时,要配置debug session和work directory
11,当出现外部链接错误时,要先检查link中的lib文件,是否存在于项目目录中。并不需要dll,因为只是链接步骤。
12,字符集问题,VC6是基于MBCS的(有宏定义,当然可以强制成unicode),对于中文用两字节,而字母和数字用一个字节。而VS201X,都是用unicode默认的,所以也就存在于宽字符的结构了,和一系列转来转来的操作。

以Qtreeview为例介绍Qt的model/view/item框架

因为,Qtreeview是层次容器,所以会复杂。尤其是加子行的时候。
首先,要找到是哪里加子行。有两个思路:位置索引还是item
1)用model的位置索引方式,定位到要加子行的QModelIndex.
2)用item方式,即后台以批量的list加树时,找到item的位置。
3)用model,如果后台的批量item加完就释放,若无从找到,有一个神器就是Model->itemFromIndex(myparent);这是索引和后台item的桥。
后两种方式归纳来看,也算是从item入手了,而且推荐都使用Item方式加子行,不然,可能会陷入到后台model和view中的QModelIndex的不同步,那个问题会让你乱套的。
然后,找到了加子行的点,就是要找方法了。
1)item->appendRow(传入item的list);
2)Model->insertRows(0, 1, myparent); // 添加一行,注意参数是QModelIndex,要理解树模型中子节点的索引机制
虽然,model有自己的appendRow函数,但是,加一行是没问题,分层次加子行时还是不行的。
而且,在分别使用item对象和QModelIndex对象的Data()和setData()时要注意,默认的role参数,一个是0,一个是257.这是绝对的坑儿。
不然,你设置了,总感觉设置的数据为空,不显示。role是一个新维度的概念,使用很方便,只要传入和调出控制好了,是一大神器。
resizecolumncontent也是个不错的技巧,可以在你设置了model后重新调用,根据内容适应宽度。
代码有点乱:但可以上两棵树,并且都有子行。

  //测试绑定线路报文内容到树控件
  QList <QStandardItem *> items;
  QList <QStandardItem *> childItems;
  for (int i = 0; i < 4; ++i)
  {
  QStandardItem *item = new QStandardItem( QString (“item L%0” ).arg(i));
  if (0 == i)
  item->setCheckable( true );
  items.push_back(item);
  }
  lineModel->appendRow(items);
  for (int i = 0; i < 4; ++i)
  {
  for (int i = 0; i < 4; ++i)
  {
  QStandardItem *item = new QStandardItem( QString (“L%0” ).arg(i));
  if (0 == i)
  item->setCheckable( true );
  childItems.push_back(item);
  }
  items.at(i)->appendRow(childItems);
  //lineModel->setItem(i, 0, childItems.at(i));
  }
  items.clear();
  childItems.clear();
  int iRow = -1;
  for (int i = 0; i < 4; ++i)
  {
  for (int i = 0; i < 3; ++i)
  {
  QStandardItem *item = new QStandardItem( QString (“item R%0” ).arg(i));
  if (0 == i)
  item->setCheckable( true );
  items.push_back(item);
  }
  //items.at(i)->appendRow(items);
  //normalModel->setItem(i, items.at(0));
  normalModel->appendRow(items);
  items.clear();
  iRow++;
  }
  //方式一,以setdata方式加子行
  //QModelIndex myparent = normalModel->index(iRow,0);
  // //myparent = normalModel->index(0, 0, myparent);
  // normalModel->insertRows(0, 1, myparent); // 添加一行
  // normalModel->insertColumns(0, 3, myparent); // 添加三列
  // ui.treeView_normal->reset();
  // ui.treeView_normal->setModel(normalModel);
  // ui.treeView_normal->update();
  // emit ui.treeView_normal->dataChanged(normalModel->index(0, 0), normalModel->index(0, 3, myparent));
  ////for (int i = 0; i<3; i++)
  ////{
  // QModelIndex index = normalModel->index(0, 0, myparent);
  // normalModel->setData(index, “kk”);
  // ui.treeView_normal->reset();
  // ui.treeView_normal->setModel(normalModel);
  // ui.treeView_normal->update();
  // emit ui.treeView_normal->dataChanged(normalModel->index(0, 0), index);
  // normalModel->insertColumns(0, 1, myparent); // 添加一列
  // index = normalModel->index(0, 1, myparent);
  // normalModel->setData(index, “ll”);
  // emit ui.treeView_normal->dataChanged(normalModel->index(0, 0), index);
  // ui.treeView_normal->update();
  // ui.treeView_normal->setModel(normalModel);
  // normalModel->insertColumns(0, 1, myparent); // 添加一列
  // index = normalModel->index(0, 2, myparent);
  // normalModel->setData(index, “mm”);
  // ui.treeView_normal->setModel(normalModel);
  // ui.treeView_normal->update();
  // //ui.treeView_normal->paintEvent()
  // emit ui.treeView_normal->dataChanged(normalModel->index(0, 0), index);
  // ui.treeView_normal->reset();
  ////}
  //myparent = lineModel->index(0,0);
  //QModelIndex tmp = lineModel->index(0, 0,myparent);
  // ui.treeView_line->setCurrentIndex(tmp);
  //方式二,以model的setitem方式加行
  QModelIndex myparent = normalModel->index(iRow, 0);
  for (int i = 0; i < 3; ++i)
  {
  QStandardItem *item = new QStandardItem( QString (“R%0” ).arg(i));
  if (0 == i)
  item->setCheckable( true );
  childItems.push_back(item);
  }
  //items.at(i)->appendRow(childItems);
  QStandardItem * tmp = normalModel->itemFromIndex(myparent);
  tmp->appendRow(childItems);
  childItems.clear();
  //normalModel->setItem(iRow, 0, childItems.at(0));
  QStandardItem *item = new QStandardItem( QString (“RE%0” ).arg(0));
  childItems.push_back(item);
  item = new QStandardItem ( QString( “RE%0” ).arg(1));
  childItems.push_back(item);
  item = new QStandardItem ( QString( “RE%0” ).arg(2));
  childItems.push_back(item);
  normalModel->appendRow(childItems);

静态编译Qt5.5并应用成果

一直为打包Qt开发的东东依赖库发愁。只好研究下静态编译,当然选个最新的版本。
环境如下:
win7 x86
VS2012
perl5.16.2
python34(32bit)
ruby21
Qt5addin1.2.4

说明:ruby安装时要把三个都选择上,QT5addin插件安装要特有耐心,不然总会觉得,程序假死了。(后来发现是装集成help文档时占时间,可以不装它的)

以上安装在一个独立的虚机,方便以后改造,重要的一点是,一编译就2-3个小时,你对着屏发呆嘛?
下载Qt5.5的源码,进入其目录,需要改的有两处:
<src目录>\qtbase\mkspecs\win32-msvc2012\qmake.conf.

将以下三处 -MD修改为 -MT

QMAKE_CFLAGS_RELEASE = -O2 -MT
QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO += -O2 -MT -Zi
QMAKE_CFLAGS_DEBUG = -Zi -MTd
当环境不同,聪明的你会找到需要更改的位置。5.5源码包是mkspecs/comon/msvc-desktop.conf里面改。

建立个批处理文件,如vs2012.build.bat
内容如下:

::配置路径
set QT5_DIR=C:\qt_tool\qt-everywhere-opensource-src-5.5.0-alpha
set THIRDPARTY_DIR=C:\qt_tool\Build
::如果您用mingw可以在这儿设置下您的mingw目录
set PATH=%PATH%;C:\Perl\site\bin;C:\Perl\bin;C:\Python34;C:\Ruby21\bin;
set PATH=%PATH%;%QT5_DIR%\bin;%QT5_DIR%\qtbase\bin;%QT5_DIR%\gnuwin32\bin;

::配置依赖,mingw的可能需要您手动加上库和头文件位置,vs的话您可以打开相应的VS* X86/64 本机命令提示符
::set SQLITE3SRCDIR=%THIRDPARTY_DIR%\sqlite
::set LIB=%LIB%;%THIRDPARTY_DIR%\icu\win32\lib;%THIRDPARTY_DIR%\icu\win32\libs;%THIRDPARTY_DIR%\openssl\openssl32\lib
::set INCLUDE=%INCLUDE%;%THIRDPARTY_DIR%\icu\win32\include;%THIRDPARTY_DIR%\openssl\openssl32\include
::set PATH=%PATH%;%THIRDPARTY_DIR%\icu\win32\bin;%THIRDPARTY_DIR%\openssl\openssl32\bin

::配置QT,为了在输入configure配置qt编译选项,我就直接写到bat了、、、
cd %QT5_DIR%
configure -prefix C:\QtSdk\Win32_static -opensource -confirm-license -static -platform win32-msvc2012 -release -c++11 -qt-sql-sqlite -qt-zlib -qt-libpng -qt-libjpeg -qt-freetype -no-angle -no-icu -opengl desktop -nomake examples -nomake tests -no-compile-examples -skip qtwebkit
把它保存。不提倡改那个bat文件,因为,webkit是不能静态编译的,并且它很耗时,并且很多选项都是经验之谈。
然后,找nmake去。在开始菜单里找”vs2012 x86本机工具命令指示行“,
打开,进入源码目录,执行批处理。

你的环境一致,定能configure过。注意,要清除前一次的垃圾,需要用nmake distclean
后面的事就是敲nmake,泡杯茶了。

有时,你真的nmake成功了,但是不一定能nmake install正常。但我坚信install只是一系列拷贝操作。你要的那些lib已经OK了,你可以部署的时候再用他们。

当然,你可以坚持找原因,nmake install成功。

注意,不要轻易改变源码的位置,或节省空间删除它。否则,上帝保佑你。

后记:
以为装了Qt5addin,打开就可以看到Qt5的菜单,错了,还要真的装个Qt sdk才行。
Qtcreator静态编译了一下,的确可用,但是无法部署到同为32的xp下。可能是因为,Qt使用的编译器仍然是VS2012的,所以,再用VS2012+Qt5addin试一次,何况这是我们目标。
不过,我发现一个坑,Qt5addin1.2.4根本和VS2012不兼容,而且这不会提示你。
1.2.3装后,开始真正的应用静态编译的成果了。

项目设置:

为了让exe能跑在xp上,需要设置在工程—-属性—配置属性–常规–平台工具集v110_xp

因为,我编译的lib都是realse的,所以把项目设成realse
改成(release为MT,debug为MTD)
在工程—-属性—配置属性—c/c++—代码生成—-运行库
选择为“多线程(/MT)”
这样设置可能是约定了对lib的调用方式。
否则,编译时报错:runtimelibrary
error LNK2038: 检测到“RuntimeLibrary”的不匹配项: 值“MT_StaticRelease”不匹配值“MD_DynamicRelease”

在工程—-属性—配置属性—链接器
本人的附加依赖项(备忘):$(QTDIR)\lib\Qt5Core.lib;$(QTDIR)\lib\Qt5Gui.lib;$(QTDIR)\lib\qtmain.lib;$(QTDIR)\lib\Qt5Widgets.lib;$(QTDIR)\plugins\platforms\qwindows.lib;$(QTDIR)\lib\Qt5PlatformSupport.lib;$(QTDIR)\plugins\platforms\qminimal.lib;$(QTDIR)\plugins\platforms\qoffscreen.lib;$(QTDIR)\lib\Qt5OpenGL.lib;$(QTDIR)\lib\Qt5OpenGLExtensions.lib;$(QTDIR)\lib\Qt5Sql.lib;winspool.lib;shlwapi.lib;rpcrt4.lib;$(QTDIR)\plugins\imageformats\qico.lib;$(QTDIR)\plugins\imageformats\qsvg.lib;$(QTDIR)\lib\Qt5Qml.lib;$(QTDIR)\lib\Qt5Quick.lib;comdlg32.lib;oleaut32.lib;imm32.lib;winmm.lib;glu32.lib;opengl32.lib;gdi32.lib;$(QTDIR)\lib\qtharfbuzzng.lib;kernel32.lib;user32.lib;shell32.lib;uuid.lib;ole32.lib;advapi32.lib;ws2_32.lib;mpr.lib;%(AdditionalDependencies)

上面配置解决了一个ub_buffer_create……destroy啥的编译错误。

QT5设置:
VS中设置好Qt versions为静态的sdk,然后在Qt project setting—–properties页的最后一个设置上。
即version属性选择下拉中的静态sdk(有时忘记它,其实主要开关在这里)

最后构建你的程序吧。不过还是有坑的。虽然没有报error了,但当你运行它会提示你:
……Failed to load platform plugin windows……

这次改main.cpp吧

#include
Q_IMPORT_PLUGIN (QWindowsIntegrationPlugin);

编译通过,这次把exe放到没有Qt5安装的xp下,都如愿运行,出画面了。

大胆的写Qt吧,一次编写,到处部署(很方便)

vim-ide技巧

乱码问题办法:以本人gvim为环境

set enc=cp936
set termencoding=chinese
language message cp936

export LANG=zh_CN.GBK
export LC_ALL=zh_CN.GBK

:help encoding-values

Image

“ctrl+]”—–光标会自动跳转到定义处
“ctrl+T”—–光标会从定义跳转回来
Tlist——–TagList窗口即出现在左侧
wm———–打开左侧两栏(文件和声明)
ctrl+Tab—–切换到前一个buffer,并在当前窗口打开文件;
ctrl+shift+Tab—切换到后一个buffer,并在当前窗口打开文件;
ctrl+箭头键—–可以切换到上下左右窗口中;
ctrl+h,j,k,l—-切换到上下左右的窗口中。

F12或:A或:AS,AV,AT或点击头文件后,gf
——–源码文件后,按F12即可以在c/h文件中切换,也可以通过输入:A实现.当使用了gf时,用ctrl+O来回退栈。
F3——将光标定位到要查找的内容上,按下F3,确定要查找的内容和搜索范围
F2——光标定位在需要添加书签的地方,按下ctrl+F2,即添加了书签.使用F2在书签之间正向切换,shift+F2反向切换。
Vimgrep Make ./*.c或在目录层vimgrep “content” **/*.cpp——–配合命令Cl,cn,cp,cw,copen,cclose
建立tags——cmd到源码目录,然后执行(本人环境下)“c:\Program Files\vim\vim73\ctags” -R *

sp,vs,vsp让人很爽的分屏

vi 查找忽略大小写
第一种方法:
/abc\c
第二种方法:
set ignorecase (或者简写 set ic)

linux下安装vim,在源光盘的包目录中依次装吧(前缀是vim-)
X11,common,enhanced,minimal

常用操作总结:
定律:

动作后,都进入插入模式
某些动作是返回了位置,前面可再加动作
动作,位置前都可以配合数值

动作:
i—插入–insert                         插入30x–30ix+esc键
I–当前行开始处插入
a–追加–append
x–删除当前,以字符为单位
X–删除之前
d–删除–delete
y–拷贝–copy
p–粘贴–paste
o–下方插行–open
O–上方插行open
u–撤消–undo
U–行撤消–undo
Ctrl+r–重做
c–更改–change
r–替换–replace
R–一直替换–replace,退格键是撤消替换
g–前往(gg文件首,G文件尾,数值G到行首)–go
f–查找–find
F–反向查找(向左)–find
t–到达和F区别于定位位置–to

位置:
w–移向下一个单词词首–word
W–同上,移动间隔不是单词而是字串
b–移向上一个单词词首–begin
B–同上,移动间隔包括了标点和符号
e–移向下一个单词词尾–end
E–同上,移动间隔包括了标点和符号
G–文件尾
^–行首非空字符
0–行首第一字符(同于home键,同于_键)
$–行尾,2$即下一行行尾,注意这是一个包括命令,即包括最后一个字符
hjkl–
H–屏幕范围内的左上角行,zt–headhome
M-屏幕范围内的中间行,zz–middle,大写可就是存盘退出了
L-屏幕范围内的左上角行,zb–last
%–对称符号的匹配定位
月光宝盒:
”–两位置,闪回
配合mark的扩展应用
[]最后修改的位置
Ctrl+o–跳回到更老的地方–older
——-i–跳回到更新的地方相当于tab

列块选择:

Ctrl+v,可视模式开启,在gvim中是使用ctrl+q

               v配合位置,即可选中欲操作的块,用一下o–other end来试试吧
     o    other end
     O    另一个对角
     ~    交换大小写
     U    转换为大写
     u    转换为小写
     r    以某个字符填充
     >    平移
     <    平移
     :set shiftwidth=4    "平移距离
     J    删除选中行的所有换行符
     gv    重复上次的可视选择------------这东东很好用
重复:

;–正向(用于ft,行内查找时)
,–反向(用于ft,行内查找时)
.–重复
屏幕操作:

ctrl+G–查看当前操作的文件和行数

Set ruler

Set number

Ctrl+u–向上滚半屏–up
Ctrl+d–向下滚半屏–down
——-e–向上多显一行one line Extra
——-y–向下多显一行

功能就是把当前行放到屏幕的上中下三个位置:(注此时光标不动所在屏幕动)
z+回车
z+.
z+-
前面都可以加行号码,注意不是行数.

当你想把光标放到屏幕的上下三个位置时(注此时屏幕内容不动,光标位置变化)
H
L

简单查询:
/+所查串正向
+所查串反向
备注:
字符 .*[]^%/?~$ 有特殊含义。如果你要查找它们,需要在前面加上一个
“”。
配合使用:

n,N

/<the>只查找the的句法

%s/old/new/g

简单修改:

x  表示  dl  (删除当前光标下的字符)
X  表示  dh  (删除光标左边的字符)
D  表示  d$  (删除到行尾)
C  表示  c$  (修改到行尾)
s  表示  cl  (修改一个字符)
S  表示  cc  (修改一整行)
.–重复最后一次的修改操作
组合拳:

     操作区域对
     <action>a<object> 和 <action>i<object>
   a是包含,i是inside
  • action可以是任何的命令,如 d (删除), y (拷贝), v (可以视模式选择)。
  • object 可能是: w 一个单词, W 一个以空格为分隔的单词, s 一个句字, p 一个段落。也可以是一个特别的字符:"、 '、 )、 }、 ]。

aw–a word

Is–inner sentence

as–a sentence

q!

e!

w!

Wq==ZZ
~ 大小写
ma 设书签
`a 定位书签
Ey,fb,ud
Set ic 区分大小写
Set autoindent
Set shiftwidth=4 设置缩进
vi一般用法
一般模式                             编辑模式                                     指令模式
h   左                               a,i,r,o,A,I,R,O                           :w   保存
j   下                                 进入编辑模式                                 :w!   强制保存
k   上                                 dd   删除光标当前行                       :q!   不保存离开
l   右                                 ndd   删除n行                                   :wq!   保存后离开
0   移动到行首                 yy   复制当前行                                 :e!   还原原始档
$   移动到行尾                 nyy   复制n行                                     :w   filename   另存为
H   屏幕最上                     p,P   粘贴                                           :set   nu   设置行号
M   屏幕中央                     u     撤消                                             :set   nonu   取消行号
L   屏幕最下                     [Ctrl]+r   重做上一个动作               ZZ   保存离开
G   档案最后一行             [ctrl]+z   暂停退出                         :set   nohlsearch       永久地关闭高亮显示
/work   向下搜索                                                         :sp   同时打开两个文档
?work   向上搜索                                                        [Ctrl]+w   两个文档设换
gg   移动到档案第一行                                        :nohlsearch         暂时关闭高亮显示
Vi同时编辑多文件
Vi -o file1.c file2.c

:e#1

:e#2

如果已经分屏
ctrl+W来切换(配合箭头方向键)

在linux里面遇到多行注释的时候,一个个去点,手有点累。
执行如下命令:
:.,+499 s/^/#/g
.    代表当前光标所在行
+499 和往后的499行
s/^/#/g 在行首加上#
:10,499 s/^/#/g
10   第十行开始
499 到第499行
其他都是一样的
本人根据以上摸索出多行注释的快捷技巧:
同理

:8,11 s/^////g

因为//是需要转义的,所以把//换成上面的#不就行了。同理要想在行首加入任何字符都是OK了。
正则表达式来查找或高亮:/#注释此为查找#(<w+>)_s*1
后台运算:ctrl+R = 2+2*3 enter
执行后看到结果了吧。
缩写替换:ab [缩写] [要替换的文字]
例子:ab asap as soon as possible
当忘记用root方式打开文件时的保存:
:w !sudo tee %
这会以root方式保存
自动补全:ctrl+n
ggVGg?说是能把全文加密,可是在gvim中没效果。
命令行下比较文件不同:
方法一:vimdiff [文件1] [文件2]
方法二:先用VSP,然后在第一窗口,diffthis,记得用diffoff来退出比较。
按时间回退文件:earlier 1m,文件回退到1分钟以前的状态,:later相反的操作
删除标记内文字:di[标记],这个应该是新瓶装老酒,我相信;di[标记]就是带标记删除了。
把VIM变成16进制编辑器:%!xxd成对的退出命令是:%!xxd -r
把内容变成html来高亮显示:%TOhtml或是%Tohtml(gvim是前者有效)

下面两个转来的参考图

Image

Image

Image