Watch, Follow, &
Connect with Us

For forums, blogs and more please visit our
Developer Tools Community.


Welcome, Guest
Guest Settings
Help

Thread: C++ Service not starting on Windows Server 2008 R2 !!!


This question is answered. Helpful answers available: 1. Correct answers available: 1.


Permlink Replies: 7 - Last Post: Jun 14, 2017 4:09 PM Last Post By: Remy Lebeau (Te...
Ahmed Sayed

Posts: 173
Registered: 8/9/07
C++ Service not starting on Windows Server 2008 R2 !!!  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Jun 13, 2017 5:28 AM
Hi,

I created a windows service with Linking with run-time packages
enabled. The services installs fine, I deployed all required files (dll,bpl)
on server to make sure that the service will run properly.

But for some reason the service does not start using Local system account
on the server it raises error: 1053.
The service did not respond to the start or control request in a timely fashion

The service runs fine on my development machine on local system account,
on server I have to change the logon user to something else to make the service
start. But that does not make the internal IdHttpServer listen to any incoming
requests.

I have installed other service on the same server (Apache, MySQL)
and they are working fine with local system account.

What could be the problem here because this is driving me crazy?
When I try to run the service app as normal exe no dependency
errors of any kind appears. It is not showing that a BPL is missing or
anything like that.

--
The limits of my language mean the limits of my world

Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: C++ Service not starting on Windows Server 2008 R2 !!!  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Jun 13, 2017 9:37 AM   in response to: Ahmed Sayed in response to: Ahmed Sayed
Ahmed Sayed wrote:

But for some reason the service does not start using Local system
account on the server it raises error: 1053.

Error 1053 is ERROR_SERVICE_REQUEST_TIMEOUT, which means you are not
processing SCM requests in a timely manner (or at all). That has
nothing to do with runtime packages. Please show your actual service
code.

The service runs fine on my development machine on local system
account, on server I have to change the logon user to something else
to make the service start. But that does not make the internal
IdHttpServer listen to any incoming requests.

TCP/IP usage is not subject to user account privileges. TIdHTTPServer
should be able to listen regardless of which user account is used.

--
Remy Lebeau (TeamB)
Ahmed Sayed

Posts: 173
Registered: 8/9/07
Re: C++ Service not starting on Windows Server 2008 R2 !!!  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Jun 13, 2017 11:24 AM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
BaaSService.cpp
//---------------------------------------------------------------------------
#include "BaaSServiceU.h"
#include "RESTDatModU.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma classgroup "Vcl.Controls.TControl"
#pragma resource "*.dfm"
TBaaSService *BaaSService;
//---------------------------------------------------------------------------
void __stdcall ServiceController(unsigned CtrlCode)
{
	BaaSService->Controller(CtrlCode);
}
//---------------------------------------------------------------------------
TServiceController __fastcall TBaaSService::GetServiceController(void)
{
	return (TServiceController) ServiceController;
}
//---------------------------------------------------------------------------
__fastcall TBaaSService::TBaaSService(TComponent* Owner)
	: TService(Owner)
{
ServiceHandler = new TServiceHandler(this);
}
//---------------------------------------------------------------------------
void __fastcall TBaaSService::MemFreeTimerTimer(TObject *Sender)
{
FreeAppMem();
}
//---------------------------------------------------------------------------
void __fastcall TBaaSService::ServiceBeforeInstall(TService *Sender)
{
try
	{
	ServiceHandler->BeforeInstall(Sender);
	}
catch (Exception *E)
	{
	ServiceHandler->Log(E->Message);
	}
}
//---------------------------------------------------------------------------
void __fastcall TBaaSService::ServiceAfterInstall(TService *Sender)
{
try
	{
	ServiceHandler->AfterInstall(Sender);
	}
catch (Exception *E)
	{
	ServiceHandler->Log(E->Message);
	}
}
//---------------------------------------------------------------------------
void __fastcall TBaaSService::ServiceStart(TService *Sender, bool &Started)
{
//I even commented the following lines
//and left this event blank and still get the error.
try
	{
	MemFreeTimer->Enabled = true;
	RESTDM = new TRESTDM(this);
	RESTDM->OnErrorEvent = DoErrorEvent;
	RESTDM->LoadSettings(Name);
	RESTDM->LoadResources();
	RESTDM->StartServer();
	}
catch (Exception *E)
	{
	ServiceHandler->Log(E->Message);
	}
}
//---------------------------------------------------------------------------
void __fastcall TBaaSService::ServiceStop(TService *Sender, bool &Stopped)
{
try
	{
	if (RESTDM)
		{
		RESTDM->StopServer();
		delete RESTDM;
		}
    MemFreeTimer->Enabled = false;
	}
catch (Exception *E)
	{
	ServiceHandler->Log(E->Message);
	}
}
//---------------------------------------------------------------------------
void __fastcall TBaaSService::ServicePause(TService *Sender, bool &Paused)
{
try
	{
	RESTDM->StopServer();
	}
catch (Exception *E)
	{
	ServiceHandler->Log(E->Message);
	}
}
//---------------------------------------------------------------------------
void __fastcall TBaaSService::ServiceContinue(TService *Sender, bool &Continued)
{
try
	{
	RESTDM->StartServer();
	}
catch (Exception *E)
	{
	ServiceHandler->Log(E->Message);
	}
}
//---------------------------------------------------------------------------
void __fastcall TBaaSService::ServiceShutdown(TService *Sender)
{
try
	{
	if (RESTDM)
		{
		RESTDM->StopServer();
		delete RESTDM;
		}
	}
catch (Exception *E)
	{
	ServiceHandler->Log(E->Message);
	}
}
//---------------------------------------------------------------------------
void __fastcall TBaaSService::ServiceDestroy(TObject *Sender)
{
delete ServiceHandler;
}
//---------------------------------------------------------------------------
void __fastcall TBaaSService::DoErrorEvent(UnicodeString Error)
{
ServiceHandler->Log(Error);
}
//---------------------------------------------------------------------------
void __fastcall TBaaSService::ServiceExecute(TService *Sender)
{
try
	{
	while (!Terminated)
		{
		ServiceThread->ProcessRequests(false);
		}
	}
catch (Exception *E)
	{
	ServiceHandler->Log( E->Message);
	}
}
//---------------------------------------------------------------------------


ServiceHandler.h
class TServiceHandler : public TObject
{
	typedef TObject inherited;
 
private:
//Fields
TService *FService;
TStringList *FLog;
String LogFile;
 
//---------------------------------------------------------------------------
protected:
//Methods
virtual void __fastcall Debug();
 
//---------------------------------------------------------------------------
public:
 
//Constructor / Destructor.
__fastcall TServiceHandler(TService *AService);
virtual __fastcall ~TServiceHandler(void);
 
//Methods
void __fastcall AfterInstall(TService *Sender);
void __fastcall BeforeInstall(TService *Sender);
void __fastcall Log(UnicodeString AMessage);
//---------------------------------------------------------------------------
};

ServiceHandler.cpp
//---------------------------------------------------------------------------
#pragma hdrstop
#include "ServiceHandler.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
//---------------------------------------------------------------------------
__fastcall TServiceHandler::TServiceHandler(TService *AService)
	: TObject()
{
LogFile = ChangeFileExt(ParamStr(0), ".txt");
FService = AService;
FLog = new TStringList;
 
String NewName;
 
if (FindCmdLineSwitch("name", NewName))
	AService->Name = NewName;
 
Debug();
}
//---------------------------------------------------------------------------
__fastcall TServiceHandler::~TServiceHandler(void)
{
delete FLog;
}
//---------------------------------------------------------------------------
/*Important Methods*/
void __fastcall TServiceHandler::BeforeInstall(TService *Sender)
{
String NewDisplayName;
if (FindCmdLineSwitch("display", NewDisplayName))
	Sender->DisplayName = NewDisplayName;
}
//---------------------------------------------------------------------------
void __fastcall TServiceHandler::AfterInstall(TService *Sender)
{
WriteKeyString("\\SYSTEM\\CurrentControlSet\\Services\\" + Sender->Name,
			   "ImagePath",
			   "\"" + ParamStr(0) + "\" -name " + Sender->Name, HKEY_LOCAL_MACHINE);
}
//---------------------------------------------------------------------------
void __fastcall TServiceHandler::Debug()
{
try
	{
	if (KeyExists("\\SYSTEM\\CurrentControlSet\\Services\\" + FService->Name))
		return;
 
	String TesterPath = ReadKeyString("Software\\CBuilderApps\\Services", "ServiceTester", HKEY_CURRENT_USER);
	String ExeName = "\"" + ParamStr(0) + "\"";
 
	if (TesterPath.Trim() == "")
		return;
 
	if (Svcmgr::Application->Installing())
		return;
 
	RunIfNot(TesterPath, ExeName);
	}
catch (Exception *E)
	{
	Log(E->Message);
	}
}
//---------------------------------------------------------------------------
void __fastcall TServiceHandler::Log(UnicodeString AMessage)
{
FLog->Clear();
 
if (FileExists( LogFile))
	{
	FLog->LoadFromFile( LogFile);
	}
 
FLog->Add(AMessage);
FLog->SaveToFile( LogFile);
}
//---------------------------------------------------------------------------

--
The limits of my language mean the limits of my world

Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: C++ Service not starting on Windows Server 2008 R2 !!! [Edit]
Helpful
Click to report abuse...   Click to reply to this thread Reply
  Posted: Jun 13, 2017 12:37 PM   in response to: Ahmed Sayed in response to: Ahmed Sayed
Ahmed Sayed wrote:

void __fastcall TBaaSService::MemFreeTimerTimer(TObject *Sender)
{
FreeAppMem();
}

What does FreeAppMem() do exactly? Is its code thread-safe?

catch (Exception *E)

You should always catch exceptions by const reference, not by pointer:

catch (const Exception &E)
{
    ServiceHandler->Log(E.Message);
}


MemFreeTimer->Enabled = true;

MemFreeTimer is created in the context of the main thread, so that is
the thread that its OnTimer event will run in. But you are
(de)activating it in the context of the service worker thread instead.
Don't do that! If you need a timer that runs in the context of the
service thread, you have to create it in the service thread to begin
with, and that thread will need a message loop.

RESTDM = new TRESTDM(this);

What does TRESTDM look like?

void __fastcall TBaaSService::ServiceDestroy(TObject *Sender)

Do not use the OnDestroy event in C++. It is a Delphi idiom that can
produce illegal behavior in C++. Use the service class's destructor
instead:

__fastcall TBaaSService::~TBaaSService()
{
    delete ServiceHandler;
}


void __fastcall TBaaSService::ServiceExecute(TService *Sender)

I STRONGLY suggest you get rid of this event handler COMPLETELY! It is
not doing anything useful that TService would not already do
automatically when the event is unassigned.

More importantly, if you want to keep this event handler, at least get
rid of the manually loop, which is running a tight unyielding loop that
eats up CPU cycles when there are no requests to process. That is
likely the root of your issues. Use this instead:

void __fastcall TBaaSService::ServiceExecute(TService *Sender)
{
    try
    {
        ServiceThread->ProcessRequests(true);
    }
    catch (const Exception &E)
    {
        ServiceHandler->Log(E.Message);
    }
}


ProcessRequests() runs an internal loop when its WaitForMessage
parameter is true. And this is exactly how TService uses
ProcessRequests() internally when an OnExecute event handler is not
assigned.

WriteKeyString("
SYSTEM
CurrentControlSet
Services
" +
Sender->Name, "ImagePath", "\"" + ParamStr(0) + "\" -name " +
Sender->Name, HKEY_LOCAL_MACHINE);

You should use AnsiQuotedStr() instead of quoting file paths manually.
And it is possible for service names to have spaces in them, too:

WriteKeyString("\\SYSTEM\\CurrentControlSet\\Services\\" +
Sender->Name, "ImagePath", AnsiQuotedStr(ParamStr(0), '\"') + " -name "
+ AnsiQuotedStr(Sender->Name, '\"'), HKEY_LOCAL_MACHINE);


String ExeName = "\"" + ParamStr(0) + "\"";

Same thing:

String ExeName = AnsiQuotedStr(ParamStr(0), '\"');


void __fastcall TServiceHandler::Log(UnicodeString AMessage)
{
FLog->Clear();

if (FileExists( LogFile))
{
FLog->LoadFromFile( LogFile);
}

FLog->Add(AMessage);
FLog->SaveToFile( LogFile);
}

Why are you loading the existing log file into memory just to append a
new line to it? That is just wasted overhead, you don't need that. In
fact, you shouldn't even be using a TStringList for your log at all.
Just open the file and write directly to it, eg:

void __fastcall TServiceHandler::Log(UnicodeString AMessage)
{
    UTF8String line = AMessage + sLineBreak;
 
    unsigned iFile;
 
    if (FileExists(LogFile))
    {
        iFile = FileOpen(LogFile, fmOpenWrite);
        FileSeek(iFile, 0, 2);
    }
    else
        iFile = FileCreate(LogFile);
 
    if (iFile != -1)
    {
        FileWrite(iFile, line.c_str(), line.Length());
        FileClose(iFile);
    }
}


Alternatively:

void __fastcall TServiceHandler::Log(UnicodeString AMessage)
{
    UTF8String line = AMessage + sLineBreak;
 
    HANDLE hFile = CreateFile(LogFile.c_str(), FILE_APPEND_DATA,
FILE_SHARE_READ, NULL, OPEN_ALWAYS, 0, NULL);
    if (hFile != INVALID_HANDLE_VALUE)
    {
        DWORD written;
        WriteFile(hFile, line.c_str(), line.Length(), &written, NULL);
 
        CloseHandle(hFile);
    }
}


Alternatively:

void __fastcall TServiceHandler::Log(UnicodeString AMessage)
{
    TStreamWriter *Writer = new TStreamWriter(LogFile, true,
TEncoding::UTF8);
    try
    {
        Writer->WriteLine(AMessage);
    }
    __finally
    {
        delete Writer;
    }
}


Either way, I would suggest opening the log file in the
TServiceHandler's constructor, close the file in the destructor, and
have Log() simply write to it without having to seek it every time:

private:
    unsigned iLogFile;
 
__fastcall TServiceHandler::TServiceHandler()
{
    if (FileExists(LogFile))
    {
        iLogFile = FileOpen(LogFile, fmOpenWrite);
        FileSeek(iLogFile, 0, 2);
    }
    else
        iLogFile = FileCreate(LogFile);
}
 
__fastcall TServiceHandler::~TServiceHandler()
{
    if (iLogFile != -1)
        FileClose(iLogFile);
}
 
void __fastcall TServiceHandler::Log(UnicodeString AMessage)
{
    if (iLogFile != -1)
    {
        UTF8String line = AMessage + sLineBreak;
        FileWrite(iLogFile, line.c_str(), line.Length());
    }
}


Alternatively:

private:
    HANDLE hLogFile;
 
__fastcall TServiceHandler::TServiceHandler()
{
    hLogFile = CreateFile(LogFile.c_str(), FILE_APPEND_DATA,
FILE_SHARE_READ, NULL, OPEN_ALWAYS, 0, NULL);
}
 
__fastcall TServiceHandler::~TServiceHandler()
{
    if (hLogFile != INVALID_HANDLE_VALUE)
        CloseHandle(hLogFile);
}
 
void __fastcall TServiceHandler::Log(UnicodeString AMessage)
{
    if (hLogFile != INVALID_HANDLE_VALUE)
    {
        UTF8String line = AMessage + sLineBreak;
 
        DWORD written;
        WriteFile(hLogFile, line.c_str(), line.Length(), &written,
NULL);
    }
}


Alternatively:

private:
    TStreamWriter *pLogFile;
 
__fastcall TServiceHandler::TServiceHandler()
{
    pLogFile = new TStreamWriter(LogFile, true, TEncoding::UTF8);
}
 
__fastcall TServiceHandler::~TServiceHandler()
{
    delete pLogFile;
}
 
void __fastcall TServiceHandler::Log(UnicodeString AMessage)
{
    pLogFile->WriteLine(AMessage);
}


--
Remy Lebeau (TeamB)
Ahmed Sayed

Posts: 173
Registered: 8/9/07
Re: C++ Service not starting on Windows Server 2008 R2 !!! [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Jun 14, 2017 5:07 AM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
Thanks Remy for your advice. I have taken your notes
into consideration and modified the code accordingly.

Also, I found the cause of the problem it was that I placed
BPL files in another directory than system32 and added that
path to User variables not system variables.

That's why the service managed to start when logged in with a user
instead of Local system account. After updating system variables Path
everything works fine now.

I just hope that Embarcadero create a distribute something similar
to .Net framework run-time dlls. So, we can use it in case of applications
that needs to be linked with run-time packages.

This way we can install the run-time packages as prerequisites before installing
the actual application.

--
The limits of my language mean the limits of my world
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: C++ Service not starting on Windows Server 2008 R2 !!! [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Jun 14, 2017 10:08 AM   in response to: Ahmed Sayed in response to: Ahmed Sayed
Ahmed Sayed wrote:

Also, I found the cause of the problem it was that I placed
BPL files in another directory than system32 and added that
path to User variables not system variables.

They should not be placed in the System32 folder at all, that should
only contain OS files. They should be placed in the same folder as the
EXE, or in a folder that is on the DLL search path
(https://msdn.microsoft.com/en-us/library/windows/desktop/ms682586.aspx).

I just hope that Embarcadero create a distribute something similar
to .Net framework run-time dlls.

They have redistributables. The problem is, they are not shipped with
Windows, like Microsoft's DLLs are. Don't expect Microsoft to ever
ship 3rd party redistributables with Windows.

So, we can use it in case of applications that needs to be linked with
run-time packages.

You need to deploy yourself any redistributes that you link to.
Microsoft and Embarcadero are not going to do it for you.

--
Remy Lebeau (TeamB)
Ahmed Sayed

Posts: 173
Registered: 8/9/07
Re: C++ Service not starting on Windows Server 2008 R2 !!! [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Jun 14, 2017 3:35 PM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
I already done so I have placed files in another folder
on C: drive.

Also, I didn't mean that Microsoft or Embarcadero
should distribute the files for me. I was hoping to
find something like:
Borland_run-time_libs_240.exe or msi for Berlin packages
So, we can use during deployment process and it will be
much easier.

--
The limits of my language mean the limits of my world
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: C++ Service not starting on Windows Server 2008 R2 !!! [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Jun 14, 2017 4:09 PM   in response to: Ahmed Sayed in response to: Ahmed Sayed
Ahmed Sayed wrote:

Also, I didn't mean that Microsoft or Embarcadero
should distribute the files for me. I was hoping to
find something like:
Borland_run-time_libs_240.exe or msi for Berlin packages

Nope. You have to distribute whatever individual runtime packages your
app actually uses, for core packages, 3rd party packages, etc. There
is no single installer.

So, we can use during deployment process and it will be
much easier.

Not really, because there are a lot of runtime packages involved, and
they don't all need to be installed on every machine. Only the ones
actually being used. So you have to check your app's dependencies and
then distribute what you actually need.

Otherwise, just turn runtime packages off, then you don't have to
distribute them at all.

--
Remy Lebeau (TeamB)
Legend
Helpful Answer (5 pts)
Correct Answer (10 pts)

Server Response from: ETNAJIVE02