Re: $100 bounty for help with Windows Service code

2014-08-22 Thread Kagamin via Digitalmars-d
https://github.com/duovia/WindowsServiceInD/blob/master/src/onedge/mysvc.d#L20 
these are not necessarily static: it makes sense to have instance 
fields of shared types too.


Re: $100 bounty for help with Windows Service code

2014-08-22 Thread Tyler Jensen via Digitalmars-d

On Friday, 22 August 2014 at 09:09:22 UTC, Kagamin wrote:
https://github.com/duovia/WindowsServiceInD/blob/master/src/onedge/mysvc.d#L20 
these are not necessarily static: it makes sense to have 
instance fields of shared types too.


Yes, Kagamin, you're right. I'll pull those out of shared as the 
OnStart, OnStop, and other On methods get called by the SCM on 
the same thread. I'll make that change. Thanks.


Re: $100 bounty for help with Windows Service code

2014-08-21 Thread Tyler Jensen via Digitalmars-d
On Monday, 18 August 2014 at 21:23:38 UTC, Vladimir Panteleev 
wrote:

On Monday, 18 August 2014 at 21:12:15 UTC, Tyler Jensen wrote:

On Monday, 18 August 2014 at 18:24:15 UTC, Etienne wrote:

http://www.dsource.org/projects/bindings/wiki/WindowsApi


Browse the source of the latter link and you'll find 
Vladimir's fix.


That's because I've just added it :)


Here's the result of refactoring it.

https://github.com/duovia/WindowsServiceInD


Re: $100 bounty for help with Windows Service code

2014-08-18 Thread Etienne via Digitalmars-d

Shouldn't you be starting with rt_init() in ServiceMain?


Re: $100 bounty for help with Windows Service code

2014-08-18 Thread Etienne via Digitalmars-d

On 2014-08-17 9:11 PM, Vladimir Panteleev wrote:

Please try changing the definition of SERVICE_STATUS_HANDLE from DWORD
to size_t. I'll commit a fix to the win32 bindings repository.


Where does `mixin DECLARE_HANDLE!` come from?


Re: $100 bounty for help with Windows Service code

2014-08-18 Thread Etienne via Digitalmars-d

On 2014-08-18 11:29 AM, Etienne wrote:

On 2014-08-17 9:11 PM, Vladimir Panteleev wrote:

Please try changing the definition of SERVICE_STATUS_HANDLE from DWORD
to size_t. I'll commit a fix to the win32 bindings repository.


Where does `mixin DECLARE_HANDLE!` come from?


Nevermind, it looks like the git mirror is out of date. It would be 
useful to have as a dub project, maybe I could make a dub.json if you 
promise to push your changes to it? ;)


Re: $100 bounty for help with Windows Service code

2014-08-18 Thread Vladimir Panteleev via Digitalmars-d

On Monday, 18 August 2014 at 15:33:42 UTC, Etienne wrote:

On 2014-08-18 11:29 AM, Etienne wrote:

On 2014-08-17 9:11 PM, Vladimir Panteleev wrote:
Please try changing the definition of SERVICE_STATUS_HANDLE 
from DWORD

to size_t. I'll commit a fix to the win32 bindings repository.


Where does `mixin DECLARE_HANDLE!` come from?


Nevermind, it looks like the git mirror is out of date. It 
would be useful to have as a dub project, maybe I could make a 
dub.json if you promise to push your changes to it? ;)


Which git mirror are you talking about?

I have two auto-updating git mirrors for the win32 bindings:

The entire bindings project:
https://github.com/CS-svnmirror/dsource-bindings

Just the win32 package (useful for git submodules):
https://github.com/CS-svnmirror/dsource-bindings-win32


Re: $100 bounty for help with Windows Service code

2014-08-18 Thread Vladimir Panteleev via Digitalmars-d

On Monday, 18 August 2014 at 15:12:58 UTC, Etienne wrote:

Shouldn't you be starting with rt_init() in ServiceMain?


The runtime should be already initialized before main() is run, 
however, now that you mention it, I think ServiceMain should call 
thread_attachThis(). I see there is a commented-out line in the 
code to do this already.


Re: $100 bounty for help with Windows Service code

