1. 程式人生 > >VS2013 MFC寫dll 多介面 引數傳遞 小雜記

VS2013 MFC寫dll 多介面 引數傳遞 小雜記

目錄

1. char[] 轉變 cstring    

2. 輸出字串到txt、MessageBox、T2A、_splitpath_s

3. CStringArray的使用、開啟對話方塊將選中的檔名讀出來,允許選擇多個檔案,注意檔名快取

4. 全域性變數的使用 extern包括int 指標 char

5. vector模板類的使用、string變char

6. 將按鈕返回路徑給編輯框

7. MFC呼叫帶MFC介面的DLL,以及傳遞引數

8. MFC下建立類似ENVI經典介面的程式

9. LPSTR轉char*

10. CString擷取字元

11. MFCDlg.cpp中想要不用按鈕建構函式,寫if for做變數運算

12. 自定義分割函式(可用於讀取csv檔案)


1. char[] 轉變 cstring    

char fname[];
CString temp(fname);//char轉cstring

2. 輸出字串到txt、MessageBox、T2A、_splitpath_s

  MFC中想要輸出字串到txt中,%s,要將char或者string轉變為cstring。

  MessageBox輸出提示框,裡面載入文字和變數

  T2A的使用

  從全路徑獲取檔名 _splitpath_s

USES_CONVERSION;//T2A用的
char drive[_MAX_DRIVE];
char dir[_MAX_DIR];
char fname[_MAX_FNAME];
char ext[_MAX_EXT];
_splitpath_s(T2A(strFileName.GetBuffer(0)), drive, dir, fname, ext);//從全路徑中獲取檔名
CString temp2;
CString temp(fname);//char轉cstring
temp2.Format(_T("計算完畢!\r\n結果儲存在 %s.txt 檔案中!"), temp);	
MessageBox(temp2);

3. CStringArray的使用、開啟對話方塊將選中的檔名讀出來,允許選擇多個檔案,注意檔名快取

CStringArray wet_type;
wet_type.Add(_T("mangr"));
wet_type.Add(_T("hekou")); 
wet_type.Add(_T("resh"));
CString name1 = FileName1.GetAt(i);//直接拿出來,就可以%s,name1 
CString temp2;
temp2.Format(_T("計算完畢!\r\n結果儲存在 %s.txt 檔案中!"), name1 );

  將選中的檔名讀出來

//將選中的檔名讀出來
CFileDialog dlgFile(TRUE, _T("shp"), NULL,
OFN_EXPLORER, _T("(向量檔案)|*.shp")); //建立開啟檔案對話方塊
dlgFile.m_ofn.Flags |= OFN_ALLOWMULTISELECT;//允許選擇多個檔案

//設定一個檔名快取,因為CFileDialog內建的檔名快取長度只有200,但是很多時候,檔案的路徑遠大於這個數,為了保險起見,所以要自己設定一個檔名快取
dlgFile.m_ofn.lpstrFile = new TCHAR[500];
memset(dlgFile.m_ofn.lpstrFile, 0, 500);
//設定快取長度
dlgFile.m_ofn.nMaxFile = 500;

if (dlgFile.DoModal() == IDOK){
		CString strPathName = dlgFile.GetPathName();//獲取檔案路徑到strPathName
		m_file.SetWindowText(strPathName);//顯示檔案路徑到編輯框
		POSITION pos_file;
		pos_file = dlgFile.GetStartPosition();//獲得初試位置,如果不設定檔名快取[預設200],如果檔名過長,會報錯
		CStringArray ary_filename1;	
		while (pos_file != NULL){
			pathName1 = dlgFile.GetNextPathName(pos_file);
			ary_filename1.Add(pathName1);
		}
                CString strTmp = ary_filename1.GetAt(i);	
                char* filepath1 = T2A(strTmp.GetBuffer(0));//Cstring轉變char*
 ...

4. 全域性變數的使用 extern包括int 指標 char

   首先在Dlg.h的extern宣告

extern int count1;
extern int count2 ;
extern int count3;
extern double* Area1;
extern double* Area2;
extern double* Area3;
//用於儲存13個溼地型別
//分別對應的是 紅樹林、河口水域、海岸性淡水湖、海岸性鹹水湖、庫塘、內陸河流、內陸湖泊、
//其他水體、淺海水域、沙石海灘、岩石海灘、養殖場、淤泥質海灘
extern int index1[];
extern int index2[];
extern int index3[];
//儲存年份用
extern char year1[];
extern char year2[];
extern char year3[];

    然後在Dlg.cpp中定義

//儲存所選溼地型別個數
int count1 = 0;
int count2 = 0;
int count3 = 0;
double* Area1 = NULL;
double* Area2 = NULL;
double* Area3 = NULL;
//
char year1[50];
char year2[50];
char year3[50];
//預設是666
int index1[13] = {666, 666, 666, 666, 666, 666, 666, 666, 666, 666, 666, 666, 666};
int index2[13] = {666, 666, 666, 666, 666, 666, 666, 666, 666, 666, 666, 666, 666};
int index3[13] = {666, 666, 666, 666, 666, 666, 666, 666, 666, 666, 666, 666, 666};

   最後在Dlg2.cpp或者其他的cpp檔案中,引入   #include "Dlg.h" 即可

5. vector模板類的使用、string變char

vector<string> filename1;
//
char drive[_MAX_DRIVE];
char dir[_MAX_DIR];
char fname[_MAX_FNAME];
char ext[_MAX_EXT]; 
_splitpath_s(T2A(strTmp.GetBuffer(0)), drive, dir, fname, ext);//從全路徑中獲取檔名
//
size_t len = strlen(fname);
filename1.push_back(fname);

  string變char,將20160807_wet.shp提取出2016年份,返回,注意最後'\0'

char year1[100];
int bj;
for (bj = 0; bj < 4; bj++)
{
	year1[bj] = filename1[0][bj];
}
year1[bj] = '\0';

6. 將按鈕返回路徑給編輯框

    首先,給編輯框新增變數

7. MFC呼叫帶MFC介面的DLL,以及傳遞引數

https://blog.csdn.net/hanford/article/details/53633870很全的

只適用於以下的方法:注意傳遞的時候,不能直接傳送模板類比如vector,且輸出必定是指定個數,【目前的理解,比如動態建立的東西就不行】必須要例項化裡面的函式,然後輸出這個函式

dll檔案建立:

類名:CWetland_Extraction_MFCDlg

標頭檔案:Wetland_Extraction_MFCDlg.h、export_variable.h

cpp:Wetland_Extraction_MFCDlg.cpp

1) 在Wetland_Extraction_MFCDlg.cpp檔案中最下面新增:

