C++ 常用

1.线程处理

1.1 界面类设计

DWORD WINAPI GetExportFileInfoThreadFunc(LPVOID Iparam);
class CExportImageDlg : public CDialog
{
public:
//! 导出图像数据线程函数
friend DWORD WINAPI GetExportFileInfoThreadFunc(LPVOID Iparam);
//! 获取导出图像信息
void GetExportFileInfo()
{}
private:
//!导出线程句柄
HANDLE m_hExportImageInfo;
}

1.2 创建线程

//创建控制线程,获取导出图像信息
m_hExportImageInfo = ::CreateThread(NULL, 0, GetExportFileInfoThreadFunc, (LPVOID)this, 0, NULL);
DWORD WINAPI GetExportFileInfoThreadFunc(LPVOID Iparam)
{
	CExportImageDlg *pExportImageDlg = (CExportImageDlg *)Iparam;
	ASSERT(pExportImageDlg);
	if (pExportImageDlg)
	{
		pExportImageDlg->GetExportFileInfo();
	}
	
	return 0;
}


1.3 保证线程已经退出

	if (m_hExportImageInfo != NULL)
	{
		const int nMaxThreadExitTimes = 5;
		
		int nTimes = 0;
		while ((WaitForSingleObject(m_hExportImageInfo, 200) == WAIT_TIMEOUT) && (nTimes < nMaxThreadExitTimes))
		{
			nTimes++;
		}
		
		if (nTimes >= nMaxThreadExitTimes)
		{
			TerminateThread(m_hExportImageInfo, 0);
		}
		
		CloseHandle(m_hExportImageInfo);
		m_hExportImageInfo = NULL;
	}

VOID ExitThread(UINTfuExitCode ); 函数终止自己

1.4 线程同步

多个线程操作相同的数据时,一般是需要按顺序访问的,否则会引导数据错乱,无法控制数据,变成随机变量。为解决这个问题,就需要引入互斥变量,让每个线程都按顺序地访问变量。这样就需要使用EnterCriticalSection和LeaveCriticalSection函数。

CRITICAL_SECTION  m_crit;//一个临界区
::InitializeCriticalSection(&m_crit);//初始化临界区
::EnterCriticalSection(&m_crit);
//此处为线程函数内需要保护的数据
::LeaveCriticalSection(&m_crit);

1.5 设置线程优先级

线程优先级 =进程类基本优先级+线程相对优先级
BOOL SetThreadPriority(HANDLE hThread, int nPriority);

1.6 判断线程是否结束

获取线程退出码: BOOL WINAPIGetExitCodeThread( HANDLE hThread, LPDWORD lpExitCode);
如果线程尚未结束,lpExitCode带回来的将是STILL_ALIVE。

1.7 挂起与恢复线程

挂起线程:DWORD SuspendThread(HANDLEhThread);
恢复线程:DWORD ResumeThread(HANDLEhThread);

1.8 多线程操作list,使用Mutex

#ifndef F_Test_20171026_18_27_JHASKDFJHASF_H_
#define F_Test_20171026_18_27_JHASKDFJHASF_H_

#include <stdio.h>
#include "Windows.h"
#include "afxmt.h"

/*
1. 测试线程同步,使用互斥锁
2. 多线程操作list,容易引起奔溃
3. MFC需要使用CMutex同步
*/
typedef struct TestData
{
	int nCom;
	list<CString> strDataList;
}sTestData;

list<sTestData> g_StrList;

CMutex g_MutexThread;
DWORD WINAPI ThreadPushDataToListFunc(LPVOID pParam);
DWORD WINAPI ThreadPrintDataFunc(LPVOID pParam);

 
void TestThreadMutex()
{
	HANDLE hThreadPrint = CreateThread(NULL, 0, ThreadPrintDataFunc, NULL, 0, 0);
	CloseHandle(hThreadPrint);
	hThreadPrint = NULL;

	HANDLE hThreadPush = CreateThread(NULL, 0, ThreadPushDataToListFunc, NULL, 0, 0);
	CloseHandle(hThreadPush);
	hThreadPush = NULL;
}

DWORD WINAPI ThreadPushDataToListFunc(LPVOID pParam)
{	
	sTestData sTestDataTemp;
	for(int i=0; i<100000; i++)
	{
		sTestDataTemp.nCom = i;

		sTestDataTemp.strDataList.clear();
		sTestDataTemp.strDataList.push_back("aaaa");
		sTestDataTemp.strDataList.push_back("bbbb");
		sTestDataTemp.strDataList.push_back("cccc");

		g_MutexThread.Lock();
		g_StrList.push_back(sTestDataTemp);
		g_MutexThread.Unlock();

		TRACE("\n-----SendData----%d\n", i);

		Sleep(2000);
	}

	return 0;
}

