1. 程式人生 > >使用動態庫DLL匯出類

使用動態庫DLL匯出類

首先建立一個DLL工程,名稱為ServMgrDll,新建一個類,包含標頭檔案ServConfig.h和cpp檔案ServConfig.cpp。

類的程式碼如下:

.h:

#pragma once

/*
    如果沒有定義:ServConfigAPI,則ServConfigAPI定義為:_declspec(dllimport),
	編譯器就知道可執行原始檔要從DLL模組中匯入某些函式。
*/
#ifdef ServConfigAPI
#else   
#define ServConfigAPI extern "C" _declspec(dllimport)
#endif



class CServItem {
public:
	CString m_strServName;
	CString m_strServDispName;
	DWORD m_dwServStatus;
	CString m_strBinPath;
	DWORD m_dwStartType;
	CString m_strDescription;
	CServItem *m_pNext;
	CServItem() {
		m_dwServStatus = 0;
		m_pNext = NULL;
	}
};

/******匯出類:CServConfig ******/
class __declspec(dllexport) CServConfig
{
public:
	CServConfig(void);
	~CServConfig(void);
public:
	CServItem *EnumServList();
	BOOL GetServPathAndStartType(LPCTSTR lpszServName, CServItem &tItem);
	CString GetServDescription(LPCTSTR lpszServName);
    void FreeServList(CServItem *pServList);
};

.cpp:

#include "StdAfx.h"

/*在標頭檔案之前定義:ServConfigAPI,表示在DLL模組中匯出一些函式*/
#define ServConfigAPI extern "C" _declspec(dllexport)
#include "ServConfig.h"

CServConfig::CServConfig(void)
{
}

CServConfig::~CServConfig(void)
{
}

CServItem *CServConfig::EnumServList()
{
	SC_HANDLE hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
	if ( !hSCM ) {
		return NULL;
	}
	CServItem *pServHeader = NULL, *pServPre = NULL, *pServNext = NULL;
	LPENUM_SERVICE_STATUS pServStatus = NULL;
	DWORD dwBytesNeeded = 0, dwServCound = 0, dwResume = 0, dwRealBytes = 0;
	BOOL bRet = EnumServicesStatus(hSCM, SERVICE_WIN32, SERVICE_STATE_ALL, NULL, 0, &dwBytesNeeded, &dwServCound, &dwResume);
	if ( !bRet && GetLastError() == ERROR_MORE_DATA ) {
		dwRealBytes = dwBytesNeeded;
		pServStatus = new ENUM_SERVICE_STATUS[dwRealBytes+1];
		ZeroMemory(pServStatus, dwRealBytes+1);
		bRet = EnumServicesStatus(hSCM, SERVICE_WIN32, SERVICE_STATE_ALL, pServStatus, dwRealBytes, &dwBytesNeeded, &dwServCound, &dwResume);
		if ( !bRet ) {
			CloseServiceHandle(hSCM);
			return NULL;
		}
	}else{
		CloseServiceHandle(hSCM);
		return NULL;
	}
	pServPre = pServNext;
	for( DWORD dwIdx = 0; dwIdx < dwServCound; dwIdx++ ) {
		pServNext = new CServItem;
		pServNext->m_strServName = pServStatus[dwIdx].lpServiceName;
		pServNext->m_strServDispName = pServStatus[dwIdx].lpDisplayName;
		pServNext->m_dwServStatus = pServStatus[dwIdx].ServiceStatus.dwCurrentState;
		GetServPathAndStartType(pServNext->m_strServName, *pServNext);
		pServNext->m_strDescription = GetServDescription(pServNext->m_strServName);
		(pServHeader == NULL) ? (pServHeader = pServNext) : pServHeader;
		(pServPre == NULL) ? (pServPre = pServNext) : (pServPre->m_pNext = pServNext, pServPre = pServNext);
	}
	CloseServiceHandle(hSCM);
	delete [] pServStatus;

	return pServHeader;
}