extern "C" __declspec(dllexport) void ShowDlg(void)
{
	// 此處需要加下面這行程式碼,不然對話方塊顯示不出來。
	AFX_MANAGE_STATE(AfxGetStaticModuleState());
	CTEST_MFC_DLLDlg dlg;
	dlg.DoModal();//實現DLL資源切換的?AFX_MANAGE_STATE(AfxGetStaticModuleState());
}

2)export_variable.h新增:

#pragma once //只編譯一次
__declspec(dllexport) int A = 300;
__declspec(dllexport) int B[4] = { 1,2,3,4 };

dll檔案引用:

1) 建立一個新的工程,然後建立import_variable.h

#pragma comment(lib, "../debug/TEST_MFC_DLL.lib")
HINSTANCE  hDll = LoadLibrary(_T("TEST_MFC_DLL.dll"));

__declspec(dllimport) int A;
__declspec(dllimport) int B[4];

2) 在dlgcpp按鈕函式下加入,就可以彈出介面了

	typedef void(*lpFun)(void);
	if (NULL == hDll)
	{
		MessageBox(L"載入失敗");
	}

	lpFun pShowDlg = (lpFun)GetProcAddress(hDll, "ShowDlg");
	if (pShowDlg == NULL)
	{
		MessageBox(L"載入失敗");
	}
	pShowDlg();

8. MFC下建立類似ENVI經典介面的程式

昨天想建一個類似ENVI介面的程式,然後就在網上搜了一下,也沒有什麼好的方法,後來就自己摸索,先將自己寫程式碼的過程經驗記錄下來以供大家分享啊。

首先,我用的是VS2010其他的應該觸類旁通,1)建立基於對話方塊類的MFC專案。然後相應修改對話方塊的外觀,在對話方塊屬性外觀欄中將Border值修改為Thin(這樣即實現了禁止通過滑鼠拖拽修改對話方塊大小)如圖所示

2)其次,在資源檢視下任意一個資料夾下右擊選擇新增資源選擇Menu項新增選單,如圖所示

然後便可以在選單欄中新增你想要的命令與程式碼

3)最後將選單加入到對話方塊中即大功告成,在對話方塊的屬性列表的雜項中Menu一項選擇你建好的選單即可

編譯執行效果如下圖

9. LPSTR轉char*

char *year1;
CString year1_temp = pstrData[1].Left(4);//取前四位 eg.2016
year1 = (char*)year1_temp.GetBuffer();//lpstr轉換char*

10. CString擷取字元

如果沒有中文可以直接:cstring a;a.left(4);取前四個字元

如果有中文,我的辦法是新建char a[5]

	從2014年溼地,中提取2014出來
    CString year1_temp;
	year1_temp = pstrData[1];

	int bj;
	for (bj = 0; bj < 4; bj++)
	{
		year1[bj] = year1_temp[bj];//cstring可以直接用下標[]
	}
	year1[bj] = '\0';//注意最後的'\0'

11. MFCDlg.cpp中想要不用按鈕建構函式,寫if for做變數運算

int count1 = 0;
int count2 = 0;
double Area1[13];
double Area2[13];
char year1[15];
char year2[15];

