Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Calling a C++ dll (unmanaged code) from a C# windows service (written in managed code)

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.

like image 374
vnammour Avatar asked Jan 21 '11 23:01

vnammour


People also ask

Can we write unmanaged code in C#?

No, there is no such thing as unmanaged C#. C# code will be always compiled into the IL code and executed by CLR. It is the case of managed code calling unmanaged code. Unmanaged code can be implemented in several languages C/C++/Assembly etc, but CLR will have no idea of what is happening in that code.

Is DLL managed or unmanaged?

dll is definitely unmanaged - it's part of Windows. If you want to check, try to add the file as a reference to your project - if it adds ok, it's managed.

What is the example of unmanaged code in C#?

Code that executes under the control of the runtime is called managed code. Conversely, code that runs outside the runtime is called unmanaged code. COM components, ActiveX interfaces, and Windows API functions are examples of unmanaged code.


2 Answers

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.

like image 187
Tony Lee Avatar answered Oct 21 '22 11:10

Tony Lee


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.

like image 21
vnammour Avatar answered Oct 21 '22 10:10

vnammour