Author Topic: Tags Library  (Read 64162 times)

chrisw100

  • Posts: 1
Re: NEW: Tags Library
« Reply #400 on: 23 Jun '17 - 09:48 »
Hi All

Apologies if this has been covered, but I can't seem to find details anywhere to help on how to update a cart tag and then save it back to the wav. It appears that I'm not setting the new value correctly, as if I  execute TagsLibrary_Save to a different filename, it will write 3k worth of tag data.

Heres the code (VB6) where I'm trying to set the EndDate value of cart chunk. Sadly the VB6 example doesn't have any save code example.
If I execute the TagsLibrary_SetTag code on its own, it returns a value of -1

Thank you

Chris.


Public Function SaveTag(FileName As String) As Integer
    If Not FileExists(FileName) Then
        SaveTag = TAGSLIBRARY_ERROR_WRITING_FILE
        Exit Function
    Else
        SaveTag = TagsLibrary_SetTag(LngTags, StrPtr("CART EndDate"), StrPtr("2017/01/01"), ttWAV)
        SaveTag = TagsLibrary_Save(LngTags, StrPtr(FileName), ttWAV)
    End If
End Function

3delite

  • Posts: 916
Re: NEW: Tags Library
« Reply #401 on: 28 Jun '17 - 05:14 »
Your code looks ok, checked the library's code and I don't see a reason why it doesn't work.
Is StrPtr() resulting a unicode string? All Tags Library functions require unicode strings.

EWeiss

  • Posts: 355
Re: NEW: Tags Library
« Reply #402 on: 28 Jun '17 - 06:30 »
Your code looks ok, checked the library's code and I don't see a reason why it doesn't work.
Is StrPtr() resulting a unicode string? All Tags Library functions require unicode strings.

see..
http://vb.mvps.org/tips/varptr/

greets
« Last Edit: 28 Jun '17 - 06:52 by EWeiss »

Steve Grant

  • Posts: 152
Re: Tags Library
« Reply #403 on: 4 Dec '17 - 10:56 »
I am having problems in getting an image to save to a file. I am using Visual Basic 6 and I hope I have got the parameters correct. Here is the code I am using;

Code: [Select]
Dim CoverArt As TCoverArtData, I64 As Int64
    If PicFileName <> "" Then
        CoverArt.ColorDepth = 0
        CoverArt.CoverType = 3
        CoverArt.Description = StrPtr("")
        CoverArt.DataSize.LowPart = FileLen(PicFileName)
        CoverArt.Height = 300
        CoverArt.ID3v2TextEncoding = 0
        CoverArt.Index = 0
        CoverArt.MIMEType = StrPtr("image/jpeg")
        CoverArt.Name = StrPtr("Cover art 1")
        CoverArt.NoOfColors = 0
        CoverArt.PictureFormat = tpfJPEG
        CoverArt.Width = 300
        TagsLibrary_SetCoverArtFromFile lTags, ttAutomatic, 0, StrPtr(PicFileName), CoverArt
    End If

This code just makes the IDE crash instantly. Also, if I am loading the picture from a file, what would the 'Data' parameter be?

I know you are a Delphi man but perhaps Eric will see this.

3delite

  • Posts: 916
Re: Tags Library
« Reply #404 on: 4 Dec '17 - 14:40 »
The 'Index' must be a valid (existing) cover art. But checking the code, the function should just fail if the 'Index' is not valid.

Is TagsLibrary_AddCoverArt() called before? The return value should be the 'Index' to be used in TagsLibrary_SetCoverArtFromFile().

I'm not sure what the problem could be, the code is quite simple, here it is (only the ttAutomatic branch):

Code: [Select]
function TagsLibrary_SetCoverArtFromFile(Tags: TTags; TagType: TagsLibrary.TTagType; Index: Integer; FileName: PChar; CoverArt: TCoverArtData): LongBool; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; export;
var
    i: Integer;
    Counter: Integer;
    TempStream: TStream;
    FlacTagCoverArtInfo: TFlacTagCoverArtInfo;
    MP4Atom: TMP4Atom;
    OggVorbisAndOpusTagCoverArtInfo: TOpusVorbisCoverArtInfo;
begin
    Result := False;
    if Assigned(Tags) then begin
        case TagType of
            TagsLibrary.ttAutomatic: begin
                if (Index >= Length(Tags.CoverArts))
                OR (Index < 0)
                then begin
                    Exit;
                end;
                try
                    Tags.CoverArts[Index].Name := CoverArt.Name;
                    TMemoryStream(Tags.CoverArts[Index].Stream).LoadFromFile(FileName);
                    Result := True;
                except
                    //*
                end;
            end;
            ...

function TagsLibrary_AddCoverArt(Tags: TTags; TagType: TagsLibrary.TTagType; CoverArt: TCoverArtData): Integer; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; export;
var
    MP4Atom: TMP4Atom;
    CoverArtInfo: TOpusVorbisCoverArtInfo;
begin
    Result := - 1;
    if Assigned(Tags) then begin
        case TagType of
            TagsLibrary.ttAutomatic: begin
                Result := Tags.AddCoverArt(CoverArt.Name).Index;
            end;
            ...

