6

I am working on a C++ project that has different components. We need to start the application as a windows service. The project is unmanaged C++ code. I wrote a C# windows service, and a C-style dll that will have a function to start the different components, and another to stop them. The dll has two files, a header and a .cpp file: RTSS.h:

namespace PFDS
{
  extern "C" __declspec(dllexport) int runRTS(char*);
}

RTSS.cpp:

using namespace PFDS;
/* ... includes and declarations */
extern "C" __declspec(dllexport) int runRTS(char* service_name)
{
   g_reserved_memory = (char*) malloc(sizeof(char) * RESERVED_MEMORY_SIZE);
   _set_new_handler(memory_depletion_handler);
   // this function is from a C++ .lib which is included in
   // the linker input for the RTSS dll project setting.
   // SetUnhandledExceptionHandler("RTS");       
   return 0;
}

In the ServiceBase subclass of the windows service, I have the following:

[DllImport("RTSSd.dll")]
public static extern int runRTS(string serviceName);

protected override void OnStart(string[] args)
{
  try
  {
    // the bin directory has all dependencies (dlls needed)
    Environment.CurrentDirectory = "D:/work/projects/bin";
    eventLog1.WriteEntry("RTSWinService: Starting " + this.ServiceName);
    int result = runRTS(this.ServiceName);
    eventLog1.WriteEntry("Result of invoking runRTS = " + result);
  }
  catch (Exception e)
  {
    eventLog1.WriteEntry("Exception caught: " + e.ToString());
  }
}

Furthermore I have a console test application with code inside main similar to that inside OnStart. Both the application and the windows service runs with no problem when the SetUnhandledException function is commented. But when I uncomment that function, the windows console application runs ok, but the windows service outputs the following exception:

System.DllNotFoundException: Unable to load DLL 'RTSSd.dll': The specified module could not be found. (Exception from HRESULT: 0x8007007E) at RTSWS.RTSWinService.runRTS(String serviceName) at RTSWS.RTSWinService.OnStart(String[] args) in D:\work\project\ ...\RTSWinService.cs:line 39

I have read in some threads in different forums that the windows services start in C:\WINDOWS\System32, and it is true since initializing a DirectoryInfo and printing its full name shows so. I tried to change the default start directory with Environment.CurrentDirectory = "directory where the windows service executable and dlls are", but that didn't work. I also tried to change the Process directory, but that failed too. Other threads lead to this conclusion link text, but is it really that? Could it be something simpler? I should note that the SetUnhandledException function is written in C++, not C, and so are many other functions that I need to call. All the needed dlls are placed next to the service executable. Your feedback is much appreciated.

Thanks.

vnammour
  • 71
  • 1
  • 5
  • Sanity check: open up dependency walker, see what your DLL depends on, then make sure both your DLL and the DLLs it depends on are somewhere on your path. – Shog9 Jan 21 '11 at 23:56
  • Also, you can run SysInternal's filemon to watch which DLLs your service tries to load. Keep in mind that a windows service runs in a different user session (and desktop) and so has its own environment. And make sure your 'd:' (or wherever you installed to) is in fact a real local path, not network nor SUBST'ed (been there done that ;-) – Chris O Jan 22 '11 at 00:02
  • Did the dependency check, but since the console application runs with no issues, I assume that there are no missing dependencies. BTW, I did run into the issue of installing the service on subst'ed drive and it was a pain to remove it :) – vnammour Jan 22 '11 at 08:56
  • 1
    If anyone is having a similar problem, when I changed the `Environment.CurrentDirectory` to the directory where my DLLs where, it worked. – fjsj Mar 06 '14 at 22:15

2 Answers2

2

When something works at the console but not as a service, I aways suspect access permissions. Make sure the user the service is running as, has read/execute access to d:\work\projects\bin.

The other suggestion is to call SetDllDirectory, which is a more direct way to say where DLLs are than to use the current directory. See this SO thread on the pinvoke dll search path

You can also use SysInternal's ProcMon to watch the system try and locate your DLL. Sometimes it's not the DLL, but a DLL your DLL depends on that has the problem and ProcMon is good for finding these issues.

Community
  • 1
  • 1
Tony Lee
  • 5,622
  • 1
  • 28
  • 45
  • Thanks a lot for the answer and the comments. I am glad it was fast :) – vnammour Jan 22 '11 at 08:46
  • I am running the service as a local service. I have also tried it as user (& my account is an admin on this machine) and local system, but it wasn't different. I have also made a call to SetDllDirectory("D:\work\projects\bin") from within the OnStart method, and it returned true, but didn't solve the issue. When I open the dependency tool (depends.exe) and examine RTSSd.dll, it gives an error about not finding IESHIMS.DLL and WER.DLL (system dlls maybe). But I would assume that the console application would have failed if there were any missing dependencies. – vnammour Jan 22 '11 at 08:53
  • It's worth learning how to use procmon so given the obvious stuff isn't solving your problem, you may be trying to solve the wrong one. Procmon often helps to see what that is. – Tony Lee Jan 24 '11 at 16:45
  • +1 for recommending ProcMon. Here is the updated download link: http://technet.microsoft.com/en-us/sysinternals/bb896645 – fjsj Mar 06 '14 at 22:04
1

Just wanted to update this thread. It turned out that the problem was exclusive to my machine. The same codeset worked like a charm on a different machine, same windows version (Windows XP 32 bit, SP2). On both machines, Visual Studio 2008 was used to build the service. Thanks a lot for all the comments and the answer. I appreciate it.

vnammour
  • 71
  • 1
  • 5