Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

How to transfer pictures from C# to VB6? 1

Status
Not open for further replies.

Coooz

Programmer
May 1, 2017
5
0
0
IT
Hi everyone,

I have to research the fastest way to transfer pictures from a C# application - which generates them - to a VB6 form... if this can be done at all. Animation by replacing must be possible, but the smoother the better. Storing the pictures somewhere on disk and loading them in VB6 is no option. Both the C# end and the VB6 end are mine to develop at the moment.
Currently I can store the picture data (a .NET Bitmap class) in memory and the address from which to start reading is known - but I am a little at a loss on how to proceed.

Assuming that I can read the picture's data into a VB6 array and that the format these bytes represent is known: is there a way to convert the bytes back into an actual picture? What I'm looking for is LoadPicture() that takes a memory address + number of bytes to read form that address as parameters, instead of a string representing a file name. I'm pretty sure the function doesn't exist in VB6, so how can it be implemented?

Any help here will be much appreciated!

Thanks,
Cooz
 
Sure, why not? Whilst VB6 doesn't natively a) have a LoadLibrary that works from a memory address and b) does not understand a .NET bitmap array (really a GDI+ bitmap array) - it does have the ability to use the Microsoft Windows Acquisition library, which knows how to deal with GDI+ bitmap arrays.

We've had a number of threads on the subject on in the past (about WIA, not about C#), and this one, thread222-1678214, should contain relevant info (and links to other supporting threads)
 
But, to summarise, following the assumption that you already have a method for transferring the byte array to VB (pretty easy), and that you have set a reference to the Windows Aquisition Library, then all you need is something like:

Code:
[blue]Private Function LoadPictureFromArray(GraphicsArray() As Byte) As StdPicture
    With New WIA.Vector
        .BinaryData = GraphicsArray
        Set LoadPictureFromArray = .ImageFile.FileData.Picture
    End With
End Function[/blue]
 
Hi strongm,

Yes, I got it working! This is neat.

It looks like I've said a little too much though when I mentioned "Currently I can store the picture data (a .NET Bitmap class) in memory and the address from which to start reading is known". - thinking a C# version of VarPtr would give me the address. And it worked for strings. Oops... not for objects of course. [sad] The required C# version of ObjPtr is not so easy to implement.

Unless you've a similar splendid idea on this, I think we can consider this thread closed.

Thanks for your input!
Cooz
 
>Currently I can store the picture data (a .NET Bitmap class) in memory and the address from which to start reading is known"

Ah, but you don't need to do that. You should be able to direfctly pass the image as an array. I'm not a C## guru, but here's a (very basic) function that I'd use in VB.NET that should be easily translatable:

Code:
[blue]Public Function GetImageBytes(image As System.Drawing.Image) As Byte()
        Dim byteArray() As Byte
        Dim stream As New IO.MemoryStream
        With stream
            image.Save(stream, System.Drawing.Imaging.ImageFormat.Bmp)
            stream.Close()

            byteArray = stream.ToArray()
        End With
        Return byteArray

    End Function[/blue]
 
Okay, yes that sounds plausible. Here's the C# format, easily translated indeed. And if you'll allow me... you can skip the "With... End With" in your function. [wink]

Code:
public byte[] GetImageBytes(Image image)
        {
            var stream = new MemoryStream();
            image.Save(stream, ImageFormat.Bmp);
            stream.Close();
            return stream.ToArray();
        }

I'll see if I can get my VB6 application to call it.
 
>you can skip the "With... End With"

Indeed. In fact my final version does not have the with ... end with, they were a hangover from a slightly earlier version.

>I'll see if I can get my VB6 application to call it.

I use an ActiveX object to transfer the data and raise an event in VB6 when the data has changed, thus making "Animation by replacing must be possible" almost effortless ...

 
I was intrigued enough to finish an example solution ...

Firstly it requires an ActiveX EXE. In my example this project is called vbDataTransfer, and consists of a module and two classes as below:

Code:
[blue]Option Explicit

Public PrivateTransfer As clsTransfer
Public lCount As Long[/blue]

Code:
[blue][green]' clsTransfer
' Instancing - PublicNotCreatable[/green]
Option Explicit
 