Very few info is used from the TCoverArtData in ttAutomatic mode for these functions, as you can see above , basically only the 'Name', should not crash if some other info is invalid.
These data is set when the TagsLibrary_AddCoverArt() or TagsLibrary_SetCoverArt is called.

The simplest solution would be if you could create a little test app., if it also crashes, please contact me at 3delite@3delite.hu and I debug what's happening. Also please make sure you are using the latest version: https://www.3delite.hu/Object%20Pascal%20Developer%20Resources/download.html#tagslibrary

Thank you!
« Last Edit: 4 Dec '17 - 15:15 by 3delite »

Steve Grant

  • Posts: 152
Re: Tags Library
« Reply #405 on: 4 Dec '17 - 22:30 »
Thank you for your comments, but there is not enough information for me to try and sort this out. Here is the code I am using now;
I( have remarked all of the CoverArt settings and have filled in the AddCoverArt settings. I have applied Index to TagsLibrary_SetCoverArtFromFile but I don't think it getting that far.
I asked above: what is CoverArt_Data? Am I at least filling in the parameters correctly.

Code: [Select]
   
    Dim CoverArt As TCoverArtData, I64 As Int64, Index As Long
    If PicFileName <> "" Then
'        CoverArt.ColorDepth = 0
'        CoverArt.CoverType = 3
'        CoverArt.Description = StrPtr("")
'        CoverArt.DataSize.LowPart = FileLen(PicFileName)
'        CoverArt.Height = 300
'        CoverArt.ID3v2TextEncoding = 0
'        CoverArt.Index = Index
'        CoverArt.MIMEType = StrPtr("image/jpeg")
'        CoverArt.Name = StrPtr("New CoverArt")
'        CoverArt.NoOfColors = 0
'        CoverArt.PictureFormat = tpfJPEG
'        CoverArt.Width = 300
        I64.LowPart = FileLen(PicFileName)
        I64.HighPart = 0
        Index = TagsLibrary_AddCoverArt(lTags, ttAutomatic, StrPtr("New CoverArt"), 0, I64, StrPtr(""), 3, StrPtr("image/jpeg"), tpfJPEG, 300, 300, 0, 0, 0, 0)
       
        TagsLibrary_SetCoverArtFromFile lTags, ttAutomatic, Index, StrPtr(PicFileName), CoverArt
    End If

The problem is it crashes instantly with no hope of locating the problem! Reading & Writing of tags is is completely ok, it is just the writing of pictures that is a problem. There is no point creating a small test program as the same will happen.

EWeiss

  • Posts: 355
Re: Tags Library
« Reply #406 on: 5 Dec '17 - 03:21 »
i have test my example in the package of Tags Library and all works fine no Crash or other.
the CoverArtData is a struct\Structure\Record  which filled with the Picture Data from a MemoryStream REAL Picture, jpg, png and so on.

if you not using my Wrapper then your must convert a stdpicture from VB to a Memorystream assign it to Coverartdata and write it to your *mp3 file as example.

CoverArtData.Data = imagePtr "Pointer to your MemoryStream"
CoverArtData.DataSize = BitmapStream.Length "length of your Bitmap Stream"
the other CoverArtData should be filled with the Imagetype which your used. (see as example ImageFormat.Jpeg)

Code: [Select]
    Private Sub AddCover(sender As Object, e As MouseEventArgs)

        If Tags.HTags <> IntPtr.Zero Then

            '//* Clear the cover art data
            Dim MIMEType As String = ""
            Dim Description As String = ""
            Dim Width As Integer = 0
            Dim Height As Integer = 0
            Dim ColorDepth As Integer = 0
            Dim NoOfColors As Integer = 0
            Dim pval As IntPtr = IntPtr.Zero

            Dim CoverArtData As TCoverArtData = New TCoverArtData()
            Dim CoverArtPictureFormat As TTagPictureFormat = TTagPictureFormat.tpfUnknown

            OpenFileDialog1.FileName = ""
            OpenFileDialog1.Title = "Select a File..."
            OpenFileDialog1.Filter = "Picture files (*.jpg*,*.jpeg*,*.bmp*,*.png*,*.gif*)|*.jpg*;*.jpeg*;*.bmp*;*.png*;*.gif*"

            If OpenFileDialog1.ShowDialog() = DialogResult.OK Then

                If (File.Exists(OpenFileDialog1.FileName)) Then

                    Dim BitmapStream = New MemoryStream()
                    Dim fs As FileStream = File.Open(OpenFileDialog1.FileName, FileMode.Open)

                    fs.CopyTo(BitmapStream)
                    BitmapStream.Position = 0

                    Dim img As Image = Image.FromStream(BitmapStream)
                    fs.Close()

                    If (img.RawFormat.Equals(System.Drawing.Imaging.ImageFormat.Jpeg)) Then

                        MIMEType = "image/jpeg"
                        CoverArtPictureFormat = TTagPictureFormat.tpfJPEG
                        Description = Path.GetFileName(OpenFileDialog1.FileName)
                        Width = img.Width
                        Height = img.Height
                        NoOfColors = 0
                        ColorDepth = 24

                    ElseIf (img.RawFormat.Equals(System.Drawing.Imaging.ImageFormat.Png)) Then

                        Width = img.Width
                        Height = img.Height
                        NoOfColors = 0
                        ColorDepth = Image.GetPixelFormatSize(img.PixelFormat)

                    ElseIf (img.RawFormat.Equals(System.Drawing.Imaging.ImageFormat.Gif)) Then

                        Width = img.Width
                        Height = img.Height
                        NoOfColors = 0
                        ColorDepth = Image.GetPixelFormatSize(img.PixelFormat)

                    ElseIf (img.RawFormat.Equals(System.Drawing.Imaging.ImageFormat.Bmp)) Then

                        Width = img.Width
                        Height = img.Height
                        NoOfColors = 0
                        ColorDepth = Image.GetPixelFormatSize(img.PixelFormat)
                    End If

                    Dim openFile As Byte()
                    openFile = File.ReadAllBytes(OpenFileDialog1.FileName)

                    Dim imagePtr As IntPtr = Utils.GetPointerfromByteArray(openFile)

                    CoverArtData.NameSPtr = Marshal.StringToHGlobalAuto(Description)
                    CoverArtData.CoverType = CoverTypes
                    CoverArtData.MIMETypeSPtr = Marshal.StringToHGlobalAuto(MIMEType)
                    CoverArtData.DescriptionSPtr = Marshal.StringToHGlobalAuto(Description)
                    CoverArtData.Width = Width
                    CoverArtData.Height = Height
                    CoverArtData.ColorDepth = ColorDepth
                    CoverArtData.NoOfColors = NoOfColors
                    CoverArtData.PictureFormat = CoverArtPictureFormat
                    CoverArtData.Data = imagePtr
                    CoverArtData.DataSize = BitmapStream.Length

                    If (TagsLib.TagsLibrary_AddCoverArt(Tags, TTagType.ttAutomatic, CoverArtData) = -1) Then

                        MessageBox.Show("Error while adding cover art: ", OpenFileDialog1.FileName, MessageBoxButtons.AbortRetryIgnore, MessageBoxIcon.Error)
                    End If
                    imagePtr = IntPtr.Zero

                    BitmapStream.Close()
                    btnSave_MouseDown(sender, e)
                End If
            End If
        End If

    End Sub

and here is a big difference or? (ok i think is a external Sub :)  )

