none
pInvoke problem RRS feed

  • Question

  • Hi,

    I'm having a problem on a callback delegate with a string argument.
    I have other callback with a integer argument that works just fine...
    I've been reading forums and experimenting for 2 days, and nothing i try seems to work.
    The execption raised is a AccessViolationException on the StartListening invoking method.

    Here is the code:

    <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< C++ >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

    typedef int ErrorType;

    typedef void (*ProgressStringType) (char *Str);
    extern ProgressStringType SetStatusMessage;

    typedef void (*ProgressPercentageType) (int Percent);
    extern ProgressPercentageType SetStatusProgress;

    ErrorType OpenComputationDatabase(const ProgressStringType ProgStrFnAddr, const ProgressPercentageType ProgPercentFnAddr);

    <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< C# >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    ----------------------------------- Interop Class -----------------------------------

    [UnmanagedFunctionPointer(CallingConvention.StdCall)]
    internal delegate void ShowProgressEventHandler(int progress);

    [UnmanagedFunctionPointer(CallingConvention.StdCall)]
    internal delegate void ProgressStringType([MarshalAs(UnmanagedType.LPStr)] StringBuilder Str);

    [DllImport("DMTRInterfaces.dll", EntryPoint = "StartListening", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = false, CallingConvention = CallingConvention.StdCall)]
    private static extern int StartListening(ProgressStringType F1, ShowProgressEventHandler F2);

    public void StartListening()
    {
    int result = 0;
        result = InteropMethods.StartListening(OnProgressString, OnShowProgress);
        if (result != 0)
            throw new ComputationException(result);
    }

    protected void OnProgressString([MarshalAs(UnmanagedType.LPStr)] StringBuilder msg)
    {
        //...
    }

    protected void OnShowProgress(int progress)
    {
     //...
    }

    Thanks

    Thursday, February 5, 2009 5:45 PM

Answers

  • Next thing to try: replace the char* by IntPtr.  If that works, use Marshal.PtrToStringAnsi().
    Hans Passant.
    • Marked as answer by Zhi-Xin Ye Thursday, February 12, 2009 8:37 AM
    Friday, February 6, 2009 2:27 PM
    Moderator

All replies

  • Hmm, unusual, you are not creating the delegate instance.  Didn't know that could work.  This is the way I would do it:

        public class InteropMethods {
          internal delegate void ShowProgressEventHandler(int progress);
          internal delegate void ProgressStringType(string Str);
          [DllImport("DMTRInterfaces.dll", SetLastError = true, CharSet = CharSet.Ansi)]
          public static extern int StartListening(ProgressStringType F1, ShowProgressEventHandler F2);
        }
        public class something {
          private InteropMethods.ProgressStringType stringCallback;
          private InteropMethods.ShowProgressEventHandler progressCallback;

          public void StartListening() {
            stringCallback = new InteropMethods.ProgressStringType(OnProgressString);
            progressCallback = new InteropMethods.ShowProgressEventHandler(OnShowProgress);
            int result = 0;
            result = InteropMethods.StartListening(stringCallback, progressCallback);
          }

          protected void OnProgressString(string msg) { }
          protected void OnShowProgress(int progress) { }
        }


    Hans Passant.
    Friday, February 6, 2009 2:15 AM
    Moderator
  •  Are you sure you should be using the StdCall calling convention? Doesn't look like it in the C++ code.
    Mattias, C# MVP
    Friday, February 6, 2009 9:51 AM
    Moderator
  • Ok, i was trying to simplify a bit... here's the original C++ (or just plain C, i confess i'm from the managed code generation and completelly ignorant regarding unmanaged code):

    typedef int ErrorType;

    typedef void (_stdcall *ProgressStringType) (char *Str);
    extern ProgressStringType SetArcViewStatusMessage;

    typedef void (_stdcall *ProgressPercentageType) (int Percent);
    extern ProgressPercentageType SetArcViewStatusProgress;

    __declspec(dllexport) ErrorType _stdcall OpenComputationDatabase(
                                               const ProgressStringType ProgStrFnAddr,
                                               const ProgressPercentageType ProgPercentFnAddr);
    Friday, February 6, 2009 11:17 AM
  •  
    nobugz,

    I thought that maybe the GC was disponsing the delegate before the DLL invokes it, so I changed the scoope of the delegates to class level like you sugested on your code.
    Unfortenly no luck on that... There is still an AccessViolationException being thrown with a "Write or Read protected memory" kind of message.
    I still forgot to say that the DLL is being used by an Delphi application, wich means that it works properly and exculde the possibilty of the error being related to the DLL.
    Friday, February 6, 2009 2:13 PM
  • Next thing to try: replace the char* by IntPtr.  If that works, use Marshal.PtrToStringAnsi().
    Hans Passant.
    • Marked as answer by Zhi-Xin Ye Thursday, February 12, 2009 8:37 AM
    Friday, February 6, 2009 2:27 PM
    Moderator