DWORD WINAPI ThreadPrintDataFunc(LPVOID pParam)
{
	list<CString>::iterator itStr;
	list<sTestData>::iterator itTest;

	while(1)
	{
		g_MutexThread.Lock();
		if(g_StrList.size() > 0)
		{
			for(itTest=g_StrList.begin(); itTest!=g_StrList.end(); itTest++)
			{
				TRACE("\n-----AcceptData----%d =>", itTest->nCom );

				for (itStr=itTest->strDataList.begin(); itStr!=itTest->strDataList.end(); itStr++)
				{
					CString strTemp = *itStr;
					TRACE("%s ", strTemp);
				}

				itTest->strDataList.clear();
				Sleep(10);
			}

			g_StrList.clear();
		}	
		g_MutexThread.Unlock();

		TRACE("\n------------------------------------------------------------------\n");
		Sleep(2000);
	}

	return 0;
}

#endif//F_Test_20171026_18_27_JHASKDFJHASF_H_


2.Gdi+ 绘图,绘字(MFC环境)

2.1 下载库

从网上下载相关Gdi+的库文件包,将文件拷贝到工程目录下。

下载地址:点击打开链接

2.2加载库

在文件 “StdAfx.h” 添加以下代码

#include "GDIPlus/Includes/GdiPlus.h"
using namespace Gdiplus;
#pragma comment(lib, "GdiPlus.lib")

2.3 启动Gdi+

使用前先启动,在使用之前添加以下代码

ULONG_PTR m_gdiplusToken;
GdiplusStartupInput m_gdiplusStartupInput;

GdiplusStartup(&m_gdiplusToken, &m_gdiplusStartupInput, NULL);


2.4 退出Gdi+

不使用时,记得关闭相关操作

GdiplusShutdown(m_gdiplusToken);


2.5 绘图

//绘图
void C***View::DrawBmpPicture(CDC *pDC, int nRectLeft, int nRectTop, CString strBmpPath, int nPictureWidth, int nPictureHeight)
{
 	HDC hdc = pDC->GetSafeHdc(); //gdi+ 处理对象
 	Graphics mygraphics(hdc);

	//CString转换为WCHAR
	int	 nLength	 = strlen(strBmpPath)+1;

	const char* tempStr = strBmpPath; 
	int	 newLength = MultiByteToWideChar(CP_ACP, 0, tempStr, nLength, NULL, 0);

	WCHAR	chPicturePath[128] = {0}; 
	MultiByteToWideChar(CP_ACP, 0, strBmpPath, nLength, chPicturePath, newLength); 
	
	//显示工位图片
	Image image(chPicturePath, FALSE); 
	Image* pThumbnail = image.GetThumbnailImage(nPictureWidth, nPictureHeight, NULL, NULL);//缩略图片 
	mygraphics.DrawImage(pThumbnail, nRectLeft, nRectTop, pThumbnail->GetWidth(), pThumbnail->GetHeight());
	if (pThumbnail)
	{	
		delete pThumbnail;
	}

	return ;
} 


2.6 绘字

//绘字
void C***View::DrawText(CDC *pDC, int nTextX, int nTextY, CString strText, DOUBLE fTextFont, Color colorText)
{
	HDC hdc = pDC->GetSafeHdc(); //gdi+处理对象
 	Graphics mygraphics(hdc);

	//CString转换为WCHAR
	strText.Format(strText);
	const char* tempStr = strText;

	int nLength		 = strlen(tempStr)+1;
	int newLength = MultiByteToWideChar(CP_ACP, 0, tempStr, nLength, NULL, 0);
	
	WCHAR  chStitionID[60] = {0};
	MultiByteToWideChar(CP_ACP, 0, strText, nLength, chStitionID, newLength);
	
	//显示文字		   
	SolidBrush brush(colorText);
	FontFamily fontFamily(L"Latha"); 
	Font font(&fontFamily, (float)fTextFont, FontStyleRegular, UnitInch);
	PointF pointF((float)nTextX, (float)nTextY); //输出坐标			
	mygraphics.DrawString(chStitionID, -1, &font, pointF, &brush);	

	return ;
}   

3.VC程序实现重启

