Przemysław Ernestowicz

Kierownik Działu IT, Profil Sp.J.

Wypowiedzi

  • Przemysław Ernestowicz
    Wpis na grupie Ms Access w temacie Kod EAN - generowanie
    25.04.2017, 14:16

    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

  • Przemysław Ernestowicz
    Wpis na grupie ACCESS w praktyce w temacie Kod EAN - generowanie
    25.04.2017, 14:16

    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

  • Przemysław Ernestowicz
    Wpis na grupie Access VBA w temacie Kod wywala aplikację przy Access 64-bit

    Aby mieć możliwość przeczytania tego posta musisz być członkiem grupy Access VBA

Dołącz do GoldenLine

Oferty pracy

Sprawdź aktualne oferty pracy

Aplikuj w łatwy sposób

Aplikuj jednym kliknięciem

Wyślij zaproszenie do