Przemysław Ernestowicz

Przemysław Ernestowicz Kierownik Działu IT,
Profil Sp.J.

Temat: Kod EAN - generowanie

Witam, kodu do generowania kodu kreskowego w Access.
Kod działa idealnie, ale przy Accessie 64-bitowym wywala błąd w momencie wykonywania linii:
CopyMemory aPictData(MY_BMIH_SIZE), ByVal lpByteImg, bmih.biSizeImage

Co mogę zrobić, aby kod zaczął działać?
Poniżej zamieszczam cały kod.

Option Compare Database
Option Explicit
'|===============================================================================|
'| 3.1 Kod kreskowy EAN -8 |
'| *********************************** |
'| Pobrano z : |
'| http://www.bratki.w.v1.pl/accesspseudofaq/32a_ImgCodaF... |
'|_______________________________________________________________________________|
'| Kod możesz dowolnie modyfikować, ale proszę nie usuwać tej ramki |
'| • autor: Zbigniew Bratko • 07.01.2005 r. • status: FREE |
'|===============================================================================|

Private Const ERR_FAIL_CHECK_DIGIT As Long = vbObjectError + 1000 + 2
Private Const ERR_FAIL_SCALE_MODE As Long = vbObjectError + 1000 + 3
Private Const ERR_NO_NUMERIC As Long = vbObjectError + 1000 + 4
Private Const ERR_FAIL_LEN_CODE As Long = vbObjectError + 1000 + 5

Private ctlMyImg As Access.Image
Private lMyModW As Long 'szerokość modułu (linii) w pikselach => 2^lScale
Private lMyLineH As Long 'względna wysokość właściwej kreski kodu

Private lHDC As Long 'uchwyt kontekstu urządzenia
Private lDpiX As Long 'rozdzielczość pozioma X
Private lDpiY As Long 'rozdzielczość pionowa Y
Private snPixToTwipsX As Single 'przelicznik Pikseli na Twipsy - poziomo
Private snPixToTwipsY As Single 'przelicznik Pikseli na Twipsy - pionowo
Private lEanH As Long 'przewidywana wysokość bitmapy EAN
Private lExtraEanH As Long 'dodatkowa ilość linii wydłużająca dolny margines
'===============================================================================================

Private Const MY_CHARS_IN_PART As Long = 4 'ilość cyfr w częściach kodu EAN 8
Private Const MY_CHARS_IN_CODE As Long = 8 'ilość cyfr kodu - EAN 8

Private Type ENCODINGPART
L1 As Long
W1 As Long
L2 As Long
W2 As Long
End Type

Private EanA(0 To 9) As ENCODINGPART 'kodowanie kresek zbioru A
Private EanC(0 To 9) As ENCODINGPART 'kodowanie kresek zbioru C
Private aCodeNo(MY_CHARS_IN_CODE - 1) As Byte 'wszystkie cyfry kodu kreskowego
Private lMyEanAngle As Long 'kąt obrotu kodu EAN; 0, 90, 180, 270 stopni
Private fMyResize As Boolean 'czy dopasować rozmiar ctlMyImg do bitmapy kodu EAN

'Uchwyty, pędzle, pióra, kolory, font
Private hBkgBrush As Long
Private hLineBrush As Long
Private hPen As Long
Private hFont As Long
Private hOldBrush As Long
Private hOldPen As Long
Private hOldFont As Long

Private lMyBkgCol As Long
Private lMyLineCol As Long
Private lMyFontCol As Long
Private lOldFontCol As Long
Private lOldBkgMode As Long

Private Const MY_BKG_COL As Long = vbWhite
Private Const MY_LINE_COL As Long = vbBlack
Private Const MY_FONT_COL As Long = vbBlack
Private Const MY_PEN_COL As Long = vbBlack
Private Const MY_DEF_FONT_NAME As String = "Arial"
Private Const MY_DEF_FONT_SIZE As Long = 8

