0

I have an COM Class, used for Twain Scanning, that I want to use. The creation of the COM Object is working fine. Also calling methods on this object is okay.

But the problem is that I need to add an EventHandler to this object. With as extra difficulty that one of the types is a custom time from within this COM Object.

The problem is now, when I attach the handler. The error message is :

Object of type 'System.EventHandler' cannot be converted to type 'TwainCOMWrapper.AcquirePageEventHandler'

I have tried several solutions found on google. Like:

Call a method when a generic event occurs

https://msdn.microsoft.com/en-us/library/ms228976%28v=vs.100%29.aspx?f=255&MSPPError=-2147217396

Also I tried to build my sample application in VB.NET and C#.NET. But no result.

Other error message I had:

Cannot implicitly convert type 'TwainCOMWrapperTester.Form1.AcquirePageDelegate' to 'TwainCOMWrapper.AcquirePageEventHandler'

Unable to cast object of type VB$AnonymousDelegate to type

...

I guess the problem is that my method "AcquirePageHandler" is not with the exact correct type from the COM Object.

What I also tried is to create the class in my own project. With same specs. But this also gives an error.

Relevant part of COM Class:

namespace TwainCOMWrapper
{
    // Use to create COM events
    public delegate void AcquirePageEventHandler(Object sender, COM_TwainAcquirePageEventArgs e);

    // Create IDispatch Interface for COM events
    [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
    [Guid("4ac3c1a3-3407-4730-8c27-06e894b172d1")]
    public interface IEventsInterface
    {
        [DispId(1)]
        void AcquirePage(Object sender, COM_TwainAcquirePageEventArgs e);
    }

    [Guid("d98471bb-34ad-4efc-8fe7-ffc9c35f2289")]
    [ComSourceInterfaces(typeof(IEventsInterface))]
    [ComVisible(true)]
    [ProgId("Leadtools.TwainCOMWrapper")]
    public class TwainCOMClass : UserControl
    {
        // .NET Twain class (This is what we are wrapping)
        public TwainSession _twSession = null;

        // The COM event
        public event AcquirePageEventHandler AcquirePage;

        // Twain COM constructor
        public TwainCOMClass()
        {
            _twSession = new TwainSession();
        }

        [HandleProcessCorruptedStateExceptions]
        public string Acquire(bool ShowUI, bool ShowModal)
        {
            try
            {
                if (_twSession != null)
                {
                    TwainUserInterfaceFlags flags = TwainUserInterfaceFlags.None;
                    if (ShowUI)
                    {
                        flags = TwainUserInterfaceFlags.Show;
                        if (ShowModal)
                            flags |= TwainUserInterfaceFlags.Modal;
                    }

                    _twSession.AcquirePage += new EventHandler<TwainAcquirePageEventArgs>(_twSession_AcquirePage);
                    _twSession.Acquire(flags);
                    _twSession.AcquirePage -= _twSession_AcquirePage;
                    return "Scan OK";
                }
                else
                    return "Twain Session is null";
            }
            catch (Exception ex)
            {
                return ex.Message;
            }
        }

        [HandleProcessCorruptedStateExceptions]
        void _twSession_AcquirePage(object sender, TwainAcquirePageEventArgs e)
        {
            try
            {
                if (AcquirePage != null)
                {
                    COM_TwainAcquirePageEventArgs args = new COM_TwainAcquirePageEventArgs(e.Image, _isBW, _compression);
                    AcquirePage(this, args);
                }
            }
            catch
            {
                return;
            }
        }
    }

    [ClassInterface(ClassInterfaceType.AutoDual)]
    [Guid("b356f142-8781-46bb-8343-44674eac86b0")]
    [ComVisible(true)]
    public class COM_TwainAcquirePageEventArgs : EventArgs
    {
        private byte[] _buffer;
        private String _error = "";
        private String _log = "";

        public String Log
        {
            get { return _log; }
        }
        public String Error
        {
            get { return _error; }
        }
        public byte[] Image
        {
            get { return _buffer; }
        }

        public COM_TwainAcquirePageEventArgs()
        {
            _buffer = null;
        }

        public COM_TwainAcquirePageEventArgs(RasterImage image, Boolean bw, int iQuality)
        {
            try
            {
                MemoryStream ms = new MemoryStream();
                RasterCodecs codecs = new RasterCodecs();
                try
                {
                    if (bw)
                    {
                        codecs.Save(image, ms, RasterImageFormat.CcittGroup4, image.BitsPerPixel, 1, image.PageCount, 1, CodecsSavePageMode.Append);
                    }
                    else
                    {
                        codecs.Options.Jpeg.Save.QualityFactor = (int)(iQuality * 2.55 + 2);
                        codecs.Save(image, ms, RasterImageFormat.Jpeg, image.BitsPerPixel, 1, image.PageCount, 1, CodecsSavePageMode.Append);
                    }
                }
                catch (Exception)
                {
                    if (!bw)
                    {
                        MemoryStream nms = new MemoryStream();
                        codecs.Save(image, nms, RasterImageFormat.Png, image.BitsPerPixel, 1, image.PageCount, 1, CodecsSavePageMode.Append);
                        codecs.Convert(nms, ms, RasterImageFormat.Jpeg, 0, 0, 0, null);
                    }
                }
                _buffer = ms.GetBuffer();

                ms.Dispose();
            }
            catch (Exception ex)
            {
                _error = ex.Message;
                _buffer = null;
            }
        }
    }
}

My test program:

Imports System.Reflection

Public Class Form1