void CTestDlg::OnBnClickedBtRestart()
{
	::PostMessage(AfxGetMainWnd()->m_hWnd, WM_SYSCOMMAND, SC_CLOSE, NULL);

	//获取exe程序当前路径  
	extern CDxRayAPITestApp theApp;//当前APP名称
	TCHAR szAppName[MAX_PATH];  
	:: GetModuleFileName(theApp.m_hInstance, szAppName, MAX_PATH);  
	CString strAppFullName;  
	strAppFullName.Format(_T("%s"), szAppName);  

	//重启程序  
	STARTUPINFO StartInfo;  
	PROCESS_INFORMATION procStruct;  
	memset(&StartInfo, 0, sizeof(STARTUPINFO));  
	StartInfo.cb = sizeof(STARTUPINFO);  
	::CreateProcess(  
		(LPCTSTR)strAppFullName,  
		NULL,  
		NULL,  
		NULL,  
		FALSE,  
		NORMAL_PRIORITY_CLASS,  
		NULL,  
		NULL,  
		&StartInfo,  
		&procStruct); 
}

 

4.VC编程,获取上一次的错误

     MSDN中通常会建议用GetLastError()来获取上一次调用系统API函数错误原因。 但是,GetLastError()返回的只是一个错误值(双字节数值(DWORD),具体请参照返回值列表:点击打开链接),没有说明具体的原因。因此可以用FormatMessage函数,获取产生异常的文字信息。需包含头文件:#include <windows.h>
实例如下:
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <assert.h>

using namespace std;

#define MAX_PATH 260
#define BUF_SIZE 5
#define WRITE_FILE_SIZE 24

void TestGetLastErrorFun(char **pError);

int main(void)
{
	char *pszBufW = new char(WRITE_FILE_SIZE);
	memset(pszBufW, 0, WRITE_FILE_SIZE);

	char szFilePath[MAX_PATH] = {0};
	GetCurrentDirectory(MAX_PATH, szFilePath);
	strncat(szFilePath, "\\TestWrite_2.txt", MAX_PATH);

	FILE *pFile = fopen(szFilePath, "r");		 //打开文件,读数据
	TestGetLastErrorFun(&pszBufW);			//此处调用,通过输出参数返回错误原因, 比如没找到文件,内存不足等
	cout <<endl <<"LastError: " <<pszBufW <<endl;	//输出错误原因

	if (!pFile)
	{	
		assert(pFile);
		return -1;
	}
	
	if(pszBufW)
	{
		delete pszBufW;
		pszBufW = NULL;
	}

	if(pFile)
	{
		fclose(pFile);
		pFile = NULL;
	}

	system("pause");
	return 0;
}

void TestGetLastErrorFun(char **pError)
{
	FormatMessage(
		FORMAT_MESSAGE_ALLOCATE_BUFFER |
		FORMAT_MESSAGE_FROM_SYSTEM |
		FORMAT_MESSAGE_IGNORE_INSERTS,
		NULL,
		GetLastError(),
		MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language 
		(LPTSTR) &(*pError),
		0,
		NULL);
}



5.RAII

将资源(如FILE*,HANDLE等)抽象为类,用局部对象来表示资源,把管理资源的任务转化为管理局部对象的任务。这就是RAII惯用法的真谛。

具体可参考:点击打开链接

用法1:需要用时,创建 新对象 RaiiFile

文件:RAII.h 

#ifndef TEST_RAII_2017_3_18_SKDJFGH_H_
#define TEST_RAII_2017_3_18_SKDJFGH_H_

#include "afx.h"

#define TEST_FILE_R "E:\\TestR.txt" 
#define TEST_FILE_W "E:\\TestW.txt"
#define MAX_PATH 260

class RaiiFile
{
public:
	RaiiFile(const char *pFilePath, const char *openType)
	{
		try 
		{
			m_pFile = fopen(pFilePath, openType);
			if (!m_pFile)
			{
				throw "Error: open file fail";
			}
		}
		catch (char *pError)
		{
			printf(pError);		
		}
	}

	~RaiiFile()
	{
		if(m_pFile)
		{
			fclose(m_pFile);
			m_pFile = NULL;
		}
	}

	FILE *GetFile()
	{
		return m_pFile;
	}

private:
	//禁止拷贝操作
	RaiiFile(const RaiiFile &);
	const RaiiFile operator=(const RaiiFile &);

public:
	FILE *m_pFile;
};

//! 测试入口
void TestFile();

#endif
文件:RAII.cpp

#include "RAII.h"