Private lFontH As Long
Private lgf As LOGFONT
'=======================================================================================
'rozmiary i położenie elementów kodu EAN
Private Const MY_MARG_LEFT As Long = 11 'margines lewy = 11 modułów
Private Const MY_MARG_RIGHT As Long = 7 'margines prawy = 7 modułów
Private Const MY_MARG_TOP As Long = 2 'margines górny = 2 moduły
Private Const MY_MARG_BOTTOM As Long = 2 'margines dolny = 2 moduły

Private Const MY_WIDTH_CHARS As Long = 7 'ilość modułów na znak
Private Const MY_WIDTH_START As Long = 3 'ilość modułów na znak Start
Private Const MY_WIDTH_SEP As Long = 5 'ilość modułów na znak Separacji
Private Const MY_WIDTH_END As Long = 3 'ilość modułów na znak Stop
Private Const MY_EXTRALENGTH As Long = 5 'ilość modułów wydłużająca w/w znaki
Private Const MY_HEIGHT_LINE_MM As Long = 6 'wysokość właściwej kreski kodu w mm
'bitmapa
Private Const MY_BMIH_SIZE As Long = 40 'wielkośc nagłówka BitmapInfoHeader
Private Const MY_MIN_SIZE_BMP As Long = 10240 'minimalna wielkość bitmapy, przy mniejszych
'wielkościach czasami bitmapa jest niestabilna

Private Sub Class_Initialize()
Dim hdcAcc As Long

hdcAcc = GetDC(Application.hWndAccessApp)
lHDC = CreateCompatibleDC(hdcAcc)
Call ReleaseDC(Application.hWndAccessApp, hdcAcc)

lDpiX = GetDeviceCaps(lHDC, LOGPIXELSX)
lDpiY = GetDeviceCaps(lHDC, LOGPIXELSY)
snPixToTwipsX = 1440 / lDpiX
snPixToTwipsY = 1440 / lDpiY

EanScale = 0 '=> tworzy odpowiedniej wielkości FONT
fMyResize = True
EanHeightLineMm = MY_HEIGHT_LINE_MM

EanA(0).L1 = 3: EanA(0).W1 = 2: EanA(0).L2 = 6: EanA(0).W2 = 1
EanA(1).L1 = 2: EanA(1).W1 = 2: EanA(1).L2 = 6: EanA(1).W2 = 1
EanA(2).L1 = 2: EanA(2).W1 = 1: EanA(2).L2 = 5: EanA(2).W2 = 2
EanA(3).L1 = 1: EanA(3).W1 = 4: EanA(3).L2 = 6: EanA(3).W2 = 1
EanA(4).L1 = 1: EanA(4).W1 = 1: EanA(4).L2 = 5: EanA(4).W2 = 2
EanA(5).L1 = 1: EanA(5).W1 = 2: EanA(5).L2 = 6: EanA(5).W2 = 1
EanA(6).L1 = 1: EanA(6).W1 = 1: EanA(6).L2 = 3: EanA(6).W2 = 4
EanA(7).L1 = 1: EanA(7).W1 = 3: EanA(7).L2 = 5: EanA(7).W2 = 2
EanA(8).L1 = 1: EanA(8).W1 = 2: EanA(8).L2 = 4: EanA(8).W2 = 3
EanA(9).L1 = 3: EanA(9).W1 = 1: EanA(9).L2 = 5: EanA(9).W2 = 2

EanC(0).L1 = 0: EanC(0).W1 = 3: EanC(0).L2 = 5: EanC(0).W2 = 1
EanC(1).L1 = 0: EanC(1).W1 = 2: EanC(1).L2 = 4: EanC(1).W2 = 2
EanC(2).L1 = 0: EanC(2).W1 = 2: EanC(2).L2 = 3: EanC(2).W2 = 2
EanC(3).L1 = 0: EanC(3).W1 = 1: EanC(3).L2 = 5: EanC(3).W2 = 1
EanC(4).L1 = 0: EanC(4).W1 = 1: EanC(4).L2 = 2: EanC(4).W2 = 3
EanC(5).L1 = 0: EanC(5).W1 = 1: EanC(5).L2 = 3: EanC(5).W2 = 3
EanC(6).L1 = 0: EanC(6).W1 = 1: EanC(6).L2 = 2: EanC(6).W2 = 1
EanC(7).L1 = 0: EanC(7).W1 = 1: EanC(7).L2 = 4: EanC(7).W2 = 1
EanC(8).L1 = 0: EanC(8).W1 = 1: EanC(8).L2 = 3: EanC(8).W2 = 1
EanC(9).L1 = 0: EanC(9).W1 = 3: EanC(9).L2 = 4: EanC(9).W2 = 1

