In duplicated code using Lockbits in VB to obtain the address of Bitmap.Scan0, the first
is OK, in all applications, but the second NEVER is. What is the explanation please? Surely
both StartAddrA and StartAddrB should be valid pointers to Bitmap.Scan0 for calls to valid,
functional ASM code in the functional DLL. The error is, it seems, in the VB Lockbits
process. Using VS2010 Beta 2 and XP.
Rgeards,
Ron
In the VB test-DLL program
Public Class Form1
Public Declare Function ProcSingleImage Lib "c:\CODE TEST\TestVBAsmCppDll-01\debug\_
TestCppAtlDllAsm.dll" (ByVal ProcID As Int32, ByVal StartAddrA As IntPtr, ByVal Nbytes As Int32, _
ByVal modData As Byte) As Boolean
Public Declare Function ProcDoubleImage Lib "c:\CODE TEST\TestVBAsmCppDll-01\debug\_
TestCppAtlDllAsm.dll" (ByVal ProcID As Int32, ByVal StartAddrA As IntPtr, ByVal StartAddrB As IntPtr, _
ByVal Nbytes As Int32, ByVal modData As Byte) As Boolean
Public ProcID As Int32
''One image
Public Const ProcIDNull As Integer = 0
Public Const ProcIDBiasR As Integer = 1
Public Const ProcIDScaleR As Integer = 2
Public Const ProcIDBiasG As Integer = 3
Public Const ProcIDScaleG As Integer = 4
Public Const ProcIDBiasB As Integer = 5
Public Const ProcIDScaleB As Integer = 6
Public Const ProcIDBiasW As Integer = 7
Public Const ProcIDScaleW As Integer = 8
Public Const ProcIDInv As Integer = 9
''Two images
Public Const ProcDoubleSub As Integer = 10
Public StartAddrA As IntPtr
Public StartAddrB As IntPtr
Public nBytes As Int32
Public nPix As Int32
Public bmp1 As Bitmap ''GLOBAL therefore safe from GC!!?
Public bmp2 As Bitmap ''GLOBAL therefore safe from GC!!?
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim ofd As New OpenFileDialog
ofd.ShowDialog(Me)
If ofd.FileName <> "" Then
''ORIGINAL APPROACH - bmp1.scan0 OK; bmp2.scan0 error
''PictureBox1.Load(ofd.FileName)
''bmp1 = PictureBox1.Image
''bmp2 = Bitmap.FromHbitmap(bmp1.GetHbitmap)
''SECOND APPROACH -bmp1.scan0 OK; bmp2 scan0 error
bmp1 = Bitmap.FromFile(ofd.FileName)
bmp2 = Bitmap.FromFile(ofd.FileName)
PictureBox1.Image = bmp1
nBytes = bmp1.Width * bmp1.Height * 3
Dim bmpData As System.Drawing.Imaging.BitmapData
Dim rect As New Rectangle(0, 0, bmp1.Width, bmp1.Height)
bmpData = bmp1.LockBits(rect, Drawing.Imaging.ImageLockMode.ReadWrite, bmp1.PixelFormat)
StartAddrA = bmpData.Scan0 ''This address OK for all of numerous operations
bmp1.UnlockBits(bmpData)
Dim bmpData2 As System.Drawing.Imaging.BitmapData
bmpData2 = bmp2.LockBits(rect, Drawing.Imaging.ImageLockMode.ReadWrite, bmp2.PixelFormat)
StartAddrB = bmpData2.Scan0 ''This address fails (protected memory error)
bmp2.UnlockBits(bmpData2)
TextBox1.Text = StartAddrA.ToString
TextBox2.Text = StartAddrB.ToString
End If
End Sub
Private Sub PictureBox1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles_
PictureBox1.Click
''To compare the bitmaps during processing
Static img As Byte
If img = 0 Then img = 2
If img = 1 Then
img = 2
PictureBox1.Image = bmp2
PictureBox1.Refresh()
Else
img = 1
PictureBox1.Image = bmp1
PictureBox1.Refresh()
End If
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles_
Button1.Click
''BLUE BIAS correct for StartAddrA but not StartAddrB
Dim res As Boolean = False
res = ProcSingleImage(ProcIDBiasB, StartAddrA, nBytes, 100)
If res = True Then
TextBox2.Text = "BLUE BIAS"
Else
TextBox2.Text = ""
End If
''PictureBox1.Image = bmp1''not needed
PictureBox1.Refresh() ''REQUIRED
End Sub
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles_
Button2.Click
''INVERT
''OK but ONLY if StartAddrA is used and NOT StartAddrB
Dim res As Boolean = False
res = ProcSingleImage(ProcIDInv, StartAddrA, nBytes, 100)
If res = True Then
TextBox2.Text = "INVERT"
Else
TextBox2.Text = ""
End If
''PictureBox1.Image = bmp1''not needed
PictureBox1.Refresh() ''REQUIRED
End Sub
Private Sub Button6_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles_
Button6.Click
''Subtracts BMP2 data from BMP1
''OK but ONLY if BMP1 is used (ie called with StartAddrA in place of StartAddrB
Dim res As Boolean = False
res = ProcDoubleImage(ProcDoubleSub, StartAddrA, StartAddrB, nBytes, 100)
If res = True Then
TextBox2.Text = "DOUBLE SUB"
Else
TextBox2.Text = ""
End If
PictureBox1.Refresh() ''REQUIRED
End Sub
End Class
In the ATL DLL:
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
extern "C" BOOL __stdcall ProcSingleImage(int ProcID, char * StartAddr, int Nbytes, char modData )
/* Simple Single Image Processing*/
/* Both OK but ONLY if StartAddrA is used - NOT if StartAddrB used */
{
switch (ProcID)
{
case ProcIDNull:;
/*Null entry warning*/
return false;
break;
case ProcIDBiasB:;
/*Add bias to BLUE*/
_asm
{
push eax;preserve register
push ebx;preserve register
mov ebx, nPix;enter loop size
mov eax, StartAddr;enter loop start offset 0 = BLUE
loopSingle1:
mov cl,modData;
adc [eax],cl;process the byte (pixel colour)
jnc nocSingle1;
mov [eax],255;
nocSingle1:
inc eax;move to pixel = GREEN
inc eax;move to pixel = RED
inc eax;move to next pixel = BLUE
dec ebx;count down pixel
jnz loopSingle1;if count is not zero repeat
pop ebx;restore register
pop eax;restore register
}
return true;
break;
case ProcIDInv:;
/*INVERT*/
_asm
{
push eax;preserve register
push ebx;preserve register
mov ebx, Nbytes;enter loop size
mov eax, StartAddr;enter loop start offset 0 = WHITE
loopInv:
not [eax];invert the byte (pixel colour)
inc eax;move to next byte
dec ebx;count down byte
jnz loopInv;if count is not zero repeat
pop ebx;restore register
pop eax;restore register
}
return true;
break;
default:;
return false;
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
extern "C" BOOL __stdcall ProcDoubleImage(int ProcID, char * StartAddrA, char * StartAddrB, int nBytes, char modData )
/* Simple Double Image Processing (eg darks, dark subtraction etc) */
/* If StartAddrA is used in both eax and ebx the image is 'delted' as it
should be. However if StartAddrB is used there is a 'read protected
memory' errror.
{
switch (ProcID)
{
case ProcIDNull:;
/*Null entry warning*/
return false;
break;
case ProcDoubleSub:;
/*Sub two images = A - B */
_asm
{
push eax;preserve register
push ebx;preserve register
push ecx;preserve register
push edx;preserve register
mov eax, StartAddrA;enter loop A start
mov ebx, StartAddrB;enter loop B start
mov ecx, nBytes;enter loop size
loopDouble1:
mov dl,[eax];get image A byte
sub dl,[ebx];sub image B byte
jns nosDouble1;
mov dl,0;
nosDouble1:
mov [eax],dl;set result
inc eax;move to next image A BYTE
inc ebx;move to next image B BYTE
dec ecx;count bytes
jnz loopDouble1;if count is not zero repeat
pop edx;restore register
pop ecx;restore register
pop ebx;restore register
pop eax;restore register
}
return true;
break;
default:;
return false;
}
}