    Private TwainSession As Object
    Public Delegate Sub AcquirePageEventHandler(sender As Object, e As Object)

    Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
        Try
            Initialize()
        Catch ex As Exception
            MessageBox.Show(ex.Message & Environment.NewLine & ex.StackTrace)
        End Try

    End Sub

    Private Sub Initialize()
        Dim comType As Type = Type.GetTypeFromProgID("Leadtools.TwainCOMWrapper")
        TwainSession = Activator.CreateInstance(comType)

        If TwainSession.IsAvailable() Then
            TwainSession.Startup("manufacturer", "productFamily", "version", "application")
        Else
            MessageBox.Show("TwainSession.IsAvailable = false(1) ")
            Exit Sub
        End If

        Dim evAcquirePage As EventInfo = comType.GetEvent("AcquirePage")

        evAcquirePage.AddEventHandler(TwainSession, New EventHandler(AddressOf AcquirePageHandler))

        If TwainSession IsNot Nothing Then
            TwainSession.GetColors()
        Else
            Exit Sub
        End If

        Dim tScanError As String = TwainSession.Acquire(False, False)
        MessageBox.Show("OK!") '"Scan OK"
    End Sub

    Private Sub AcquirePageHandler(sender As Object, e As Object)
        Try
            MessageBox.Show("[Debug info]" & vbCrLf & "Error Information: " & IIf(e.Error = "", "All OK!", e.Error) & vbCrLf & "Log:" & vbCrLf & e.Log)
        Catch ex As Exception
        End Try
    End Sub
End Class
Community
  • 1
  • 1
Stinus
  • 309
  • 1
  • 3
  • 18
  • You are making a very standard mistake by writing the test code in a managed language. The CLR is not that easily fooled, it can see at runtime that the COM server is implemented in .NET and will bypass the COM interop layers. With the extra bonus that it can see that your AcquirePageHandler() method is not at all a proper event handler, its second argument is wrong. Cannot be Object, it must be COM_TwainAcquirePageEventArgs – Hans Passant Dec 04 '15 at 15:17
  • @HansPassant I know that the type needs to be COM_TwainAcquirePageEventArgs, but how do I create a method with this type? Without referencing the COM project. – Stinus Dec 04 '15 at 15:45
  • You can't. Otherwise the basic reason that the late binding implementation in VB.NET only supports methods and properties but not events. You'd have to add a reference to the type library, at which point you discover that fooling the IDE doesn't work either. Since you are not actually testing COM interop at all, you might as well add a reference to the assembly. Now it is simple. – Hans Passant Dec 04 '15 at 15:55
  • @HansPassant The wierd part is that from an Silverlight application, this code works. (I have an application for Twain Scanning from silveright). But at one customer it works slow. So I wanted to create a WinForms test application to test if the speed problem is with IE / Silverlight. – Stinus Dec 04 '15 at 15:57
  • That's not terribly unlikely, Silverlight does COM very differently, support for it was bolted on in a later version. Pretty important that you use Silverlight as well if you hope for a repro. – Hans Passant Dec 04 '15 at 16:02

0 Answers0