hPen = CreatePen(PS_SOLID, 1, MY_PEN_COL)
hOldPen = SelectObject(lHDC, hPen)

lMyBkgCol = MY_BKG_COL
hBkgBrush = CreateSolidBrush(MY_BKG_COL)
hOldBrush = SelectObject(lHDC, hBkgBrush)

lMyLineCol = MY_LINE_COL
hLineBrush = CreateSolidBrush(MY_LINE_COL)

lOldFontCol = SetTextColor(lHDC, vbBlue)
lOldBkgMode = SetBkMode(lHDC, TRANSPARENT)

End Sub
Private Sub Class_Terminate()

Set ctlMyImg = Nothing

'przywróć stare pióro
Call SelectObject(lHDC, hOldPen)
'zniszcz używane pióro
Call DeleteObject(hPen)
'wybierz stary pędzel
Call SelectObject(lHDC, hOldBrush)
'usuń nieużywane pędzle
Call DeleteObject(hBkgBrush)
Call DeleteObject(hLineBrush)
'przywróć kolor tekstu i styl tła
Call SetTextColor(lHDC, lOldFontCol)
Call SetBkMode(lHDC, lOldBkgMode)
'przywróć stary font
Call SelectObject(lHDC, hOldFont)
'zniszcz używany font
Call DeleteObject(hFont)
'usuń kontekst urządzenia
Call DeleteDC(lHDC)

End Sub
'kolor tła bitmapy
Public Property Let EanColorBkg(lBkgCol As Long)
lMyBkgCol = lBkgCol

SelectObject lHDC, hOldBrush
DeleteObject hBkgBrush
hBkgBrush = CreateSolidBrush(lMyBkgCol)
'SelectObject lHDC, hBkgBrush

End Property
Public Property Get EanColorBkg() As Long
EanColorBkg = lMyBkgCol
End Property
'kolor linii kodu
Public Property Let EanColorLine(lLineCol As Long)
lMyLineCol = lLineCol

SelectObject lHDC, hOldBrush
DeleteObject hLineBrush
hLineBrush = CreateSolidBrush(lMyLineCol)
'SelectObject lHDC, hLineBrush

End Property
Public Property Get EanColorLine() As Long
EanColorLine = lMyLineCol
End Property
'kolor czcionki
Public Property Let EanColorFont(lCol As Long)
lMyFontCol = lCol
SetTextColor lHDC, lCol
End Property
Public Property Get EanColorFont() As Long
EanColorFont = lMyFontCol
End Property
'kąt obrotu kodu EAN; 0, 90, 180, 270 stopni
Public Property Let EanAngle(lAng As Integer)
Dim lAngle As Integer
lAngle = lAng - (lAng \ 360) * 360

If lAngle < 0 Then lAngle = lAngle + 359
lAngle = (((Abs(lAngle)) + 45) \ 90) * 90
If lAngle >= 360 Then lAngle = 0
lMyEanAngle = lAngle

End Property
Public Property Get EanAngle() As Integer
EanAngle = lMyEanAngle
End Property
'współczynnik skalowania bitmapy
'szerokość modułu (linii) w pikselach => 2^lScale
'zmiana współczynnika wymusza utworzenie nowego fontu
Public Property Let EanScale(ByVal lScale As Long)

If lScale > 3 Then
zbRaiseErrCls ERR_FAIL_SCALE_MODE
End If

If lMyModW <> 2 ^ lScale Then
lMyModW = 2 ^ lScale
If lMyModW <= 0 Then lMyModW = 1
Call zbCreateFont
End If