BOOL CServConfig::GetServPathAndStartType(LPCTSTR lpszServName, CServItem &tItem)
{
	BOOL bRet = FALSE;
	SC_HANDLE hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
	if (hSCM == NULL){
		return FALSE;
	}
	SC_HANDLE hSvc = OpenService(hSCM, lpszServName, SERVICE_QUERY_CONFIG);
	if (hSvc == NULL){
		CloseServiceHandle(hSCM);
		return FALSE;
	}

	// for the QueryServiceConfig;
	QUERY_SERVICE_CONFIG *pServCfg = NULL;
	DWORD cbBytesNeeded = 0, cbBufferSize = 0;
	bRet = QueryServiceConfig(hSvc, NULL, 0, &cbBytesNeeded);
	if (bRet == FALSE){
		if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER ){
			pServCfg = new QUERY_SERVICE_CONFIG[cbBytesNeeded+1];
			ZeroMemory(pServCfg, cbBytesNeeded+1);
			cbBufferSize = cbBytesNeeded;
			cbBytesNeeded = 0;
		}else{
			goto __Error_End;
		}
	}
	bRet = QueryServiceConfig(hSvc, pServCfg, cbBufferSize, &cbBytesNeeded);
	if (bRet == FALSE){
		goto __Error_End;
	}
	tItem.m_strBinPath = pServCfg->lpBinaryPathName;
	tItem.m_dwStartType = pServCfg->dwStartType;
	bRet = TRUE;
	if ( pServCfg ) {
		delete [] pServCfg;
	}
__Error_End:
	CloseServiceHandle(hSvc);
	CloseServiceHandle(hSCM);
	return bRet;
}

CString CServConfig::GetServDescription(LPCTSTR lpszServName)
{
	CString strResult;
	BOOL bRet = FALSE;
	SC_HANDLE hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
	if (hSCM == NULL){
		return strResult;
	}
	SC_HANDLE hSvc = OpenService(hSCM, lpszServName, SERVICE_QUERY_CONFIG);
	if (hSvc == NULL){
		CloseServiceHandle(hSCM);
		return strResult;
	}
	//for the QueryServiceConfig2;
	DWORD dwNeeded = 0, dwLen = 0;
	LPSERVICE_DESCRIPTION pDescripTion = NULL;
	bRet = QueryServiceConfig2(hSvc, SERVICE_CONFIG_DESCRIPTION, NULL, 0, &dwNeeded);
	if ( !bRet && GetLastError() == ERROR_INSUFFICIENT_BUFFER ) {
		dwLen = dwNeeded + 1;
		pDescripTion = new SERVICE_DESCRIPTION[dwLen];
		ZeroMemory(pDescripTion, dwLen);
		if ( QueryServiceConfig2(hSvc, SERVICE_CONFIG_DESCRIPTION, (LPBYTE)pDescripTion, dwLen, &dwNeeded) ) {
			strResult = pDescripTion->lpDescription;
		}
	}
	CloseServiceHandle(hSvc);
	CloseServiceHandle(hSCM);
	return strResult;
}

void CServConfig::FreeServList(CServItem *pServList)
{
	CServItem *pT = NULL;
	while (pServList) {
		pT = pServList->m_pNext;
		delete pServList;
		pServList = pT;
	} 
}

編譯生成,會生成兩個檔案:ServMgrDll.lib、ServMgrDll.dll。

2、使用匯出的類:

首先,包含動態庫生成的匯入庫:#pragma comment(lib,"D:\\繪圖程式設計\\ServMgrDll\\Release\\ServMgrDll.lib");

其次,將dll工程中建立的標頭檔案ServConfig.h加入到可執行檔案的工程中,包含標頭檔案:#include "ServConfig.h";

再次,將動態庫與可執行檔案.exe放在一起。

如下:

// DllUse.cpp : 定義控制檯應用程式的入口點。
//

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

#pragma comment(lib,"D:\\繪圖程式設計\\ServMgrDll\\Release\\ServMgrDll.lib")

int _tmain(int argc, _TCHAR* argv[])
{
	CServConfig  m_ServCfg;
	CServItem * m_pServList = NULL;
	CServItem * m_pHeader = m_ServCfg.EnumServList();
	if ( !m_pHeader ) {
		return 0;
	}

	TCHAR szbuf[MAX_PATH] = {0};
	m_pServList = m_pHeader;
	for ( int idx = 0; m_pServList != NULL; idx++ ) {
		_tcscpy(szbuf,m_pServList->m_strServName.GetBuffer());
		_tprintf(_T("%s\n"),szbuf);
		m_pServList = m_pServList->m_pNext;
	}

	m_ServCfg.FreeServList(m_pHeader);

	system("pause");

	return 0;
}

3、在win32動態庫中使用MFC中的CString,需進行如下配置:

首先,包含標頭檔案,注意順序:

#include <afx.h>
#include <windows.h>

其次,屬性->C/C++->程式碼生成->執行庫:多執行緒(/MT);

最後,在dllmain.cpp中新增如下程式碼:

#ifdef _X86_
extern "C" { int _afxForceUSRDLL; }
#else
extern "C" { int __afxForceUSRDLL; }
#endif 
完畢!