void TestFile()
{
	char szPathFileR[MAX_PATH] = {0};
	strcat(szPathFileR, TEST_FILE_R);
	char szPathFileW[MAX_PATH] = {0};
	strcat(szPathFileW, TEST_FILE_W);

	RaiiFile FileR(szPathFileR, "r");//如果中途返回,也会调用析构函数关闭文件
	RaiiFile FileW(szPathFileW, "w");

	//Copy File
	fseek(FileR.GetFile(), 0, SEEK_SET);
	int chTest;
	while(true)
	{
		chTest = fgetc(FileR.GetFile());

		if (!feof(FileR.GetFile()))
		{
			fputc(chTest, FileW.GetFile());
		}
		else
		{
			break;
		}
	}

	//此处即使返回, 也会调用 RaiiFile 的析构函数,关闭文件
}


用法2(简单,推荐):需要用时,无需创建 新对象,只需要将对象初始化到RAII, 即可直接使用 FILE*

文件:RAII_2.h

#ifndef TEST_RAII_2_2017_3_18_SKDJFGHDSDFG_H_
#define TEST_RAII_2_2017_3_18_SKDJFGHDSDFG_H_

#include "afx.h"

#define TEST_FILE_R "E:\\TestR.txt" 
#define TEST_FILE_W "E:\\TestW.txt"
#define MAX_PATH 260

class RaiiFile
{
public:
	RaiiFile(FILE *pFile)
	{
		if (pFile)
		{
			m_pFile = pFile;
		}
		else
		{
			printf("Error:open file fail");
		}
	}

	~RaiiFile()
	{
		if(m_pFile)
		{
			fclose(m_pFile);
			m_pFile = NULL;
		}
	}

private:
	//禁止拷贝操作
	RaiiFile(const RaiiFile &);
	const RaiiFile operator=(const RaiiFile &);

public:
	FILE *m_pFile;
};

//! 测试入口
void TestFile();

#endif //TEST_RAII_2_2017_3_18_SKDJFGHDSDFG_H_

文件: RAII_2.cpp

#include "RAII_2.h"

void TestFile()
{
	char szPathFileR[MAX_PATH] = {0};
	strcat(szPathFileR, TEST_FILE_R);
	char szPathFileW[MAX_PATH] = {0};
	strcat(szPathFileW, TEST_FILE_W);

	FILE* pFileR = fopen(szPathFileR, "r");
	if (!pFileR)
	{
		printf("Error:open file fail");
		return;
	}
	RaiiFile raiiFileR(pFileR);//如果中途返回,也会调用 raiiFileR析构函数 关闭文件
	FILE* pFileW = fopen(szPathFileW, "w");
	RaiiFile raiiFileW(pFileW);//如果中途返回,也会调用 raiiFileW析构函数 关闭文件

	//Copy File
	fseek(pFileR, 0, SEEK_SET);
	int chTest;
	while(true)
	{
		chTest = fgetc(pFileR);

		if (!feof(pFileR))
		{
			fputc(chTest, pFileW);
		}
		else
		{
			break;
		}
	}

	if(pFileR)
	{
		fclose(pFileR);
		pFileR = NULL;
	}

	if(pFileW)
	{
		fclose(pFileW);
		pFileW = NULL;
	}

}


书写自己的RAII控制资源

#ifndef MY_RAII_2017_3_18_SKDJFGHDSDFG_H_
#define MY_RAII_2017_3_18_SKDJFGHDSDFG_H_

class RAIIBase 
{
public:
	RAIIBase() {}
	~RAIIBase() {}

	RAIIBase(const RAIIBase&);
	RAIIBase operator=(const RAIIBase&);
};

template<class T>
class MyRAIIResource: private RAIIBase //私有继承 禁用Base的所有继承操作
{
public:
	explicit MyRAIIResource(T* ptMyResouce)
		:m_ptMyRAIIResource(ptMyResouce)
	{}

	~MyRAIIResource()
	{
		delete m_ptMyRAIIResource;
		m_ptMyRAIIResource = NULL;
	}

	T* GetResource()
	{
		return m_ptMyRAIIResource;
	}

private:
	T* m_ptMyRAIIResource;
};

#endif //TEST_RAII_2_2017_3_18_SKDJFGHDSDFG_H_


6.MFC画bmp图片