End Property
'przelicza wysokość właściwych linii kodu z milimetrów na piksele
'z uwzględnieniem współczynnika skalowania
Public Property Let EanHeightLineMm(lHeight As Long)
lMyLineH = (lHeight) * lDpiY / 25.4
If lMyLineH <= 0 Then lMyLineH = 1 * lDpiY / 25.4
lMyLineH = lMyLineH * lMyModW
End Property
'formant Image wyświetlający kod EAN-8
Public Sub zbSetImgEan8(ctlImg As Access.Image)
Set ctlMyImg = ctlImg
End Sub
'czy dopasować rozmiar ctlMyImg do bitmapy kodu
Public Property Let EanResizeImg(fResize As Boolean)
fMyResize = fResize
End Property
'funkcja wywołująca tworzenie kodu EAN-8, zwraca liczbę kontrolną lub ""
Public Function DrawCodeBarEan8(sCode As String) As String
Dim lChkDig As Long

lChkDig = zbCheckDigitExamine(sCode)
If lChkDig > -1 Then
DrawCodeBarEan8 = lChkDig
Call zbBmpCreate
Else
DrawCodeBarEan8 = ""
End If

End Function
'zwraca liczbę kontrolną dla potrzeb formularza (OnChange)- lokalnie używa aNo()
'TUTAJ NIE JEST STOSOWANA - wewnątrz klasy stosowana jest zbCheckDigitExamine
Public Function zbCheckDigitCalculateEAN(sCode As String) As String
Dim aNo(0 To MY_CHARS_IN_CODE - 2) As Byte
Dim lChkDig As Long
Dim fOddEv As Boolean
Dim i As Integer

'sprawdź poprawność stringu wejściowego
If Len(sCode) <> MY_CHARS_IN_CODE - 1 Or IsNumeric(sCode) = False Then
If IsNull(ctlMyImg.PictureData) = False Then ctlMyImg.Picture = ""
zbCheckDigitCalculateEAN = ""
Exit Function
End If

CopyMemory aNo(0), ByVal sCode, MY_CHARS_IN_CODE - 1

fOddEv = True
For i = 0 To MY_CHARS_IN_CODE - 2
aNo(i) = Chr$(aNo(i))

If fOddEv = True Then
lChkDig = lChkDig + 3 * aNo(i)
Else
lChkDig = lChkDig + aNo(i)
End If
fOddEv = Not fOddEv
Next

lChkDig = lChkDig Mod 10
If lChkDig > 0 Then lChkDig = 10 - lChkDig

zbCheckDigitCalculateEAN = lChkDig

End Function
'tworzy bitmapę, przemalowuje ją kolorem tła i wywołuje funkcję:
'rysująca kod i obracającą bitmapę kodu kreskowego
Private Sub zbBmpCreate()

Dim bmih As BITMAPINFOHEADER
Dim aPictData() As Byte 'bajty bitmapy - odpowiednik img.PictureData
Dim lBmpWidth As Long 'całkowita szerkośc bitmapy
Dim lpByteImg As Long 'wskaźnik do bajtów obrazu
Dim lLenLine As Long 'ilość bajtów linii bitmapy
Dim hBmp As Long 'uchwyt Bmp
Dim hMyOldBitmap As Long ' ""

'szerokość bitmapy - orientacja pozioma
lBmpWidth = (MY_MARG_LEFT + _
MY_WIDTH_START + MY_CHARS_IN_PART * MY_WIDTH_CHARS + _
MY_WIDTH_SEP + _
MY_CHARS_IN_PART * MY_WIDTH_CHARS + MY_WIDTH_END + _
MY_MARG_RIGHT) * lMyModW

'szerokość linii w bajtach
lLenLine = ((lBmpWidth * 3 + 3) \ 4) * 4
'przewidywana wysokość bitmapy
lEanH = (MY_MARG_TOP + MY_MARG_BOTTOM) * lMyModW + lFontH + lMyLineH

