使用動態庫DLL匯出類
阿新 • • 發佈:2019-01-30
首先建立一個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
完畢!