Unterschiedlichste Fehlermeldungen wegen "Beschädigung des Heaps"
-
Hallo zusammen,
ich versuche gerade meine ersten Schritte in Visual C++. (IDE ist Visual C++ 2010 Express)
Mein erstes Ziel ist es einen einfachen Windows Service zu erstellen, und darin eine einfache Logfunktion einzubauen (Ausgabe ins Debuglog und in eine Logdatei)
Allerdings stoße ich hier schon auf ein gewaltiges Problem: Meine einfache Log-Funktion scheint bereits den Heap zu beschädigen.
Die Ausführung des Programms bricht stets mit der Meldung "Windows hat einen Haltepunkt in Service.exe ausgelöst. Dies kann auf eine Beschädigung des Heaps zurückzuführen sein, [...]" ab.In der Ausgabe erscheinen die unterschiedlichsten Fehlermeldungen, mit denen ich jedoch wenig anfangen kann. (So wie der Code gerade ist z.B. "Critical error detected c0000374").
Ich denke, dass ich wahrscheinlich einen zeimlichen Bock geschossen habe, allerdings komme ich von selbst nicht drauf. Ich vermute den Fehler derzeit in einer kleinen Funktion, die ich zum verknüpfen von TCHARs geschrieben habe (sicher bin ich mir jedoch nicht):
LPTSTR concatenate(LPTSTR string1, LPTSTR string2) { int len = _tcsnlen(string1,1024) + _tcsnlen(string2,1024) + 1; // add size of both strings +1 for null terminator LPTSTR string3 = new TCHAR(len); // create new string3 large enough to hold string1 and string2 _tcscpy_s(string3,len,string1); // copy string1 to string3 _tcscat_s(string3,len,string2); // append string2 to string3 return string3; }
Aufruf in der Logfunktion:
void Log(int level, LPTSTR message) { if(level>LogLevel) return; // don't log anything if LogLevel < level of this message /* set path to logfile (same as executable but with .log extension */ int len = _tcsnlen(lpFullPath,1024)+1; // get length of full executable path (+1 for null terminator) LPTSTR LogFile = new TCHAR[len]; // crate new string to store logfile path _tcsncpy_s(LogFile,len,lpFullPath,len-4); // copy full executable path without "exe" (-3 + -1 for null terminator) _tcscat_s(LogFile,len,L"log"); // append "log" /* open log file */ FILE *pLogFile; if(_tfopen_s(&pLogFile,LogFile,L"a")) OutputDebugString(concatenate(L"Can't open logfile ",LogFile)); else OutputDebugString(concatenate(L"Successfully opened logfile ",LogFile)); fclose(pLogFile); switch(level) { case 1: OutputDebugString(L"Error - "); break; case 2: OutputDebugString(L"Warning - "); break; case 3: OutputDebugString(L"Info - "); break; case 4: OutputDebugString(L"Debug - "); break; } OutputDebugString(message); OutputDebugString(L"\n"); }
In diesen beiden Funktionen tritt vermutlich der Fehler auf, ich hoffe ihr könnt mir dabei weiter helfen. Der Einstieg in C++ ist doch etwas schwieriger als ich erwartet hatte und es ist alles etwas viel für den Anfang.
Hier noch der vollständige Code:
#include <windows.h> #include <stdio.h> #include <tchar.h> //#include <string.h> #include <WinSvc.h> //Header file for Services. /* Global variables */ LPTSTR lpFullPath; int LogLevel = 4; SERVICE_STATUS m_ServiceStatus; SERVICE_STATUS_HANDLE m_ServiceStatusHandle; BOOL ServiceRunning = true; /* Prototypes */ void WINAPI ServiceMain(DWORD argc, LPTSTR *argv); void WINAPI ServiceCtrlHandler(DWORD Opcode); BOOL InstallService(); BOOL UninstallService(); void Log(int level, LPTSTR message); LPTSTR concatenate(LPTSTR string1, LPTSTR string2); /* Main Function */ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { LPTSTR *Args; int nArgs; Args = CommandLineToArgvW(GetCommandLine(),&nArgs); lpFullPath = Args[0]; // full path to program .exe Log(0,L""); if(nArgs>1) { if(wcscmp(Args[1],L"-install")==0) { Log(3,L"Installing service..."); if(InstallService()) Log(3,L"Service installed sucessfully."); else Log(1,L"Error installing service."); } else if(wcscmp(Args[1],L"-uninstall")==0) { Log(3,L"Uninstalling service..."); if(UninstallService()) Log(3,L"Service uninstalled sucessfully."); else Log(1,L"Error uninstalling service."); } else if(wcscmp(Args[1],L"-service")==0) { Log(3,L"Starting Service..."); SERVICE_TABLE_ENTRY DispatchTable[]={{L"Service1",ServiceMain},{NULL,NULL}}; StartServiceCtrlDispatcher(DispatchTable); } } else { Log(4,L"Running program in user mode..."); } return 0; } /* Service related functions */ void WINAPI ServiceMain(DWORD argc, LPTSTR *argv) { //DWORD status; //DWORD specificError; m_ServiceStatus.dwServiceType = SERVICE_WIN32; m_ServiceStatus.dwCurrentState = SERVICE_START_PENDING; m_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP; m_ServiceStatus.dwWin32ExitCode = 0; m_ServiceStatus.dwServiceSpecificExitCode = 0; m_ServiceStatus.dwCheckPoint = 0; m_ServiceStatus.dwWaitHint = 0; m_ServiceStatusHandle = RegisterServiceCtrlHandler(L"Service1", ServiceCtrlHandler); if (m_ServiceStatusHandle == (SERVICE_STATUS_HANDLE)0) { return; } m_ServiceStatus.dwCurrentState = SERVICE_RUNNING; m_ServiceStatus.dwCheckPoint = 0; m_ServiceStatus.dwWaitHint = 0; if (!SetServiceStatus (m_ServiceStatusHandle, &m_ServiceStatus)) { } ServiceRunning = true; while(ServiceRunning) { Sleep(3000); //Place Your Code for processing here.... Log(4,L"Running service..."); } return; } void WINAPI ServiceCtrlHandler(DWORD Opcode) { switch(Opcode) { case SERVICE_CONTROL_PAUSE: m_ServiceStatus.dwCurrentState = SERVICE_PAUSED; break; case SERVICE_CONTROL_CONTINUE: m_ServiceStatus.dwCurrentState = SERVICE_RUNNING; break; case SERVICE_CONTROL_STOP: m_ServiceStatus.dwWin32ExitCode = 0; m_ServiceStatus.dwCurrentState = SERVICE_STOPPED; m_ServiceStatus.dwCheckPoint = 0; m_ServiceStatus.dwWaitHint = 0; SetServiceStatus(m_ServiceStatusHandle,&m_ServiceStatus); ServiceRunning=false; break; case SERVICE_CONTROL_INTERROGATE: break; } return; } BOOL InstallService() { TCHAR strDir[1024]; SC_HANDLE schSCManager,schService; GetCurrentDirectory(1024,strDir); wcscat_s(strDir,L"\\Service.exe"); schSCManager = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS); if (schSCManager == NULL) return false; LPCTSTR lpszBinaryPathName = strDir; schService = CreateService(schSCManager, L"Service1", // service name L"The Display Name Needed", // service name to display SERVICE_ALL_ACCESS, // desired access SERVICE_WIN32_OWN_PROCESS, // service type SERVICE_DEMAND_START, // start type SERVICE_ERROR_NORMAL, // error control type lpszBinaryPathName, // service's binary NULL, // no load ordering group NULL, // no tag identifier NULL, // no dependencies NULL, // LocalSystem account NULL); // no password if (schService == NULL) return false; CloseServiceHandle(schService); return true; } BOOL UninstallService() { SC_HANDLE schSCManager; SC_HANDLE hService; schSCManager = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS); if (schSCManager == NULL) return false; hService=OpenService(schSCManager,L"Service1",SERVICE_ALL_ACCESS); if (hService == NULL) return false; if(DeleteService(hService)==0) return false; if(CloseServiceHandle(hService)==0) return false; return true; } /* Logging funcion */ void Log(int level, LPTSTR message) { if(level>LogLevel) return; // don't log anything if LogLevel < level of this message /* set path to logfile (same as executable but with .log extension */ int len = _tcsnlen(lpFullPath,1024)+1; // get length of full executable path (+1 for null terminator) LPTSTR LogFile = new TCHAR[len]; // crate new string to store logfile path _tcsncpy_s(LogFile,len,lpFullPath,len-4); // copy full executable path without "exe" (-3 + -1 for null terminator) _tcscat_s(LogFile,len,L"log"); // append "log" /* open log file */ FILE *pLogFile; if(_tfopen_s(&pLogFile,LogFile,L"a")) OutputDebugString(concatenate(L"Can't open logfile ",LogFile)); else OutputDebugString(concatenate(L"Successfully opened logfile ",LogFile)); fclose(pLogFile); switch(level) { case 1: OutputDebugString(L"Error - "); break; case 2: OutputDebugString(L"Warning - "); break; case 3: OutputDebugString(L"Info - "); break; case 4: OutputDebugString(L"Debug - "); break; } OutputDebugString(message); OutputDebugString(L"\n"); } /* Helper functions, "toolbox" */ LPTSTR concatenate(LPTSTR string1, LPTSTR string2) { int len = _tcsnlen(string1,1024) + _tcsnlen(string2,1024) + 1; // add size of both strings +1 for null terminator LPTSTR string3 = new TCHAR(len); // create new string3 large enough to hold string1 and string2 _tcscpy_s(string3,len,string1); // copy string1 to string3 _tcscat_s(string3,len,string2); // append string2 to string3 return string3; }
-
Sag mal: Hast Du schon jemals mit Grundlagen angefangen!
1. Dein Programm leaked ohne Ende: new ohn delete hast Du x-fach in Deinem Code.
2. Diese Funktion zeigt zu 100% wie man es nicht machen soll.
/* Helper functions, "toolbox" */ LPTSTR concatenate(LPTSTR string1, LPTSTR string2) { int len = _tcsnlen(string1,1024) + _tcsnlen(string2,1024) + 1; // add size of both strings +1 for null terminator LPTSTR string3 = new TCHAR(len); // create new string3 large enough to hold string1 and string2 _tcscpy_s(string3,len,string1); // copy string1 to string3 _tcscat_s(string3,len,string2); // append string2 to string3 return string3; }
Du allokierst len von String1 +1 und packst dann string1+string2 rein?
Wie dass?3. Warum benutzt Du überhaupt new und nicht enfach den Stack.
4. Ist Dir klar, dassbei der Notation, die Du hast _MAX_PATH genügt?
Nochmal: Lies etwas mehr über Grundlagen.
-
Danke schonmal für deine Antwort Martin. Ich hoffe du verzeihst mir meine Unwissenheit, aber das ist mein erstes C++-Projekt überhaupt - und ich habe gestern zum ersten mal mit C++ programmiert. Wie bereits erwähnt hatte ich mir den Einstieg etwas leichter vorgestellt (insbesondere da ich auch schon Erfahrung mit einigen anderen Programmiersprachen gesammelt hatte) und habe mir deshalb zu Anfang gleich etwas zu viel aufgebürdet.
Ich bin fleißig am lesen, aber das ganze braucht einfach Zeit bis man es richtig verarbeitet und verstanden hat und manchmal hilft es, wenn man etwas Hilfe von jemand anders bekommt. Sonst läuft man gefahr das Rad ständig neu zu erfinden und das auch noch falsch zu machen.
Außerdem habe ich bisher noch kein richtig gutes Tutorial gefunden. Wenn ihr Tpps habt würde ich mich freuen.Also zu deinen Kommentaren:
1. Dein Programm leaked ohne Ende: new ohn delete hast Du x-fach in Deinem Code.
Stimmt x=2 (d.h. "LPTSTR string3" und "LPTSTR LogFile")? Oder übersehe ich entsprechende Konstruktoren? Würde ein einfaches "delete LogFile" an dieser Stelle reichen oder muss ich mehr tun um den Speicher korrekt freizugeben?
2. Diese Funktion zeigt zu 100% wie man es nicht machen soll.
Du allokierst len von String1 +1 und packst dann string1+string2 rein?
Wie dass?Sorry, kannst du mir das erklären?
Ich war der Meinung, dass ich einen neuen TCHAR der Länge "len = String1+String2+1" erzeuge und dann dort String1 reinkopiere, String2 anhänge und am Ende somit noch einen char für en null terminator habe.
Verstehe ich hier wtas falsch?3. Warum benutzt Du überhaupt new und nicht enfach den Stack.
Du meinst ich soll eine einfache lokale Variable erstellen? Wie kann ich die aber mit der richtigen Größe erstellen? Das ist eines der "unlösbaren" Probleme vor denen ich als Neuling gerade stehe.
Wie würdet ihr zwei TCHARS miteinander verknüpfen, ohne deren Länge im Voraus zu kennen?4. Ist Dir klar, dassbei der Notation, die Du hast _MAX_PATH genügt?
Du meinst an der stelle, an der ich den Pfad "LogFile" zusammenstückele? Nein, dass Kommando kannte ich noch nicht, danke dafür!