'zwiększaj margines dolny, aż do przekroczenia granicy MY_MIN_SIZE_BMP
'zbyt małe bitmapy nie zawsze są właściwie odmalowywane.
'Access Bug ???
lExtraEanH = 0
Do While (lEanH + lExtraEanH) * lLenLine < MY_MIN_SIZE_BMP
lExtraEanH = lExtraEanH + 1
Loop

'Utwórz nagłówek BitmapInfoHeader
With bmih
.biSize = MY_BMIH_SIZE
.biWidth = lBmpWidth
.biHeight = lEanH + lExtraEanH
.biPlanes = 1
.biBitCount = 24
.biCompression = 0
.biSizeImage = ((.biHeight * lLenLine))
.biXPelsPerMeter = 0
.biYPelsPerMeter = 0
.biClrUsed = 0
.biClrImportant = 0
End With

'utwórz bitmapę
hBmp = CreateDIBSection(lHDC, bmih, DIB_RGB_COLORS, lpByteImg, 0&, 0&)
hMyOldBitmap = SelectObject(lHDC, hBmp)

ReDim aPictData(0 To MY_BMIH_SIZE + bmih.biSizeImage - 1)
'kopiuj nagłówek bitmapy do tablicy
CopyMemory aPictData(0), bmih, MY_BMIH_SIZE

'przemaluj bitmapę
SelectObject lHDC, hBkgBrush
Call ExtFloodFill(lHDC, 0, 0, lMyBkgCol, FLOODFILLBORDER)

Call zbBmpPaint

CopyMemory aPictData(MY_BMIH_SIZE), ByVal lpByteImg, bmih.biSizeImage

SelectObject lHDC, hMyOldBitmap
DeleteObject hBmp
'DeleteDC lHDC

Call zbBmpRotate(aPictData())

End Sub
Private Sub zbBmpPaint()
Dim rct As RECT
Dim sde(0 To 5) As POINTAPI 'wspólrzędne znaków: Start, Sep, Stop
Dim i As Byte
Dim sText As String
Dim papi As POINTAPI
Dim bNumer As Byte

'współrzędne znaków Start
sde(0).x = MY_MARG_LEFT: sde(0).Y = sde(0).x + 1
sde(1).x = sde(0).Y + 1: sde(1).Y = sde(1).x + 1
'współrzędne znaków Separatora
sde(2).x = sde(1).Y + MY_WIDTH_CHARS * MY_CHARS_IN_PART
sde(2).x = sde(2).x + 1: sde(2).Y = sde(2).x + 1
sde(3).x = sde(2).Y + 1: sde(3).Y = sde(3).x + 1
'współrzędne znaków Stop
sde(4).x = sde(3).Y + MY_WIDTH_CHARS * MY_CHARS_IN_PART
sde(4).x = sde(4).x + 1: sde(4).Y = sde(4).x + 1
sde(5).x = sde(4).Y + 1: sde(5).Y = sde(5).x + 1

'TEXT - cyfry lewej części kodu
rct.Top = lEanH - lFontH - MY_MARG_BOTTOM * lMyModW '- lExtraEanH
rct.Bottom = rct.Top + lFontH

For i = 0 To MY_CHARS_IN_PART - 1
rct.Left = (sde(1).Y + i * MY_WIDTH_CHARS) * lMyModW + lMyModW
rct.Right = rct.Left + MY_WIDTH_CHARS * lMyModW + lMyModW
sText = CStr(aCodeNo(i))
DrawText lHDC, sText, Len(sText), rct, DT_CENTER
Next

'TEXT - cyfry prawej części kodu
For i = 0 To MY_CHARS_IN_PART - 1
rct.Left = (sde(3).Y + i * MY_WIDTH_CHARS) * lMyModW + lMyModW
rct.Right = rct.Left + MY_WIDTH_CHARS * lMyModW + lMyModW
sText = CStr(aCodeNo(i + MY_CHARS_IN_PART))
DrawText lHDC, sText, Len(sText), rct, DT_CENTER
Next

'KOD - znaki Startu, Separacji i Stopu
rct.Top = MY_MARG_TOP * lMyModW
rct.Bottom = rct.Top + lMyLineH + MY_EXTRALENGTH * lMyModW