2014-08-18 Thread Tyler Jensen via Digitalmars-d
On Monday, 18 August 2014 at 15:42:26 UTC, Vladimir Panteleev 
wrote:

On Monday, 18 August 2014 at 15:12:58 UTC, Etienne wrote:

Shouldn't you be starting with rt_init() in ServiceMain?


The runtime should be already initialized before main() is run, 
however, now that you mention it, I think ServiceMain should 
call thread_attachThis(). I see there is a commented-out line 
in the code to do this already.



I did try the suggested thread_attachThis() but it did not help.
Not saying it should not be done, but it was not the cause or the
solution. Ultimately, it was the HANDLE that was the problem.
Thanks, to Vladimir, this has been resolved.

I will continue to experiment with and try to create my own
reference implementation for a Windows Service since much of
what I plan to write in D will be deployed as such.


Re: $100 bounty for help with Windows Service code

2014-08-18 Thread Etienne via Digitalmars-d

On 2014-08-18 11:38 AM, Vladimir Panteleev wrote:

Which git mirror are you talking about?


Oh! I really thought it was this:

https://github.com/AndrejMitrovic/WindowsAPI

That's because there's a link to it on the dsource page

http://www.dsource.org/projects/bindings/wiki/WindowsApi


Re: $100 bounty for help with Windows Service code

2014-08-18 Thread Tyler Jensen via Digitalmars-d

On Monday, 18 August 2014 at 18:24:15 UTC, Etienne wrote:

On 2014-08-18 11:38 AM, Vladimir Panteleev wrote:

Which git mirror are you talking about?


Oh! I really thought it was this:

https://github.com/AndrejMitrovic/WindowsAPI

That's because there's a link to it on the dsource page

http://www.dsource.org/projects/bindings/wiki/WindowsApi


Browse the source of the latter link and you'll find Vladimir's 
fix. Andrej's mirror is not updated yet.


Re: $100 bounty for help with Windows Service code

2014-08-18 Thread Vladimir Panteleev via Digitalmars-d

On Monday, 18 August 2014 at 21:12:15 UTC, Tyler Jensen wrote:

On Monday, 18 August 2014 at 18:24:15 UTC, Etienne wrote:

http://www.dsource.org/projects/bindings/wiki/WindowsApi


Browse the source of the latter link and you'll find Vladimir's 
fix.


That's because I've just added it :)


$100 bounty for help with Windows Service code

2014-08-17 Thread Tyler Jensen via Digitalmars-d

$100 bounty offered!

I've coded up a Windows Service that ALMOST works but I'm missing 
something. I need your help.


I obtained some code from another forum user who had obtained it 
from another forum. I've modified and simplified to the best of 
my limited ability. Install and uninstall works. The service 
starts and produces the following error:


[[ Error 1053: The service did not respond to the start or 
control request in a timely fashion. ]]


Despite the error, the process runs and the ServiceMain is called 
and the worker thread executes as you can see from the following 
logging output:


[[
main [C:\\Code\\DPlay\\edge\\edge\\Debug DMD x64\\edge.exe], 
tid: 9980

initialize, tid: 9980
RunService serviceTable.ptr 81359A3F00, tid: 9980
ServiceMain pid: 11092813551BE58, tid: 5852
RegisterServiceCtrlHandler, serviceStatusHandle 894776416, tid: 
5852

pendStatus 0, tid: 5852
runningStatus 0, tid: 5852
worker pid: 11092, tid: 9964
worker thread, tid: 9964
]]

I've been struggling with this for a while now and reading 
everything I can find but to no avail. I'm using the latest DMD 
compiler with the following command line:


$(VisualDInstallDir)pipedmd.exe dmd -m64 -g -debug -X 
-Xf$(IntDir)\$(TargetName).json -IC:\D\dsource 
-deps=$(OutDir)\$(ProjectName).dep 
-of$(OutDir)\$(ProjectName).exe -map 
$(INTDIR)\$(SAFEPROJECTNAME).map


I'm using Visual Studio 2013 on Windows 8.1 x64. The dsource 
win32 lib comes from dsource.org.


The first person who can help me solve this wins a $100 bounty 
and an honorable mention in the blog post I'll write up about it, 
along with the working code.


Here's the code in its entirety.