Code: [Select]
TagsLibrary_AddCoverArt(lTags, ttAutomatic, StrPtr("New CoverArt"), 0, I64, StrPtr(""), 3, StrPtr("image/jpeg"), tpfJPEG, 300, 300, 0, 0, 0, 0)
Code: [Select]
TagsLib.TagsLibrary_AddCoverArt(Tags, TTagType.ttAutomatic, CoverArtData)
if you understand correctly and your want create a blank Image without Image Data.
then create a MemoryStream from it and assign the Data to CoverArtData.

btw.. your want also save a Image with a bit depth of 0 ? using for Jpeg 24Bit or 32Bit not 0 that must fail.
also compare your Settings with my own.

at last!
You can not Fill the CoverArtData Structure as your want that must always valid Image Value.

greets
« Last Edit: 5 Dec '17 - 04:39 by EWeiss »

Steve Grant

  • Posts: 152
Re: Tags Library
« Reply #407 on: 5 Dec '17 - 10:09 »
@Emil, many thanks for offering your code. This appears to be vbNet and I am using VB6, so sadly I do not understand your code.

I looked at your wrapper but It does not show an image being saved to the tag. So I have tried loading the image into an image control and then hBitmap=image1.picture.

I then try the Addcoverart call again;

Code: [Select]
I64.LowPart = FileLen(PicFileName)
         I64.HighPart = 0
Index = TagsLibrary_AddCoverArt(lTags, ttAutomatic, StrPtr("New CoverArt"), VarPtr(hBitmap), I64, StrPtr(""), 3, StrPtr("image/jpeg"), tpfJPEG, 300, 300, 24, 0, 0, 0)

I don't know how to get the size of the image in memory so am using the FileLen. Are you able to help me more?

Greets Steve.

EWeiss

  • Posts: 355
Re: Tags Library
« Reply #408 on: 5 Dec '17 - 15:02 »
@Emil, many thanks for offering your code. This appears to be vbNet and I am using VB6, so sadly I do not understand your code.

I looked at your wrapper but It does not show an image being saved to the tag. So I have tried loading the image into an image control and then hBitmap=image1.picture.

I then try the Addcoverart call again;

Code: [Select]
I64.LowPart = FileLen(PicFileName)
         I64.HighPart = 0
Index = TagsLibrary_AddCoverArt(lTags, ttAutomatic, StrPtr("New CoverArt"), VarPtr(hBitmap), I64, StrPtr(""), 3, StrPtr("image/jpeg"), tpfJPEG, 300, 300, 24, 0, 0, 0)

I don't know how to get the size of the image in memory so am using the FileLen. Are you able to help me more?

Greets Steve.

sorry i am not found a solution yet.

greets
« Last Edit: 5 Dec '17 - 16:25 by EWeiss »

3delite

  • Posts: 916