For i = 0 To 5
rct.Left = sde(i).x * lMyModW
rct.Right = sde(i).Y * lMyModW
FillRect lHDC, rct, hLineBrush
Next

'KOD - lewa część kodu
rct.Bottom = rct.Top + lMyLineH

For i = 0 To MY_CHARS_IN_PART - 1
rct.Left = (sde(1).Y + i * MY_WIDTH_CHARS + EanA(aCodeNo(i)).L1) * lMyModW
rct.Right = rct.Left + (EanA(aCodeNo(i)).W1) * lMyModW
FillRect lHDC, rct, hLineBrush

rct.Left = (sde(1).Y + i * MY_WIDTH_CHARS + EanA(aCodeNo(i)).L2) * lMyModW
rct.Right = rct.Left + EanA(aCodeNo(i)).W2 * lMyModW
FillRect lHDC, rct, hLineBrush
Next

'KOD - prawa część kodu
For i = 0 To MY_CHARS_IN_PART - 1
bNumer = aCodeNo(i + MY_CHARS_IN_PART)
rct.Left = (sde(3).Y + 1 + i * MY_WIDTH_CHARS) * lMyModW
rct.Right = rct.Left + EanC(bNumer).W1 * lMyModW
FillRect lHDC, rct, hLineBrush

rct.Left = rct.Left + EanC(bNumer).L2 * lMyModW
rct.Right = rct.Left + EanC(bNumer).W2 * lMyModW
FillRect lHDC, rct, hLineBrush
Next

End Sub
'sprawdza liczbę kontrolną dla potrzeb klasy - pobiera tekst
'przy powodzeniu zwraca liczbę kontrolną i ustawia tablicę aCodeNo()
'przy niepowodzeniu zwraca -1, tablica aCodeNo() jest zerowana
Private Function zbCheckDigitExamine(sCode As String, _
Optional fRaiseErr As Boolean = True) As Long
Dim lChkDig As Long
Dim fOddEv As Boolean
Dim i As Integer

Erase aCodeNo()

If Len(sCode) <> MY_CHARS_IN_CODE Then
zbCheckDigitExamine = -1
If fRaiseErr = True Then zbRaiseErrCls ERR_FAIL_LEN_CODE
End If

If IsNumeric(sCode) = False Then
zbCheckDigitExamine = -1
If fRaiseErr = True Then zbRaiseErrCls ERR_NO_NUMERIC
End If

CopyMemory aCodeNo(0), ByVal sCode, MY_CHARS_IN_CODE

fOddEv = True
For i = 0 To MY_CHARS_IN_CODE - 2
aCodeNo(i) = Chr$(aCodeNo(i))

If fOddEv = True Then
lChkDig = lChkDig + 3 * aCodeNo(i)
Else
lChkDig = lChkDig + aCodeNo(i)
End If
fOddEv = Not fOddEv
Next

'konwertuj ostatni znak
aCodeNo(MY_CHARS_IN_CODE - 1) = Chr$(aCodeNo(MY_CHARS_IN_CODE - 1))

lChkDig = lChkDig Mod 10
If lChkDig > 0 Then lChkDig = 10 - lChkDig

If lChkDig = aCodeNo(MY_CHARS_IN_CODE - 1) Then
zbCheckDigitExamine = aCodeNo(MY_CHARS_IN_CODE - 1)
Else
zbCheckDigitExamine = -1
If fRaiseErr = True Then zbRaiseErrCls ERR_FAIL_CHECK_DIGIT
End If

End Function
'tworzy nowy font przy zmianie skali odwzorowania
Private Sub zbCreateFont()
Dim fnWH As POINTAPI
Dim f As Boolean

With lgf
.lfHeight = MY_DEF_FONT_SIZE * lMyModW * -lDpiY / 72
.lfWidth = 0
.lfEscapement = 0
.lfOrientation = 0
.lfWeight = FW_NORMAL
.lfItalic = False
.lfUnderline = False
.lfStrikeOut = False
.lfCharSet = EASTEUROPE_CHARSET
.lfOutPrecision = OUT_DEFAULT_PRECIS
.lfClipPrecision = CLIP_DEFAULT_PRECIS
.lfQuality = DEFAULT_QUALITY
.lfPitchAndFamily = DEFAULT_PITCH
.lfFaceName = MY_DEF_FONT_NAME & vbNullChar
End With