void Statistical_Data_VisualizationDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_TCHART3, m_chart_new);
	count1 = 13;
	count2 = 13;
	CStdioFile file;
	CString strLine;
	if (!file.Open(_T("g:\\log.csv"), CFile::modeRead))
	{
		AfxMessageBox(_T("請先進行各類溼地變化檢測模組"));
		return;
	}
	int n = 0;
	file.ReadString(strLine);
	CString *pstrData = SplitString(strLine, ',', n);
	//取前四位 eg.2016
	int bj;
	for (bj = 0; bj < 4; bj++)
	{
		year1[bj] = pstrData[1][bj];
		year2[bj] = pstrData[2][bj];
	}
	year1[bj] = '\0';
	year2[bj] = '\0';
	for (int i = 0; i < 13; i++)
	{
		file.ReadString(strLine);//	讀取下一行
		CString *pstrData = SplitString(strLine, ',', n);
		Area1[i] = _ttof(pstrData[1]);
		Area2[i] = _ttof(pstrData[2]);
	}
}

12. 自定義分割函式(可用於讀取csv檔案)

首先可以在Dlg.h中宣告,動態建立,用到指標*

class Statistical_Data_VisualizationDlg : public CDialogEx
{
......
//因為不知道返回多少個CString,涉及到動態建立,所有要用*
public:
	CString* SplitString(CString str, char split, int iSubStrs);  //分割字串
}

然後在Dlg.cpp中定義

CString* Statistical_Data_VisualizationDlg::SplitString(CString str, char split, int iSubStrs)
{
	int iPos = 0; //分割符位置
	int iNums = 0; //分割符的總數
	CString strTemp = str;
	CString strRight;
	//先計運算元字串的數量
	while (iPos != -1)
	{
		iPos = strTemp.Find(split);
		if (iPos == -1)
		{
			break;
		}
		strRight = strTemp.Mid(iPos + 1, str.GetLength());
		strTemp = strRight;
		iNums++;
	}
	if (iNums == 0) //沒有找到分割符
	{
		//子字串數就是字串本身
		iSubStrs = 1;
		return NULL;
	}
	//子字串陣列
	iSubStrs = iNums + 1; //子串的數量= 分割符數量+ 1
	CString* pStrSplit;
	pStrSplit = new CString[iSubStrs];
	strTemp = str;
	CString strLeft;
	for (int i = 0; i < iNums; i++)
	{
		iPos = strTemp.Find(split);
		//左子串
		strLeft = strTemp.Left(iPos);
		//右子串
		strRight = strTemp.Mid(iPos + 1, strTemp.GetLength());
		strTemp = strRight;
		pStrSplit[i] = strLeft;
	}
	pStrSplit[iNums] = strTemp;
	return pStrSplit;
}

使用

    CString strLine;
    int n = 0;
	for (int i = 0; i < 13; i++)
	{
		file.ReadString(strLine);//	讀取下一行
		CString *pstrData = SplitString(strLine, ',', n);
		Area1[i] = _ttof(pstrData[0]);//CString轉換成double
		Area2[i] = _ttof(pstrData[1]);//CString轉換成double
	}

13. 獲取當前解決方案的debug路徑

WCHAR szPaht[MAX_PATH] = { 0 };
GetModuleFileName(NULL, szPaht, sizeof(szPaht));//獲取exe的路徑
PathRemoveFileSpec(szPaht);	
// 設定你的檔名
CString strFileName3("Demo.txt");
// 將檔名附加在 當前路徑 裡面
wcscat_s(szPaht, L"\\");  ///知道為啥是L 開頭嗎,因為vs2013工程預設是unicode環境,unicode字串需要 L  開頭的巨集
wcscat_s(szPaht, strFileName3.GetString());//這時候szPaht已經是全路徑了
//如果原來存在就刪除檔案
if (PathFileExists(szPaht))
{
	DeleteFile(szPaht);
}
/// 必須 設定 一下 語言環境,否則 my_log_file.WriteString 不能輸出中文(是不是感覺好複雜?)沒關係,當前工程能跑起來,能夠就行。
//setlocale(LC_ALL, "chs");

// 檔案讀寫 StdioFile
// 1.建立 CStdioFile的物件,並指定 讀寫檔案的方式。 CFile::modeNoTruncate,不會覆蓋之前的檔案。
CStdioFile my_log_file(szPaht, CFile::modeWrite | CFile::modeCreate | CFile::modeNoTruncate);
/// 這裡將2行程式碼合併為1行了。如果分開寫,是這樣的:
/// CStdioFile my_log_file;
/// my_log_file.Open(szPaht, CFile::modeWrite | CFile::modeCreate | CFile::modeNoTruncate);
// 2.將讀寫指標移到檔案末尾
my_log_file.SeekToEnd();
CString  strData;
strData.Format(L"%s\n", strPathName1);
my_log_file.WriteString(strData);
strData.Format(L"%s\n", strPathName2);
my_log_file.WriteString(strData);
// 4.關閉 讀寫指標 
my_log_file.Close();