import core.thread;
import std.conv : to;
import std.process : system;
import std.stdio;
import std.string;
import win32.w32api;
import win32.winbase;
import win32.winerror;
import win32.winnt;
import win32.windef;
import win32.winsvc;
pragma(lib, advapi32.lib);

enum SERVICE_NAME = MyTestService;
enum DISPLAY_NAME = My Test Service;
enum SERVICE_START_NAME = NT AUTHORITY\\NetworkService;
enum CONTROL_PORT = 8080;

enum _MAX_PATH = 4096;

__gshared
{
char* serviceName;
char* displayName;
char* serviceStartName;
SERVICE_TABLE_ENTRY[] serviceTable;
SERVICE_STATUS serviceStatus;
SERVICE_STATUS_HANDLE serviceStatusHandle = 0;
HANDLE stopServiceEvent = null;
Thread web;
DWORD checkPoint = 1;
bool stopping = false;
}

void initialize()
{
serviceName = cast(char*) toStringz(SERVICE_NAME);
displayName = cast(char*) toStringz(DISPLAY_NAME);
serviceStartName = cast(char*) toStringz(SERVICE_START_NAME);
debug logIt(initialize);
}

void logIt(T...)(T args)
{
File f = File(rc:\temp\inc.log, a);
auto tid = GetCurrentThreadId();
if (tid)
f.writeln(args, , tid: , tid);
else
f.writeln(args);
f.close();
}

extern (Windows)
void ServiceControlHandler(DWORD controlCode)
{
debug logIt(ServiceControlHandler, controlCode , 
controlCode);


switch (controlCode)
{
case SERVICE_CONTROL_SHUTDOWN:
case SERVICE_CONTROL_STOP:
StopService();
break;

case SERVICE_CONTROL_SESSIONCHANGE:
case SERVICE_CONTROL_PAUSE: // 2
case SERVICE_CONTROL_CONTINUE: // 3
case SERVICE_CONTROL_INTERROGATE: // 4
default:
SetStatus(serviceStatus.dwCurrentState);
break;
}
}

