Windows Service, Threads and fstream
I've written an application which writes some data to disk every few seconds to keep the hard drive awake.
Since this application must run all the time I decided to convert it to a Windows Service.
After hours of studying, coding and testing it finally looks as though I've got it right. My service installs, starts, stops etc. My only problem is that the code that writes to disk doesn't work anymore, e.g the file doesn't get written to disk. I really have no idea what the problem could be.
The code is contained in a thread:
PHP Code:
unsigned __stdcall ServiceWorkerThread(void * pVoid)
{
endWorkerThread = ::CreateEvent(0, TRUE, FALSE, 0);
long data = 1000;
serviceRunning = true;
while (serviceRunning == true)
{
std::wofstream dfile;
dfile.open(L"data.txt", std::ios::out);
data = data + 1;
dfile << data;
dfile.close();
Sleep(25000);
}
::SetEvent(endWorkerThread);
return 0;
}
The thread is started as follows:
PHP Code:
void StartWorkerThread()
{
hThread = reinterpret_cast<HANDLE>(::_beginthreadex(NULL,
NULL,
ServiceWorkerThread,
NULL,
NULL,
NULL));
return;
}
I've tried debugging the service and I can see that the thread gets called and I can step through it, but wofstream looks extremely complex and I can't make out whats going on inside it.
So what's causing the problem? Is it the thread or the service part, or both?
If anyone can shed some light on this it will be greatly appreciated.
Re: Windows Service, Threads and fstream
I just want to add that I have the following piece of code which only runs when the service is installed / removed and it works 100% which further leads me to believe that its got something to do with the service / thread code.
PHP Code:
void WriteLog(std::wstring text)
{
std::wofstream file;
file.open(L"log.txt", std::ios::out | std::ios_base::app);
file << text << std::endl;
file.close();
return;
}
Re: Windows Service, Threads and fstream
How are you concluding that the data is not being written ? Are you sure you are looking at the right location for the file ? HAve you tried using a hardcoded absolute path for example ?
Re: Windows Service, Threads and fstream
test with condition :
if( dfile.is_open() ) { } to confirm whether the file is opened sucessfully or not.
and why dont you try...
std::ofstream file;
file.open("C:\\sample.txt",file.out);
if( !file.is_open() )
{
cout<<"File open failed!"<<endl;
}
think this may helps.. cheers:)
Re: Windows Service, Threads and fstream
Thanks guys, you saved me! It never occurred to me that I can provide the full path name. When I hardcode the absolute path e.g C:\\sample.txt it works 100%. So I guess it gets written to disk in some unknown location when I do not provide the full path.
Why is this? As I said in my previous post the following code generates the .txt file in the same location as the executable:
PHP Code:
void WriteLog(std::wstring text)
{
std::wofstream file;
file.open(L"log.txt", std::ios::out | std::ios_base::app);
file << text << std::endl;
file.close();
return;
}
But this code which runs in another thread gets written somewhere else:
PHP Code:
while (serviceRunning == true)
{
std::wofstream dfile;
dfile.open(L"D:\\data.txt", std::ios::out);
data = data + 1;
dfile << data;
dfile.close();
Sleep(25000);
}
I'm just trying to figure out why this is so. Any further insight is welcome!
Re: Windows Service, Threads and fstream
You mean, even after specifying absolute path, you don't find it? Why not search and see where it is being created? Perhaps you can see some pattern. Also, is D driver a mapped drive by any chance ?
Re: Windows Service, Threads and fstream
Quote:
Originally Posted by links
I'm just trying to figure out why this is so. Any further insight is welcome!
The currentdirectory is used when you don't supply a complete file path in a file operation. This current directory can depending on how the app was started (e.g. specifying a different start up folder when using create process) or if the application internally changes it (using SetCurrentDirectory). In the case of services, I believe the current directory is set to the location of the SCM. If you want to know what the current directory is use GetCurrentDirectory.
That all being said, rather than writing to a file to keep the harddrive on, how about turning off the power saving options?
Re: Windows Service, Threads and fstream
Quote:
So I guess it gets written to disk in some unknown location when I do not provide the full path.
Your "some unknown location" most likely is %WINDIR%\system32 :D
Re: Windows Service, Threads and fstream
Thanks for all the replies.
And indeed, I found the text file in Windows\System32! So, as Arjay stated, the current directory gets changed to the location of the SCM. GetCurrentDirectory led me to SetCurrentDirectory so I'm going to adapt my code to change the directory back to my service's exe directory.
Unfortunately merely changing the power saving settings isn't an option in my case. Its a HP laptop with an extremely limited BIOS. After a hard disk replacement the disk is shut down every minute or so irrespective of the power settings in Windows. All I can think is that the BIOS is set to a much more aggresive setting and overrides the Windows settings.
I wouldn't have gone through all the trouble to write this service if it weren't absolutely necessary!
Re: Windows Service, Threads and fstream
IMO opinion Set[Get]CurrentDirectory usually causes issues because unless you immediately set the currentdirectory, you can't rely that GetCurrentDirectory will return the correct value. I say this because any [3rd party] dll may change the current directory. Instead use GetModuleFileName(...) at the start of the service and store the value for use later.
Re: Windows Service, Threads and fstream
The GetSystemPowerStatus function retrieves the power status of the system. The status indicates whether the system is running on AC or DC power, whether the battery is currently charging, and how much battery life remains.
BOOL GetSystemPowerStatus(LPSYSTEM_POWER_STATUS lpSystemPowerStatus);
cheers:)
Re: Windows Service, Threads and fstream
GetModuleFileName is a better alternative. But, depending on where the exe is placed, the location might be forbidden to be written into. For e.g. if the exe were to be in Program Files folder and the service were to be per user, it probably wouldn't work unless the user has privileges to write to the location. Just something to keep in mind.
Re: Windows Service, Threads and fstream
Agreed, I didn't mention this earlier but you can use SHGetFolderPath api to retrieve valid areas to write to. Check out the FolderID_Documents and FolderID_LocalAppData constants.
Re: Windows Service, Threads and fstream
I've used GetModuleFileName and SetCurrentDirectory and it works great.
Thanks for all the help.
Re: Windows Service, Threads and fstream
Quote:
Originally Posted by links
I've used GetModuleFileName and SetCurrentDirectory and it works great.
Thanks for all the help.
You missed the point about SetCurrentDirectory.