Public Event TransferArrived(arrTransfer() As Byte)
 
Friend Sub RaiseTransferArrived(arrTransfer() As Byte)
    RaiseEvent TransferArrived(arrTransfer)
End Sub[/blue]

Code:
[blue][green]' clsConnector
' Instancing - MultiUse[/green]
Option Explicit

Private WithEvents Transfer As clsTransfer
Public Event TransferArrived(arrTransfer() As Byte)
 
Private Sub Class_Initialize()
    If PrivateTransfer Is Nothing Then
        Set PrivateTransfer = New clsTransfer
    End If
    Set Transfer = PrivateTransfer
    lCount = lCount + 1
End Sub
 
Private Sub Class_Terminate()
    lCount = lCount - 1
    If lCount = 0 Then
        Set PrivateTransfer = Nothing
    End If
End Sub
 
[green]' Bubble the event[/green]
Private Sub Transfer_TransferArrived(arrTransfer() As Byte)
    RaiseEvent TransferArrived(arrTransfer)
End Sub
 
Public Property Let NewCommand(arrTransfer() As Byte)
    PrivateTransfer.RaiseTransferArrived arrTransfer()
End Property[/blue]

This should be compiled and the resulting ActiveX library registered.

Ok, that's the 'complicated' bit ...

And now we need a .NET program that sends a bitmap ... here's the VB.NET version:

Code:
[blue][green]' Requires a COM reference to vbDataTransfer (or whatever you called the class library) to be added to the project
' Windows form should have a picturebox and a command button, picturebox should have an image loaded[/green]
Public Class Form1

    Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
        Dim test As New vbDataTransfer.clsConnector
        test.NewCommand = GetImageBytes(Me.PictureBox1.Image)
    End Sub

    Public Function GetImageBytes(image As System.Drawing.Image) As Byte()
        Dim stream As New IO.MemoryStream
        image.Save(stream, System.Drawing.Imaging.ImageFormat.Bmp)
        stream.Close()
        GetImageBytes = stream.ToArray()
    End Function

End Class[/blue]

Oh, and my attempt at a C# version as well:

Code:
[blue][green]// Requires a COM reference to vbDataTransfer (or whatever you called the class library) to be added to the project
// Windows form should have a picturebox and a command button, picturebox should have an image loaded[/green]
namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        public byte[] GetImageBytes(Image image)
        {
            var stream = new MemoryStream();
            image.Save(stream, ImageFormat.Bmp);
            stream.Close();
            return stream.ToArray();
        }
        private void button1_Click(object sender, EventArgs e)
        {
            var test = new vbDataTransfer.clsConnector();
            test.set_NewCommand(GetImageBytes(pictureBox1.Image));
        } 
    }
}[/blue]

And finally the vb program that the bitmap can be sent to ...

Code:
[blue][green]' assumes user form with picturebox and command button
' assumes reference to WIA added
' and reference added to vbDataTransfer library; you may, of course, have called it something else[/green]
Option Explicit

Dim WithEvents appConnector As clsConnector

Private Sub Form_Initialize()
    Set appConnector = New clsConnector
End Sub

Private Sub appConnector_TransferArrived(strTransfer() As Byte)
    Set Picture1.Picture = LoadPictureFromArray(strTransfer)
End Sub

Private Function LoadPictureFromArray(GraphicsArray() As Byte) As StdPicture
    With New WIA.Vector
        .BinaryData = GraphicsArray
        Set LoadPictureFromArray = .ImageFile.FileData.Picture
    End With
End Function[/blue]
 
Hi strongm,

This looks not too difficult. Thanks for sharing all the details!
One thingie though... I've never registered a VB6 dll; and VB6 dlls in the GAC won't work. Using regsvr32 looks fine initially and I can set a reference to vbDataTransfer without any problems, but then the code doesn't recognize clsConnector. This goes for the sending as well as for the receiving code. Am I overlooking something?
 
To register it properly, try at command line

ActiveXexeName.exe /regserver

(you can also simply double click it in Explorer, which has the same effect)
 
strongm, this is a w e s o m e.
Indeed, this is exactly what I wanted... and so elegant! Thank you so much!
I'll have a happy weekend now. I hope you'll have one too. [bigsmile]
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top