extern(Windows)
void ServiceMain(DWORD argc, TCHAR** argv)
{
//auto mythread = thread_attachThis();
debug logIt(ServiceMain pid: , getpid(), argv);

// initialise service status
with (serviceStatus)
{
dwServiceType   = SERVICE_WIN32_OWN_PROCESS;
dwCurrentState  = SERVICE_STOPPED;
dwControlsAccepted |= SERVICE_ACCEPT_STOP | 
SERVICE_ACCEPT_SHUTDOWN;

dwWin32ExitCode = NO_ERROR;
dwServiceSpecificExitCode = 0;
dwCheckPoint  = 0;
dwWaitHint= 0;
}

serviceStatusHandle = RegisterServiceCtrlHandler(serviceName,
   
ServiceControlHandler);


debug logIt(RegisterServiceCtrlHandler, serviceStatusHandle 
, serviceStatusHandle);

if (!serviceStatusHandle)
{
return;
}

// service is starting
auto pendStatus = SetStatus(SERVICE_START_PENDING);
debug logIt(pendStatus , pendStatus);

// do initialisation here
stopServiceEvent = CreateEvent(null, FALSE, FALSE, null);
if (!stopServiceEvent)
{
debug logIt(!stopServiceEvent = CreateEvent);
}

//worker thread
web = new Thread(
 {
 Sleep(3000);
 debug logIt(worker pid: , getpid());
 //serve(CONTROL_PORT, logFile);
 while (!stopping)
 {
 Sleep(5000);
 logIt(worker 

Re: $100 bounty for help with Windows Service code

2014-08-17 Thread Vladimir Panteleev via Digitalmars-d

On Sunday, 17 August 2014 at 21:24:24 UTC, Tyler Jensen wrote:
I've coded up a Windows Service that ALMOST works but I'm 
missing something. I need your help.


Hi,

The service works as expected on my Windows machine, but it shows 
the symptoms you described on my Windows XP VM. I'm going to 
assume that the symptoms indicate the same problem for my VM and 
your system.


The reason for the 1053 error is that the service hangs before it 
can contact the service manager. It is terminated after 5 seconds.


If you use Process Explorer (freeware) or Process Hacker 
(open-source) to peek at the service process's stack trace, 
you'll notice that it shows a message box. The message box is not 
visible to the desktop user, because it is being displayed on the 
hidden service window station.


When the D runtime encounters an unhandled exception, it will 
print the exception stack trace to standard error stream, if it 
is valid. However, services have no standard output or error 
stream, so the runtime shows a MessageBox instead. (Incidentally, 
I implemented that behavior.) Thus, the service hangs because of 
an unhandled exception.


The exception is:

std.exception.ErrnoException@std\stdio.d(367): Cannot open file 
`c:\temp\inc.log' in mode `a' (Permission denied)


This occurs when the service process attempts to add a line to 
the log file. However, as the log is owned by the desktop user 
(because it was created by a process started as the desktop 
user), and the service process runs under as the NT 
AUTHORITY\NETWORK SERVICE user, the service process cannot write 
to the same log file as the process starting the service.


Re: $100 bounty for help with Windows Service code

2014-08-17 Thread ketmar via Digitalmars-d
On Sun, 17 Aug 2014 22:12:06 +
Vladimir Panteleev via Digitalmars-d digitalmars-d@puremagic.com
wrote:

ah! you stole my money! ;-)


signature.asc
Description: PGP signature


Re: $100 bounty for help with Windows Service code

2014-08-17 Thread Vladimir Panteleev via Digitalmars-d

On Sunday, 17 August 2014 at 21:24:24 UTC, Tyler Jensen wrote:
Despite the error, the process runs and the ServiceMain is 
called and the worker thread executes as you can see from the 
following logging output:


[[
main [C:\\Code\\DPlay\\edge\\edge\\Debug DMD x64\\edge.exe], 
tid: 9980

initialize, tid: 9980
RunService serviceTable.ptr 81359A3F00, tid: 9980
ServiceMain pid: 11092813551BE58, tid: 5852
RegisterServiceCtrlHandler, serviceStatusHandle 894776416, tid: 
5852

pendStatus 0, tid: 5852
runningStatus 0, tid: 5852
worker pid: 11092, tid: 9964
worker thread, tid: 9964
]]


Erm, forgot about this bit. Clearly this is a different problem 
than the one I had on my XP VM.


The log shows that SetStatus returns 0, indicating that 
SetServiceStatus is failing. I would suggest logging 
GetLastError's result for more information.


Re: $100 bounty for help with Windows Service code

2014-08-17 Thread Tyler Jensen via Digitalmars-d
On Sunday, 17 August 2014 at 22:38:38 UTC, Vladimir Panteleev 
wrote:

On Sunday, 17 August 2014 at 21:24:24 UTC, Tyler Jensen wrote:
Despite the error, the process runs and the ServiceMain is 
called and the worker thread executes as you can see from the 
following logging output:


[[
main [C:\\Code\\DPlay\\edge\\edge\\Debug DMD x64\\edge.exe], 
tid: 9980

initialize, tid: 9980
RunService serviceTable.ptr 81359A3F00, tid: 9980
ServiceMain pid: 11092813551BE58, tid: 5852
RegisterServiceCtrlHandler, serviceStatusHandle 894776416, 
tid: 5852

pendStatus 0, tid: 5852
runningStatus 0, tid: 5852
worker pid: 11092, tid: 9964
worker thread, tid: 9964
]]


Erm, forgot about this bit. Clearly this is a different problem 
than the one I had on my XP VM.


The log shows that SetStatus returns 0, indicating that 
SetServiceStatus is failing. I would suggest logging 
GetLastError's result for more information.


GetLastError on both returns 0. I had misread the 
SetServiceStatus documentation and was assuming a 0 was success. 
Am looking into that. I'm also trying to figure out how to get 
access to the message box you mentioned.


Re: $100 bounty for help with Windows Service code

2014-08-17 Thread Tyler Jensen via Digitalmars-d

On Sunday, 17 August 2014 at 23:56:56 UTC, Tyler Jensen wrote:


GetLastError on both returns 0. I had misread the 
SetServiceStatus documentation and was assuming a 0 was 
success. Am looking into that. I'm also trying to figure out 
how to get access to the message box you mentioned.


I also changed my worker thread to write to a different file. It 
does not end the process after 5 seconds. It continues to write 
to the file every 5 seconds until it finds stopping to be true. 
So currently it continues to write to the worker thread file 
until I kill the process.


Re: $100 bounty for help with Windows Service code

2014-08-17 Thread ketmar via Digitalmars-d
On Sun, 17 Aug 2014 23:56:54 +
Tyler Jensen via Digitalmars-d digitalmars-d@puremagic.com wrote:

try to catch and process exceptions where they may arose. any file
operation can throw exception (yes, even innocent-looking writeln(),
let alone 'auto fl = File(...)').

also, you don't need to manually close the file, it will be
automatically closed when file variable goes out of scope.


signature.asc
Description: PGP signature


Re: $100 bounty for help with Windows Service code

2014-08-17 Thread Tyler Jensen via Digitalmars-d
On Monday, 18 August 2014 at 00:07:57 UTC, ketmar via 
Digitalmars-d wrote:

On Sun, 17 Aug 2014 23:56:54 +
Tyler Jensen via Digitalmars-d digitalmars-d@puremagic.com 
wrote:


try to catch and process exceptions where they may arose. any 
file
operation can throw exception (yes, even innocent-looking 
writeln(),

let alone 'auto fl = File(...)').

also, you don't need to manually close the file, it will be
automatically closed when file variable goes out of scope.


Now have all file i/o ops in a try/catch and ignoring errors just 
to see if that has anything to do with it. The answer is no. I'm 
still getting result of 0 and a GetLastError return of 
ERROR_INVALID_HANDLE. Now I just need to figure out why the 
serviceStatusHandle is invalid. Ideas?


Re: $100 bounty for help with Windows Service code

2014-08-17 Thread Vladimir Panteleev via Digitalmars-d

On Monday, 18 August 2014 at 00:37:15 UTC, Tyler Jensen wrote:
On Monday, 18 August 2014 at 00:07:57 UTC, ketmar via 
Digitalmars-d wrote:

On Sun, 17 Aug 2014 23:56:54 +
Tyler Jensen via Digitalmars-d digitalmars-d@puremagic.com 
wrote:


try to catch and process exceptions where they may arose. any 
file
operation can throw exception (yes, even innocent-looking 
writeln(),

let alone 'auto fl = File(...)').

also, you don't need to manually close the file, it will be
automatically closed when file variable goes out of scope.


Now have all file i/o ops in a try/catch and ignoring errors 
just to see if that has anything to do with it.


I would recommend wrapping the entire main() function in a 
try/catch block, and logging any caught exceptions.


The answer is no. I'm still getting result of 0 and a 
GetLastError return of ERROR_INVALID_HANDLE. Now I just need to 
figure out why the serviceStatusHandle is invalid. Ideas?


I think I found the problem.

In winsvc.d, SERVICE_STATUS_HANDLE is incorrectly declared as a 
DWORD (4-byte integer), when it should be declared as a HANDLE (8 
bytes on 64-bit platforms).


Please try changing the definition of SERVICE_STATUS_HANDLE from 
DWORD to size_t. I'll commit a fix to the win32 bindings 
repository.


Re: $100 bounty for help with Windows Service code

2014-08-17 Thread Tyler Jensen via Digitalmars-d
On Monday, 18 August 2014 at 01:11:37 UTC, Vladimir Panteleev 
wrote:

On Monday, 18 August 2014 at 00:37:15 UTC, Tyler Jensen wrote:
On Monday, 18 August 2014 at 00:07:57 UTC, ketmar via 
Digitalmars-d wrote:

On Sun, 17 Aug 2014 23:56:54 +
Tyler Jensen via Digitalmars-d digitalmars-d@puremagic.com 
wrote:


try to catch and process exceptions where they may arose. any 
file
operation can throw exception (yes, even innocent-looking 
writeln(),

let alone 'auto fl = File(...)').

also, you don't need to manually close the file, it will be
automatically closed when file variable goes out of scope.


Now have all file i/o ops in a try/catch and ignoring errors 
just to see if that has anything to do with it.


I would recommend wrapping the entire main() function in a 
try/catch block, and logging any caught exceptions.


Good idea. I'll work to make this more robust before putting it 
to a blog post.




The answer is no. I'm still getting result of 0 and a 
GetLastError return of ERROR_INVALID_HANDLE. Now I just need 
to figure out why the serviceStatusHandle is invalid. Ideas?


I think I found the problem.

In winsvc.d, SERVICE_STATUS_HANDLE is incorrectly declared as a 
DWORD (4-byte integer), when it should be declared as a HANDLE 
(8 bytes on 64-bit platforms).


Please try changing the definition of SERVICE_STATUS_HANDLE 
from DWORD to size_t. I'll commit a fix to the win32 bindings 
repository.


FANTASTIC! That little gem fixed it all up. With this change to 
winsvc.d:


//original: alias DWORD SERVICE_STATUS_HANDLE;
alias size_t SERVICE_STATUS_HANDLE;

And with the code below, you'll have an x64 Windows Service. The 
code is not sufficient robust for production but it serves as a 
working example with the fix to winsvc.d.


Vladimir, you win the $100. Thanks for doggedly helping me solve 
this. It's very much appreciated and comes as a great relief. 
Shoot me a private email with an address or PayPal account I can 
use to send you the bounty.


Here's the final service code:

import core.sync.mutex : Mutex;
import core.thread;
import std.conv : to;
import std.process : system;
import std.stdio;
import std.string;
import win32.w32api;
import win32.winbase;
import win32.winerror;
import win32.winnt;
import win32.windef;
import win32.winsvc;
pragma(lib, advapi32.lib);

enum SERVICE_NAME = MyTestService;
enum DISPLAY_NAME = My Test Service;
enum SERVICE_START_NAME = NT AUTHORITY\\NetworkService;
enum CONTROL_PORT = 8080;

enum _MAX_PATH = 4096;

__gshared
{
char* serviceName;
char* displayName;
char* serviceStartName;
SERVICE_TABLE_ENTRY[] serviceTable;
SERVICE_STATUS serviceStatus;
SERVICE_STATUS_HANDLE serviceStatusHandle = 0;
HANDLE stopServiceEvent = null;
Thread web;
DWORD checkPoint = 1;
bool stopping = false;
}

void initialize()
{
serviceName = cast(char*) toStringz(SERVICE_NAME);
displayName = cast(char*) toStringz(DISPLAY_NAME);
serviceStartName = cast(char*) toStringz(SERVICE_START_NAME);
debug logIt(initialize);
}

void logIt(T...)(T args)
{
try
{
File f = File(rc:\temp\inc.log, a);
auto tid = GetCurrentThreadId();
if (tid)
f.writeln(args, , tid: , tid);
else
f.writeln(args);
}
catch
{

}
}

void logItWt(T...)(T args)
{
try
{
File f = File(rc:\temp\incwt.log, a);
auto tid = GetCurrentThreadId();
if (tid)
f.writeln(args, , tid: , tid);
else
f.writeln(args);
}
catch
{
}
}

//void ServiceControlHandler(DWORD controlCode)

extern (Windows)
DWORD ServiceControlHandler(DWORD controlCode, DWORD eventType,
void* eventData, void* context)
{
debug logIt(ServiceControlHandler, controlCode , 
controlCode);


switch (controlCode)
{
case SERVICE_CONTROL_SHUTDOWN:
case SERVICE_CONTROL_STOP:
StopService();
break;

case SERVICE_CONTROL_SESSIONCHANGE:
case SERVICE_CONTROL_PAUSE: // 2
case SERVICE_CONTROL_CONTINUE: // 3
case SERVICE_CONTROL_INTERROGATE: // 4
default:
//SetStatus(serviceStatus.dwCurrentState);
break;
}
return NO_ERROR;
}

extern(Windows)
void ServiceMain(DWORD argc, TCHAR** argv)
{
//auto mythread = thread_attachThis();
debug logIt(ServiceMain pid: , getpid(), argv);

// initialise service status
//with (serviceStatus)
//{

//DWORD dwServiceType;
//DWORD dwCurrentState;
//DWORD dwControlsAccepted;
//DWORD dwWin32ExitCode;
//DWORD dwServiceSpecificExitCode;
//DWORD dwCheckPoint;
//DWORD dwWaitHint;

serviceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
serviceStatus.dwCurrentState= SERVICE_STOPPED;
serviceStatus.dwControlsAccepted = 0; //|= 
SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;

serviceStatus.dwWin32ExitCode