If hOldFont <> 0 Then
SelectObject lHDC, hOldFont
DeleteObject hFont
End If

Do
hFont = CreateFontIndirect(lgf)
hOldFont = SelectObject(lHDC, hFont)

GetTextExtentPoint32 lHDC, "8", 1&, fnWH

If (fnWH.x + 1 * lMyModW) <= MY_WIDTH_CHARS * lMyModW Then
f = True
lFontH = fnWH.Y
Else
SelectObject lHDC, hOldFont
DeleteObject hFont
lgf.lfHeight = lgf.lfHeight + 1
End If
Loop While f = False

End Sub
Private Sub zbBmpRotate(aPData() As Byte)
Dim bmih As BITMAPINFOHEADER 'nagłówek bitmapy
Dim aTmp() As Byte 'robocza tablica bajtów PictureData
Dim aLine() As Byte 'tablica bajtów jednej linii bitmapy
Dim lLenLine As Long 'aktualna ilość bajtów linii bitmapy
Dim lOrigLenLine As Long 'oryginalna ilość bajtów linii bitmapy
Dim lOrig_X As Long, lOrig_Y As Long 'oryginalna szerokość/wysokość bitmapy
Dim lNew_X As Long, lNew_Y As Long 'aktualna szerokość/wysokość bitmapy
Dim i As Long, j As Long, k As Long 'liczniki
Dim lMaxY As Long, lMaxX As Long 'wartość obliczeniowa
Dim lTmp1 As Long, lTmp2 As Long 'wartość obliczeniowa
Dim lByte_X As Long 'wartość obliczeniowa

CopyMemory bmih, aPData(0), MY_BMIH_SIZE

lOrig_X = bmih.biWidth
lOrig_Y = bmih.biHeight

'bez obrotu
If lMyEanAngle = 0 Then
With ctlMyImg
.PictureData = aPData()
If fMyResize = True Then
.Width = snPixToTwipsX * lOrig_X
.Height = snPixToTwipsY * lOrig_Y
End If
End With
Exit Sub
End If

'te same wymiary bitmapy
If lMyEanAngle = 180 Then
lNew_X = lOrig_X
lNew_Y = lOrig_Y
Else
lNew_X = lOrig_Y
lNew_Y = lOrig_X
'zmiana orientacji, zapamiętaj oryginalną długość linii
lOrigLenLine = ((lOrig_X * 3 + 3) \ 4) * 4 '-----------------------------------------------------------------
End If

lMaxY = lOrig_Y - 1
lMaxX = 3 * lNew_X - 3

lLenLine = ((lNew_X * 3 + 3) \ 4) * 4 '----------------------------------------------------------------------------

'Utwórz nagłówek BitmapInfoHeader
With bmih
.biSize = MY_BMIH_SIZE
.biWidth = lNew_X
.biHeight = lNew_Y
.biPlanes = 1
.biBitCount = 24
.biCompression = 0
.biSizeImage = lNew_Y * lLenLine
.biXPelsPerMeter = 0
.biYPelsPerMeter = 0
.biClrUsed = 0
.biClrImportant = 0
End With
Erase aTmp

ReDim aTmp(0 To MY_BMIH_SIZE + bmih.biSizeImage - 1)
CopyMemory aTmp(0), bmih, MY_BMIH_SIZE


lByte_X = 3 * lOrig_X
'zainicjuj tablicę bajtów jednej linii
ReDim aLine(0 To lByte_X - 1)

Select Case lMyEanAngle
Case 180
For j = 0 To lMaxY
CopyMemory aLine(0), aPData(MY_BMIH_SIZE + j * lLenLine), lByte_X
lTmp1 = MY_BMIH_SIZE + (lMaxY - j) * lLenLine
For i = 0 To lMaxX Step 3
aTmp(lTmp1 + i + 0) = aLine(lMaxX - i + 0)
aTmp(lTmp1 + i + 1) = aLine(lMaxX - i + 1)
aTmp(lTmp1 + i + 2) = aLine(lMaxX - i + 2)
Next
Next
Case 90
lTmp2 = lByte_X - 3