Re: Tags Library
« Reply #409 on: 5 Dec '17 - 16:23 »
Creating a little test app. would help me to check what is happening inside the function, I could debug it.

Sorry, TCoverArtData.Data should be a pointer to the picture file data's address and TCoverArtData.DataSize is the size of this data. These are only used when setting a cover art from memory, I think you should go for the file version though.

One note: Is VB clearing the TCoverArtData structure when it is created? If not (Delphi doesn't) I'm note sure, but maybe the HighPart of DataSize contains random data, as it's not set, that would cause AV if it is so, as it would give a random DataSize and the library would try to copy that much data from the address.

EWeiss

  • Posts: 355
Re: Tags Library
« Reply #410 on: 5 Dec '17 - 16:32 »
Creating a little test app. would help me to check what is happening inside the function, I could debug it.

Sorry, TCoverArtData.Data should be a pointer to the picture file data's address and TCoverArtData.DataSize is the size of this data. These are only used when setting a cover art from memory, I think you should go for the file version though.

One note: Is VB clearing the TCoverArtData structure when it is created? If not (Delphi doesn't) I'm note sure, but maybe the HighPart of DataSize contains random data, as it's not set, that would cause AV if it is so, as it would give a random DataSize and the library would try to copy that much data from the address.

VB6 has Trouble with pointers so is not simple.
create a procedure like this and good is.

AddCoverArt(MySoundFilePath, MyPIcturePath) then write the Data inside Delphi self with the given SoundFilePath.
read the file back works

but the IStream.tlb which are used is not the right one for handle this in VB6.

greets

3delite

  • Posts: 916
Re: Tags Library
« Reply #411 on: 5 Dec '17 - 16:48 »
Tried just to be sure, it's working fine here:

Code: [Select]
                CoverArtData.Name := PwideChar(Description);
                CoverArtData.CoverType := 3; //* ID3v2 cover type (3: front cover)
                CoverArtData.MIMEType := PwideChar(MIMEType);
                CoverArtData.Description := PwideChar(Description);
                CoverArtData.Width := Width;
                CoverArtData.Height := Height;
                CoverArtData.ColorDepth := ColorDepth;
                CoverArtData.NoOfColors := NoOfColors;
                CoverArtData.PictureFormat := CoverArtPictureFormat;
                CoverArtData.Data := nil; //PictureStream.Memory;
                CoverArtData.DataSize := 0; //PictureStream.Size;
                NewCoverArtIndex := TagsLibrary_AddCoverArt(Tags, ttAutomatic, CoverArtData);
                if NOT TagsLibrary_SetCoverArtFromFile(Tags, ttAutomatic, NewCoverArtIndex, PChar(OpenDialog1.FileName), CoverArtData) then begin
                    MessageDlg('Error while adding cover art: ' + OpenDialog1.FileName, mtError, [mbCancel], 0);
                end;

Are you sure 'lTags' is valid?

Also what is the size of the TCoverArtData struct there? It should be 56 bytes.

Code: [Select]
    Showmessage(IntToStr(SizeOf(TCoverArtData)));

EDIT: Ok got it, in your first post you set the TCoverArtData.DataSize to non-zero value, set it to 0 (low and high part too) and call the:

Code: [Select]
    NewCoverArtIndex := TagsLibrary_AddCoverArt(Tags, ttAutomatic, CoverArtData);

Before the TagsLibrary_SetCoverArtFromFile() function.
« Last Edit: 5 Dec '17 - 17:11 by 3delite »

Steve Grant

  • Posts: 152
Re: Tags Library
« Reply #412 on: 6 Dec '17 - 10:46 »
Thank you for your continued help. Because of the code you wrote above it made me go and look at TagsLibrary Defs.Pas. I found that the VB6 function definition is not correct for AddCoverArt. Here is a before and after:

Code: [Select]
Before:

Public Declare Function TagsLibrary_SetCoverArtFromFile Lib "TagsLib.dll" _
    (ByVal Tags As Long, ByVal TagType As TTagType, ByVal index As Long, ByVal _
    FileName As Long, ByRef CoverArt As TCoverArtData) As Long

Public Declare Function TagsLibrary_AddCoverArt Lib "TagsLib.dll" (ByVal _
    Tags As Long, ByVal TagType As TTagType, ByVal CoverArt_Name As Long, ByVal _
    CoverArt_Data As Long, ByVal CoverArt_DataSize As Int64, ByVal _
    CoverArt_Description As Long, ByVal CoverArt_CoverType As Long, ByVal _
    CoverArt_MIMEType As Long, ByVal CoverArt_PictureFormat As _
    TTagPictureFormat, ByVal CoverArt_Width As Long, ByVal CoverArt_Height As _
    Long, ByVal CoverArt_ColorDepth As Long, ByVal CoverArt_NoOfColors As Long, _
    ByVal CoverArt_ID3v2TextEncoding As Long, ByVal CoverArt_Index As Long) As _
    Long

After:

Public Declare Function TagsLibrary_SetCoverArtFromFile Lib "TagsLib.dll" _
    (ByVal Tags As Long, ByVal TagType As TTagType, ByVal Index As Long, ByVal _
    FileName As Long, ByVal CoverArt As Any) As Long

Public Declare Function TagsLibrary_AddCoverArt Lib "TagsLib.dll" (ByVal _
    Tags As Long, ByVal TagType As TTagType, ByVal CoverArt As Any) As Long

What happens now is I get a 'Bad DLL call convention' error on  the AddCoverArt line, then the IDE crashes.
I think I have tried every permutation of CoverArt:

ByVal CoverArt as Long: Called with varptr(Coverart)
ByRef CoverArt as Long: Called with varptr(Coverart)
ByVal CoverArt as Any: Called with varptr(Coverart)
ByRef CoverArt as Any: Called with Coverart

My current code:

Code: [Select]
GetTags Trk.FullPath '//Gives lTags a value
                CoverArt.Name = StrPtr("Album Art")
                CoverArt.CoverType = 3 '//* ID3v2 cover type (3: front cover)
                CoverArt.MIMEType = StrPtr("image/jpeg")
                CoverArt.Description = StrPtr("")
                CoverArt.Width = ScaleX(ImageStart.Picture.Width, vbTwips, vbPixels)
                CoverArt.Height = ScaleY(ImageStart.Picture.Height, vbTwips, vbPixels)
                CoverArt.ColorDepth = 24
                CoverArt.NoOfColors = 0
                CoverArt.PictureFormat = tpfJPEG
                CoverArt.Data = 0 '; //PictureStream.Memory;
                CoverArt.DataSize.LowPart = 0 '//PictureStream.Size;
                CoverArt.DataSize.HighPart = 0 '//PictureStream.Size;
                Index = TagsLibrary_AddCoverArt(lTags, ttAutomatic, CoverArt)
                If Not TagsLibrary_SetCoverArtFromFile(lTags, ttAutomatic, Index, StrPtr(PicFileName), CoverArt) Then
                    MsgBox "Error while adding cover art: " & PicFileName, vbExclamation
                End If

EWeiss

  • Posts: 355
Re: Tags Library
« Reply #413 on: 6 Dec '17 - 15:27 »
that should work
but no the same Problem

that is correctly
Code: [Select]
Public Declare Function TagsLibrary_AddCoverArt Lib "TagsLib.dll" (ByVal Tags As Long, ByVal TagType As TTagType, ByRef CoverArt As TCoverArtData) As Long
Code: [Select]
Private Sub cmdAddCoverart_Click()

    If Not Tags Is Nothing Then
        comdlgOpen.DialogTitle = "Select a File..."
        comdlgOpen.CancelError = False
        comdlgOpen.Flags = cdlOFNExplorer Or cdlOFNHideReadOnly
        comdlgOpen.Filter = "Picture files (*.jpg*,*.bmp*)|*.jpg*;*.bmp*"

        comdlgOpen.ShowOpen
        If comdlgOpen.FileName <> "" Then
            Image1.Picture = LoadPicture(comdlgOpen.FileName)

            Tags.CoverArtName = StrPtr("Album Art")
            Tags.CoverArtData = 0 'not working without stream
            Tags.CoverArtDataSize.LowPart = 0 'same here
            Tags.CoverArtDescription = StrPtr("")
            Tags.CoverArtCoverType = 3
            Tags.CoverArtMIMEType = StrPtr("image/jpeg")
            Tags.CoverArtPictureFormat = tpfJPEG
            Tags.CoverArtWidth = Image1.width / 15
            Tags.CoverArtHeight = Image1.height / 15
            Tags.CoverArtColorDepth = 24
            Tags.CoverArtNoOfColors = 0
            Call Tags.AddCoverArt(ttAutomatic)
        End If
    End If

End Sub

Code: [Select]
Public Function AddCoverArt(ByVal TagType As TTagType) As Long

Dim CoverArt As TCoverArtData

    CoverArt.Name = CoverArtName
    CoverArt.Data = CoverArtData
    CoverArt.DataSize = CoverArtDataSize
    CoverArt.Description = CoverArtDescription
    CoverArt.CoverType = CoverArtCoverType
    CoverArt.MIMEType = CoverArtMIMEType
    CoverArt.PictureFormat = CoverArtPictureFormat
    CoverArt.width = CoverArtWidth
    CoverArt.height = CoverArtHeight
    CoverArt.ColorDepth = CoverArtColorDepth
    CoverArt.NoOfColors = CoverArtNoOfColors
    CoverArt.ID3v2TextEncoding = CoverArtID3v2TextEncoding

    AddCoverArt = TagsLibrary_AddCoverArt(LngTags, TagType, CoverArt)
   
End Function

LngTags = hLib
TagType = ttAutomatic
CoverArt = record

Quote
'Bad DLL call convention'

greets
« Last Edit: 6 Dec '17 - 16:25 by EWeiss »

Steve Grant

  • Posts: 152
Re: Tags Library
« Reply #414 on: 6 Dec '17 - 19:41 »
Hi Emil,

I have tried your test program without any modification and it still gives a Bad DLL Calling convention error on this line;

 AddCoverArt = TagsLibrary_AddCoverArt(LngTags, TagType, CoverArt)

I am using the most up to date version of TagsLib.dll 1.0.64.107.

EWeiss

  • Posts: 355
Re: Tags Library
« Reply #415 on: 7 Dec '17 - 03:05 »
Quote
I have tried your test program without any modification and it still gives a Bad DLL Calling convention error on this line;
yes that is clear ;)

i have upload the file so 3delite can debug it..
i think some is wrong on the Delphi side. (dependent Delphi vs. VB6)

if using
CoverArtData = 0 and CoverArtDataSize = 0 that should not Crash the application.

Steve i can fix it but i have not the source so i can no more do. Sorry
3delite on the Delphi side if your want Supported VB6 you should not use Datatypes like Int64 use Integer only.
your use Packed for Record is that needed?

i am use in Delphi a record like this..
Delphi
Code: [Select]
  PBASSVIS_EXEC = ^TBASSVIS_EXEC;
  TBASSVIS_EXEC = record
    PluginFile            : PAnsiChar;// Plugin Datei für Sonique, Winamp, BassBox
    AMP_UseOwnW1          : DWORD;    // Flag für Winamp (ownHDC)
    AMP_UseOwnW2          : DWORD;    // Flag für Winamp (ownHDCW2)
    AMP_Moduleindex       : DWORD;    // Modul-index für Winamp
    AMP_UseFakeWindow     : BOOL;     // Create a own Window for WindowMessages
    SON_ParentHandle      : HWND;     // ParentHandle für Sonique
    SON_ConfigFile        : PAnsiChar;// Dateiname der Konfiguration für Sonique
    SON_UseOpenGL         : BOOL;
    SON_ViewportWidth     : integer;  // Stretch Width
    SON_ViewportHeight    : integer;  // Stretch Height
    SON_ShowPrgBar        : BOOL;     // Progressbar anzeigen
    SON_ShowFPS           : BOOL;     // Frames pro Sekunde anzeigen
    SON_UseCover          : BOOL;     // Cover anzeigen
    WMP_PluginIndex       : integer;  // Pluginindex für WMP;
    WMP_PresetIndex       : integer;  // Presetindex für WMP;
    WMP_ParentHandle      : HWND;     // ContainerVisHandle für WMP;
    //WMP_CoInit            : TBASSVIS_CoInit;
    BB_ParentHandle       : HWND;     // Parent Windowhandle
    BB_ShowFPS            : BOOL;     // Frames pro Sekunde anzeigen
    BB_ShowPrgBar         : BOOL;     // Progressbar anzeigen
    AIMP_PaintHandle      : HDC;      // Painthandle für Aimp2
    Width, Height         : integer;  // Fensterhöhe und Breite
    Left, Top             : integer;  // Left und Top;
  end;

VB6
Code: [Select]
  ' Definition der Typen für die variablen Parameter bei Create bzw. Execute
  Public TYPE BASSVIS_EXEC
    Pluginfile            AS STRING  ' Dateiname des Plugins für Sonique und Winamp
    AMP_UseOwnW1          AS LONG    ' Flag für Winamp False =(Render Winamp5 im eigenen Window) 0=aus,1=an
    AMP_UseOwnW2          AS LONG    ' Flag für Winamp False =(Render Winamp2 im eigenen Window) 0=aus,1=an
    AMP_Moduleindex       AS LONG    ' Modul-index für Winamp
    AMP_UseFakeWindow     AS LONG    ' Create a own Window for WindowMessages  'BOOL
    SON_ParentHandle      AS LONG    ' Parent Windowhandle
    SON_ConfigFile        AS STRING  ' Dateiname der Konfiguration für Sonique
    SON_UseOpenGL         AS LONG    ' Use OpenGL instead of GDI               'BOOL
    SON_ViewportWidth     AS LONG    ' Stretch Width
    SON_ViewportHeight    AS LONG    ' Stretch Height
    SON_ShowPrgBar        AS LONG    ' Progressbar anzeigen                    'BOOL
    SON_ShowFPS           AS LONG    ' Frames pro Sekunde anzeigen             'BOOL
    SON_UseCover          AS LONG    ' Cover anzeigen                          'BOOL
    WMP_PluginIndex       AS LONG    ' Pluginindex für WMP;
    WMP_PresetIndex       AS LONG    ' Presetindex für WMP
    WMP_ParentHandle      AS LONG    ' ContainerVisHandle für WMP
    BB_ParentHandle       AS LONG    ' Parent Windowhandle
    BB_ShowFPS            AS LONG    ' Frames pro Sekunde anzeigen             'BOOL
    BB_ShowPrgBar         AS LONG    ' Progressbar anzeigen                    'BOOL
    AIMP_ParentHandle     AS LONG    ' Painthandle für Aimp2
    Width                 AS LONG    ' Fensterbreite
    Height                AS LONG    ' Fensterhöhe
    Left                  AS LONG    ' Top
    top                   AS LONG    ' Left
  END TYPE     
and have no Problem send and retrieve Data over VB6 from it.

Delphi
Code: [Select]
procedure BASSVIS_ExecutePlugin(Param: PBASSVIS_EXEC;
    var Base: TBASSVIS_PARAM
); stdcall; external dllfile;
VB6
Code: [Select]
Public DECLARE SUB BASSVIS_ExecutePlugin LIB "bass_vis.dll" ( _
    BYREF param AS BASSVIS_EXEC, _
    BYREF Base AS BASSVIS_PARAM _
)         

greets
« Last Edit: 7 Dec '17 - 03:29 by EWeiss »

Steve Grant

  • Posts: 152
Re: Tags Library
« Reply #416 on: 7 Dec '17 - 09:12 »
Thanks for trying Emil, I really appreciate it. I don't want to abandon TagsLib as it is such a good library, but I do need to be able to write images to the metadata.

Greets

EWeiss

  • Posts: 355
Re: Tags Library
« Reply #417 on: 7 Dec '17 - 09:52 »
Thanks for trying Emil, I really appreciate it. I don't want to abandon TagsLib as it is such a good library, but I do need to be able to write images to the metadata.

Greets

for the data you can do this..
load a tmp Image to a invisible Picturebox then create a Bitmap from Image Handle.
copy this to clsTags..
Code: [Select]
Public Function GetBitmapData(Picture As PictureBox) As String

    Dim BitmapData As String
    Dim BitmapHeight As Long
    Dim strBitmapHeight As String
    Dim BitmapWidth As Long
    Dim strBitmapWidth As String
    Dim BytesPerPixel As Integer
    Dim strBytesPerPixel As String
    Dim BitmapBytes As Long
   
    Dim BMP As BITMAP
   
    GetObject Picture.Image.Handle, Len(BMP), BMP
    BitmapHeight = BMP.bmHeight
    BitmapWidth = BMP.bmWidth
    BytesPerPixel = (BMP.bmBitsPixel \ 8)
    BitmapBytes = BitmapHeight * BitmapWidth * BytesPerPixel
   
    BitmapData = Space$(BitmapBytes)
    GetBitmapBits Picture.Image.Handle, BitmapBytes, ByVal BitmapData
   
    strBitmapHeight = Space$(4)
    CopyMemory ByVal strBitmapHeight, BitmapHeight, 4
   
    strBitmapWidth = Space$(4)
    CopyMemory ByVal strBitmapWidth, BitmapWidth, 4
   
    strBytesPerPixel = Space$(2)
    CopyMemory ByVal strBytesPerPixel, BytesPerPixel, 2
   
    GetBitmapData = strBitmapHeight & strBitmapWidth & strBytesPerPixel & BitmapData
   
End Function
   
create a button in frmMain
Code: [Select]
Private Sub cmdAddCoverart_Click()

Dim Data As String

Dim BitmapData As String
Dim strBitmapHeight As String
Dim strBitmapWidth As String
Dim strBytesPerPixel As String

Dim BitmapWidth As Long
Dim BitmapHeight As Long
Dim BitmapBytes As Long
Dim BytesPerPixel As Integer

    If Not Tags Is Nothing Then
        comdlgOpen.DialogTitle = "Select a File..."
        comdlgOpen.CancelError = False
        comdlgOpen.Flags = cdlOFNExplorer Or cdlOFNHideReadOnly
        comdlgOpen.Filter = "Picture files (*.jpg*,*.bmp*)|*.jpg*;*.bmp*"

        comdlgOpen.ShowOpen
        If comdlgOpen.FileName <> "" Then
            tmpPic.Picture = LoadPicture(comdlgOpen.FileName)
            Data = PicFromMem.GetBitmapData(tmpPic)
           
            strBitmapHeight = Left$(Data, 4)
            strBitmapWidth = Mid$(Data, 5, 4)
            strBytesPerPixel = Mid$(Data, 9, 2)
            BitmapData = Mid$(Data, 11)
           
            CopyMemory BitmapHeight, ByVal strBitmapHeight, 4
            CopyMemory BitmapWidth, ByVal strBitmapWidth, 4
            CopyMemory BytesPerPixel, ByVal strBytesPerPixel, 2
           
            BitmapBytes = BitmapHeight * BitmapWidth * BytesPerPixel
           
            Tags.CoverArtName = StrPtr("Album Art")
            Tags.CoverArtData = StrPtr(BitmapData)
            Tags.CoverArtDataSize.LowPart = BitmapBytes
            Tags.CoverArtDescription = StrPtr("")
            Tags.CoverArtCoverType = 3
            Tags.CoverArtMIMEType = StrPtr("image/jpeg")
            Tags.CoverArtPictureFormat = tpfJPEG
            Tags.CoverArtWidth = BitmapWidth
            Tags.CoverArtHeight = BitmapHeight
            Tags.CoverArtColorDepth = 24
            Tags.CoverArtNoOfColors = 0
            Call Tags.AddCoverArt(ttAutomatic)
        End If
       Set tmpPic = Nothing
    End If

End Sub

i have also create a String from the Bitmap Data which can use for StrPtr..
no idea if that work later after the Function not Fails.

greets




3delite

  • Posts: 916
Re: Tags Library
« Reply #418 on: 7 Dec '17 - 10:32 »
Debugging the test app. EWeiss posted, the TCoverArtData is not properly received. Here's a snapshot:



It seems like the problem is after 'Description', so either 'Description' is not properly defined (that I don't understand as it's a simple 32 bit value), or not aligned? Also the first 'Name' value is probably wrong. The struct is a packed record in Delphi, so that should be fine. For me the definition of the struct in VB6 looks ok, but I'm not sure about the function definition. The TCoverArtData needs to be passed by value, not by reference:

Code: [Select]
Public Declare Function TagsLibrary_SetCoverArt Lib "TagsLib.dll" (ByVal Tags As Long, ByVal TagType As TTagType, ByVal Index As Long, ByRef CoverArt As TCoverArtData) As Long

Delphi definition:

Code: [Select]
function TagsLibrary_SetCoverArt(Tags: TTags; TagType: TagsLibrary.TTagType; Index: Integer; CoverArt: TCoverArtData): LongBool; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; export;

Could this be the problem?

EWeiss

  • Posts: 355
Re: Tags Library
« Reply #419 on: 7 Dec '17 - 11:11 »
no!

The Trouble is your record seems that is not the same.

Code: [Select]
Public Type TCoverArtData
    Name              As Long               '* LPWSTRtoBSTR(Name)
    Data              As Long               '* VarPtr(Data)
    DataSize          As Int64              '* DataSize.LowPart
    Description       As Long               '* LPWSTRtoBSTR(Description)
    CoverType         As Long
    MIMEType          As Long               '* LPWSTRtoBSTR(MIMEType)
    PictureFormat     As TTagPictureFormat
    width             As Long
    height            As Long
    ColorDepth        As Long
    NoOfColors        As Long
    ID3v2TextEncoding As Long
    Index             As Long
End Type

that is what i send...
Code: [Select]
            Tags.CoverArtName = StrPtr("Album Art")
            Tags.CoverArtData = StrPtr(BitmapData)
            Tags.CoverArtDataSize.LowPart = BitmapBytes
            Tags.CoverArtDescription = StrPtr("")
            Tags.CoverArtCoverType = 3
            Tags.CoverArtMIMEType = StrPtr("image/jpeg")
            Tags.CoverArtPictureFormat = tpfJPEG
            Tags.CoverArtWidth = BitmapWidth
            Tags.CoverArtHeight = BitmapHeight
            Tags.CoverArtColorDepth = 24
            Tags.CoverArtNoOfColors = 0
            Call Tags.AddCoverArt(ttAutomatic)

and now check your shot!

Description as example i am send nothing and you read "Album Art"
any is wrong here..

i am send Width = 400, Height = 384 and that is also wrong by you.
Quote
The struct is a packed record in Delphi, so that should be fine.
yes for Delphi not for VB6.

please test the File without packed Record.
see http://www.un4seen.com/forum/?topic=15754.msg114246#msg114246

greets
« Last Edit: 7 Dec '17 - 11:42 by EWeiss »

3delite

  • Posts: 916
Re: Tags Library
« Reply #420 on: 7 Dec '17 - 11:36 »
It does not matter what you send if you send the record wrongly. It is needed by value, not by reference. Please try to send it be value and check if it works.

EWeiss

  • Posts: 355
Re: Tags Library
« Reply #421 on: 7 Dec '17 - 11:45 »
It does not matter what you send if you send the record wrongly. It is needed by value, not by reference. Please try to send it be value and check if it works.

https://msdn.microsoft.com/de-de/vba/language-reference-vba/articles/user-defined-type-may-not-be-passed-byval

you can only use ByRef not ByVal
ok is enough for me...

greets
« Last Edit: 7 Dec '17 - 12:02 by EWeiss »

3delite

  • Posts: 916
Re: Tags Library
« Reply #422 on: 7 Dec '17 - 12:13 »
Ok, then it seems VB6 is not supported by Tags Library.

EWeiss

  • Posts: 355
Re: Tags Library
« Reply #423 on: 7 Dec '17 - 12:16 »
Ok, then it seems VB6 is not supported by Tags Library.

they make it easy..
ok no Problem for me.

but i send all my records from vb6 with ByRef how why it's work by me and not by you. that is the question.
See!
Code: [Select]
Public DECLARE SUB BASSVIS_ExecutePlugin LIB "bass_vis.dll" ( _
    BYREF param AS BASSVIS_EXEC, _
    BYREF Base AS BASSVIS_PARAM _

have a nice day

greets
« Last Edit: 7 Dec '17 - 17:59 by EWeiss »

3delite

  • Posts: 916
Re: Tags Library
« Reply #424 on: 8 Dec '17 - 10:44 »
Added a new function TagsLibrary_AddCoverArtFromFile() which expects a reference for TCoverArtData. Hopefully this will now work for VB6.

https://www.3delite.hu/Tags%20Library/Download/Tags%20Library.zip

This is the latest version, there are a couple of updates included that are not yet released.

A new VB6 header is included, please let me know if there are still problems.

EWeiss: When passing a variable by reference, the pointer to the variable is sent. When passing a variable by value, the variable's value is copied to the stack (depends on the calling convention, might be a register too) for the function that expects it. If you pass a reference (pointer) to a struct only the pointer is copied to the stack, if you send the struct by value, the whole structure is copied to the stack.
« Last Edit: 8 Dec '17 - 10:49 by 3delite »