Jump to content
Xtreme .Net Talk

Delegate not called from win32 api in C# windows service


Recommended Posts

Posted

I have a C# library which calls TAPI2 Win32 methods, declared using DllImport (tapi32.dll).

 

One of these routines is passed a delegate, which should then be frequently called by Tapi.

 

If I use my library from a Windows Form application, then all works well and my callback is successfully called.

However, if I use it from a Windows service, then although everything else works, my delegate never gets called.

 

I have searched for reasons why this may be the case, and found that the ApartmentState may have something to do with it, but adding a [sTAThread] before the Main() function in the service hasn't made any difference.

 

Does anyone know anything else I may need to do?

 

Thanks,

Jonathan Corwin.

Posted
Could you post the relevant code? Or at least give afew more details about what the callback function does.

 

Yes, here is the code. I was just initially checking there wasn't anything "obvious" that I may not have done. (I'm relatively new to .Net)

 

Relevant bits from the service:

namespace CtiServerCS
{
public class Service1 : System.ServiceProcess.ServiceBase
{
	BMSTapi.Tapi t;
	BMSTapi.NetworkUserCollection u;
	BMSTapi.NetworkListener nl;
	private System.ComponentModel.Container components = null;

	public Service1()
	{
		InitializeComponent();
	}

	[sTAThread]
	static void Main()
	{
		System.ServiceProcess.ServiceBase[] ServicesToRun;
		ServicesToRun = new System.ServiceProcess.ServiceBase[] { new Service1() };
		System.ServiceProcess.ServiceBase.Run(ServicesToRun);
	}
	protected override void OnStart(string[] args)
	{
		t = new BMSTapi.Tapi();
		u = new BMSTapi.NetworkUserCollection();
		nl = new BMSTapi.NetworkListener(t, u);
		nl.Start();
	}
...
}
}

 

And relevant bits from the BMSTapi library:

 


namespace BMSTapi
{
public class Tapi
{

[structLayout(LayoutKind.Sequential)]
public struct LineInitializeExParams
{
	public uint dwTotalSize;
	public uint dwNeededSize;
	public uint dwUsedSize;
	public uint dwOptions;
	public System.IntPtr hEvent;
	public System.IntPtr hCompletionPort;
	public uint dwCompletionKey;
}

	private System.IntPtr _hTapi;
	private LineCallBackFunc _hCallBackFunc;

	public delegate void LineCallBackFunc(uint hDevice, uint dwMsg, uint dwCallbackInstance,
		uint dwParam1, uint dwParam2, uint dwParam3);

	[DllImport("Tapi32.dll", EntryPoint="lineInitializeExW", CharSet=CharSet.Auto, SetLastError=true)]
	internal static extern LineErrReturn lineInitializeEx(
		out IntPtr hLineApp, 
		IntPtr hAppHandle, 
		LineCallBackFunc lCallBack,
		string FriendlyAppName, 
		out uint NumDevices, 
		ref uint APIVersion,
		ref LineInitializeExParams lineExInitParams);

	public TapiApi.LineCallBackFunc CallBackFunc
	{
		get
		{
			return _hCallBackFunc;
		}
	}
	public Tapi()
	{
		InitialiseTapi();
	}
	
	public void LineEventHandler(uint dwDevice, uint dwMsg, uint dwCallbackInstance,
		uint dwParam1, uint dwParam2, uint dwParam3)
	{
			
		// Code that never ever gets reached from the service, but does from the form
	}

	private void InitialiseTapi()
	{
		LineErrReturn ret;
		uint apiVers = TapiConstants.ApiHighVers;

		LineInitializeExParams tapiParams = new LineInitializeExParams();
		tapiParams.dwTotalSize = (uint) Marshal.SizeOf(tapiParams);
		tapiParams.dwNeededSize = tapiParams.dwTotalSize;
		tapiParams.dwUsedSize = tapiParams.dwUsedSize;
		tapiParams.dwOptions = (uint)LineInitializeExOptions.UseHiddenWindow;
		tapiParams.hEvent = System.IntPtr.Zero;
		tapiParams.hEvent = System.IntPtr.Zero;
		tapiParams.hCompletionPort = System.IntPtr.Zero;
		_hCallBackFunc = new TapiApi.LineCallBackFunc(LineEventHandler);
		ret = lineInitializeEx(out _hTapi, System.IntPtr.Zero, _hCallBackFunc, "BMSTAPI", out _lineCnt, ref apiVers, ref tapiParams);
	}
}

public class NetworkListener
{
	private TcpListener _netListen;
	private System.Timers.Timer _netClientTimer;
	private Tapi _tapi;
	private NetworkUserCollection _users;    
	private NetworkClientCollection _netClients = new NetworkClientCollection();

	public NetworkListener(Tapi tapi, NetworkUserCollection users)
	{
		_netListen = new TcpListener(IPAddress.Parse("0.0.0.0"), 33334);
		_netClientTimer = new System.Timers.Timer();
		_netClientTimer.Interval = 500;
		_netClientTimer.Elapsed+=new ElapsedEventHandler(netClientTimer_Elapsed);
	}
	public void Start()
	{
		_netListen.Start();
		_netClientTimer.Start();
		_tapi.EventMessage("Started");
	}
	private void netClientTimer_Elapsed(object sender, ElapsedEventArgs e)
	{
		TcpClient client;
		NetworkClient netClient;
		if(_netListen.Pending())
		{
			client = _netListen.AcceptTcpClient();
			netClient = new NetworkClient(client, _tapi, _users);
			_netClients.Add(netClient);
			Thread t = new Thread(new ThreadStart(netClient.Start));
			t.ApartmentState = ApartmentState.STA;	//Added to see if this made a difference
			t.Start();
		}
	}
}
}

  • 2 weeks later...
Posted

The problem ended up being down to me not reading the Tapi documentation properly, so apologies for taking up your time.

 

For anyone who may be interested:

I was calling lineInitializeEx with a parameter USEHIDDENWINDOW, which tells the routine to use a hidden window for its event handling. As no message queue exists in a windows service, the messages didn't get very far.

Using the USEEVENT parameter instead, and using the lineGetMessage routine to get the messages rather than a delegate solved the problem.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...