从路径读取bmp图片,画到dc上。
//MFC从文件画BMP图片
void DrawBmpPicture(CDC* pDC) 
{	
	CFileFind findFile;
	CString strPicturePath = "E:\\Picture.bmp";
	BOOL bFindFile = findFile.FindFile(strPicturePath);
	
	//找到BMP图片
	if(bFindFile)
	{
		CDC dcMem;
		dcMem.CreateCompatibleDC(pDC);
		
		//获取图片句柄
		HBITMAP hBmp = (HBITMAP)::LoadImage(AfxGetInstanceHandle(),	strPicturePath, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION|LR_LOADFROMFILE);
		
		CBitmap *pBitmap = CBitmap::FromHandle(hBmp);
		
		//获取位图信息
		BITMAP bitmap;
		pBitmap->GetBitmap(&bitmap);
		
		//将位图选人到pDC中
		CBitmap* pbitold = dcMem.SelectObject(pBitmap);
		
		float fLogSize = 0.4;			//放大倍数
		CRect rectDraw(0, 0, 500, 500);	//画图坐标

		//以stretchBlt的方式添加位图到相应区域
		pDC->StretchBlt(rectDraw.left, rectDraw.top, (int)(bitmap.bmWidth*fLogSize),
			(int)(bitmap.bmHeight*fLogSize), &dcMem, 0, 0, bitmap.bmWidth, bitmap.bmHeight, SRCCOPY);
		
		pBitmap->DeleteObject();
		pDC->SelectObject(pbitold);
		dcMem.DeleteDC();
	}
}


7.Kill掉指定名称的进程

需要“psapi.lib”,“PSAPI.DLL”和“psapi.h”
下载地址:点击打开链接
void KillProcessByName(LPCWSTR strProcessName)
{
	//HWND是Windows窗口句柄
	HWND hProcessWindow = ::FindWindow(NULL, strProcessName);

	//进程ID
	ULONG nProcessProcessID = 0;
	::GetWindowThreadProcessId(hProcessWindow, &nProcessProcessID);

	//HANDLE(句柄),是Windows用来表示对象的
	HANDLE hProcessHandle = ::OpenProcess(PROCESS_TERMINATE, FALSE, nProcessProcessID);

	//杀死进程
	::TerminateProcess(hProcessHandle, 4);
}


8.重载new/delete来检测内存泄露,显示内存申请文件和行号

OperatorNewSrc.h
#ifndef OPERATOR_NEW_20170609_SDFGDFGF_H_H_
#define OPERATOR_NEW_20170609_SDFGDFGF_H_H_

#include "assert.h"
#include <iostream>
using namespace std;

void * operator new(size_t nSize, const char* pFIle, const size_t unLine);
void * operator new[] (size_t nSize, const char* pFIle, const size_t unLine);

void operator delete(void *pVoid);
void operator delete[](void *pVoid);

static int nNewTimes = 0;

#endif	//OPERATOR_NEW_20170609_SDFGDFGF_H_H_


OperatorNewSrc.cpp
#include "stdafx.h"
#include "OperatorNewSrc.h"

void * operator new(size_t nSize, const char* pFIle, const size_t unLine)
{
	if (nSize <= 0)
	{
		return NULL;
	}
	
	++nNewTimes;

	void *pVoid = malloc(nSize);//此处的nSize会自动计算为new对象的大小.如:int *pTest = new int(__FILE__,__LINE__);此时nSize=4;
	if(!pVoid)
	{
		assert(pVoid);

		cout <<endl <<"内存申请失败=> " <<"NewTimes:" <<nNewTimes  <<"  Size:" <<nSize <<"  File:" <<pFIle <<"  Line:" <<unLine <<endl;
	}

	cout <<endl <<"内存申请成功=> " <<"NewTimes:" <<nNewTimes  <<"  Size:" <<nSize <<"  File:" <<pFIle <<"  Line:" <<unLine <<endl;

	return pVoid; 
}

void * operator new[] (size_t nSize, const char* pFIle, const size_t unLine)
{
	return operator new(nSize);
}

void operator delete(void *pVoid)
{
	if (pVoid)
	{
		free(pVoid);
		pVoid = NULL;
	}
}

void operator delete[](void *pVoid)
{
	operator delete(pVoid);
}


测试代码(注:不能用于多线程)
#include "stdafx.h"
#include "OperatorNewSrc.h"

#define new new(__FILE__,__LINE__)	//一定记得加上这句

class CTestOperatorNew
{
public:
	CTestOperatorNew();
	~CTestOperatorNew()
	{}

private:
	int		m_nTest;
	char	m_chTest;
};

CTestOperatorNew::CTestOperatorNew()
{
	m_chTest = 'a';
	m_nTest = 789;
}

int _tmain(int argc, _TCHAR* argv[])
{
	int *pnTest = new int(__FILE__, __LINE__);
	int *pszTest = new int(__FILE__, __LINE__);


	CTestOperatorNew *pTestNew = new CTestOperatorNew;

	delete pnTest;
	delete pszTest;
	delete pTestNew;

	system("pause");
	return 0;
}


执行结果




  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值