For j = 0 To lMaxY
CopyMemory aLine(0), aPData(MY_BMIH_SIZE + j * lOrigLenLine), lByte_X
lTmp1 = MY_BMIH_SIZE + j * 3
For i = 0 To lByte_X - 3 Step 3
'===================== obrót o 90 stopni =============
aTmp(k * lLenLine + 0 + lTmp1) = aLine(lTmp2 - i + 0)
aTmp(k * lLenLine + 1 + lTmp1) = aLine(lTmp2 - i + 1)
aTmp(k * lLenLine + 2 + lTmp1) = aLine(lTmp2 - i + 2)
'=====================================================
'obrót o 90 stopni i Flip Vertical
'aTmp(MY_BMIH_SIZE + (k) * lLenLine + 0 + j * 3) = aLine(i + 0)
'aTmp(MY_BMIH_SIZE + (k) * lLenLine + 1 + j * 3) = aLine(i + 1)
'aTmp(MY_BMIH_SIZE + (k) * lLenLine + 2 + j * 3) = aLine(i + 2)
k = k + 1
Next
k = 0
Next
Case 270
For j = 0 To lMaxY
CopyMemory aLine(0), aPData(MY_BMIH_SIZE + j * lOrigLenLine), lByte_X
lTmp1 = MY_BMIH_SIZE + (lMaxY - j) * 3
For i = 0 To lByte_X - 3 Step 3
'================= obrót o 270 stopni =================
aTmp(k * lLenLine + 0 + lTmp1) = aLine(i + 0)
aTmp(k * lLenLine + 1 + lTmp1) = aLine(i + 1)
aTmp(k * lLenLine + 2 + lTmp1) = aLine(i + 2)
'=======================================================
'======== obrót o 90 stopni i Flip Horizontal ========
'aTmp(MY_BMIH_SIZE + (k) * lLenLine + 0 + j * 3) = aLine(i + 0)
'aTmp(MY_BMIH_SIZE + (k) * lLenLine + 1 + j * 3) = aLine(i + 1)
'aTmp(MY_BMIH_SIZE + (k) * lLenLine + 2 + j * 3) = aLine(i + 2)
k = k + 1
Next
k = 0
Next
Case Else
ctlMyImg.Picture = ""
Exit Sub
End Select

With ctlMyImg
.PictureData = aTmp()
'przeskaluj formant Image
If fMyResize = True Then
.Width = snPixToTwipsX * lNew_X
.Height = snPixToTwipsY * lNew_Y
End If
End With

End Sub
Private Sub zbRaiseErrCls(lMyErr As Long, Optional sInfo As String = "", _
Optional fRaise As Boolean = True)
Dim sDescr As String
Dim sSource As String

Select Case lMyErr
Case ERR_FAIL_CHECK_DIGIT
sDescr = "Nieprawidłowa liczba kontrolna kodu EAN !"
Case ERR_FAIL_SCALE_MODE
sDescr = "Największa dopuszczalna wartośc współczynnika" & vbNewLine & _
"skalowania kodu EAN nie może być większa niż 3 !"
Case ERR_NO_NUMERIC
sDescr = "Nieprawidłowy kod EAN " & vbNewLine & _
"Oczekiwano wartości numerycznej."
Case ERR_FAIL_LEN_CODE
sDescr = "Nieprawidłowa długość kodu EAN !"
Case Else
sDescr = "Nieprzewidziany błąd." & vbNewLine & _
" Proszę zanotować nr błędu i okoliczności jego wystąpienia" & vbNewLine & _
"i skontaktować się z Administratorem Bazy !"
End Select

If Len(sInfo) > 0 Then sDescr = sDescr & vbNewLine & sInfo
'wygeneruj błąd
Err.Raise lMyErr, "", sDescr

End Sub