problem crashing in callback to C# method from win32 dll

Tech Tip: Click here to run a free scan for Windows Errors and optimize PC performance

From: Eric Gou (ericgou_at_msn.com)
Date: 08/26/04


Date: Thu, 26 Aug 2004 00:43:11 -0700


I encountered a problem when I used the .NET P-Invoke and C# delegate to
make the interoperation between a win32 dll and a C# program. the flow is
very simple and can be described as follows:

step 1, The C# program calls a unmanaged function "SetCallBackAddress" in
the win32 dll to set its callback method to the dll, and function
SetCallBackAddress stores the callback address in a static variable shared
among a few functions.

step 2, The C# program calls another unmanaged function "TriggerCallback2"
in the win32 dll to trigger a callback, function TriggerCallback makes an
actual callback in relay to the preestalished callback method in the C#
program.

step 3, The callback method in the C# program calls Console.WriteLine to
print something on the screen.

There will be no problem if above steps are executed only once. However, if
the step two and three are to be looped 2000 times just like the following
program does, an exception will be reported by the .NET CLR at the point of
about 458 times like this:

...

i = 457
_hdl, ThreadId: 3348, Thread.GetHashCode: 2, sn = 458, Showing
Thread.GetHashCode = 2

i = 458
_hdl, ThreadId: 3348, Thread.GetHashCode: 2, sn = 459,
Unhandled Exception: System.NullReferenceException: Object reference not set
to an instance of an object.
at Test.TriggerCallback2(Int32 sn, Int32 hc)
at Test.Main(String[] args)

The following is the C# program:

//========================================================
using System;
using System.Text;
using System.Runtime.InteropServices;
using System.Threading;

public class Test
{
    public delegate void CallBackDef(IntPtr msg, int a, int b);
    
    [DllImport("thd.dll")]
    public static extern void SetCallBackAddress(CallBackDef cb);
    
    [DllImport("thd.dll")]
    public static extern void TriggerCallback2(int sn, int hc);
    
    public static void Showing(IntPtr msg, int a, int b) {
        Console.WriteLine("Showing Thread.GetHashCode = {0}\n",
Thread.CurrentThread.GetHashCode() );
    }

    public static void Main(string[] args) {
        CallBackDef cbd = new CallBackDef(Showing);
        SetCallBackAddress(cbd);
        
        int times = 2000;
        for (int i=0; i < times; i++) {
            Console.WriteLine("i = {0}", i );
            TriggerCallback2(i+1, Thread.CurrentThread.GetHashCode() );
            Thread.Sleep(2);
        }
    }

}
//========================================================

The command "csc caller.cs" was used to compile the source code into a .NET
executable.

The following is the source code of the win32 dll:

//========================================================
#include <stdio.h>
#include <windows.h>

typedef void (__stdcall *MYCALLBACK)(void* ptr, long, long);

static MYCALLBACK _hdl = NULL;

__declspec(dllexport)
void SetCallBackAddress(MYCALLBACK newhdl)
{
    _hdl = newhdl;
}

__declspec(dllexport)
void TriggerCallback2(int sn, int hc)
{
    DWORD dwProcssThreadId;
    dwProcssThreadId = GetCurrentThreadId();
    
    fprintf(stdout, "_hdl, ThreadId: %8X, Thread.GetHashCode: %8X, sn = %d,
", dwProcssThreadId, hc, sn );
    _hdl("1111111", 1, 2);
}
//========================================================

The command "cl -MD -LD thd.c -Fethd.dll" was used to build the source code
into a win32 dll.

The version information of cl.exe:
========================

Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 13.10.3077 for 80x86
Copyright (C) Microsoft Corporation 1984-2002. All rights reserved.

The version information of csc.exe
========================

Microsoft (R) Visual C# .NET Compiler version 7.10.3052.4
for Microsoft (R) .NET Framework version 1.1.4322
Copyright (C) Microsoft Corporation 2001-2002. All rights reserved.

The version of .NET framework is v1.1.4322
===============================

Is there anyone who encountered the similar problems to this one can help me?

Thanks in advance!