Author Topic: VB6 Ide crash using BASS_StreamUserCreate  (Read 227 times)

jpf

  • Posts: 51
VB6 Ide crash using BASS_StreamUserCreate
« on: 3 Feb '18 - 19:01 »
I started writing a module to move/rename a file while it's being played by Bass. I thought of using BASS_StreamUserCreate. If there are better workarounds I'd like to learn them.

This is the module so far (no moving/renaming so far, just playing):
Code: [Select]
Option Explicit

Public Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (ByVal Destination As Long, Source As Any, ByVal Length As Long)

' User file stream callback functions (BASS_FILEPROCS)
Public Sub mFileClose(ByVal User As Long)
    Close User
End Sub

Public Function mFileLen(ByVal User As Long) As Currency ' ???
    mFileLen = LOF(User) / 10000#
End Function

Public Function mFileRead(ByVal Buffer As Long, ByVal Length As Long, ByVal User As Long) As Long
    Dim mBuff() As Byte
   
    If Length > LOF(User) - Loc(User) Then
        Length = LOF(User) - Loc(User)
    End If
   
    ReDim mBuff(Length - 1)
    mBuff = InputB(Length, User)
   
    CopyMemory Buffer, mBuff(0), Length
    mFileRead = Length
End Function

Public Function mFileSeek(ByVal Offset As Long, ByVal OffsetHigh As Long, ByVal User As Long) As Long
    On Error Resume Next
    Seek User, Offset
    If Err = 0 Then mFileSeek = BASSTRUE
End Function

Private Function GetAddr(ByVal Addr As Long) As Long
    'packing AddressOf
    GetAddr = Addr
End Function

Public Function BASS_StreamUserCreate(ByVal FileName As String, ByVal Flags As Long) As Long
    Dim nFile As Long
    Dim BASS_FileProcs(3) As Long
   
    On Error Resume Next
    nFile = FreeFile
    If Err <> 0 Then Exit Function
    Open FileName For Binary Access Read Shared As nFile
    If Err <> 0 Then Exit Function

    'typedef struct {
    '    FILECLOSEPROC *close;
    '    FILELENPROC *length;
    '    FILEREADPROC *read;
    '    FILESEEKPROC *seek;
    '} BASS_FILEPROCS;
    BASS_FileProcs(0) = GetAddr(AddressOf mFileClose)
    BASS_FileProcs(1) = GetAddr(AddressOf mFileLen)
    BASS_FileProcs(2) = GetAddr(AddressOf mFileRead)
    BASS_FileProcs(3) = GetAddr(AddressOf mFileSeek)

    'HSTREAM BASS_StreamCreateFileUser(
    '    DWORD system,
    '    DWORD flags,
    '    BASS_FILEPROCS *procs,
    '    void *user
    ');
    BASS_StreamUserCreate = BASS_StreamCreateFileUser(STREAMFILE_BUFFER, Flags, VarPtr(BASS_FileProcs(0)), nFile)

End Function

For testing I used a slightly modified vb\BASStest example from the bass 2.4.13 package.

The modification is to use BASS_StreamUserCreate from my module instead of BASS_StreamCreateFile in the sub cmdStreamAdd_Click():
Code: [Select]
Private Sub cmdStreamAdd_Click()
   ...
    'StreamHandle = BASS_StreamCreateFile(BASSFALSE, StrPtr(DLG.FileName), 0, 0, 0)
    StreamHandle = BASS_StreamUserCreate(DLG.FileName, 0)
   ...
End Sub

The code seems to work well in the Ide. It does until I close the form. Then the Ide crashes with "Access violation" error on VB6.exe module.

This doesn't happen if I close the window without having Add'd any files to the playlist.

If I compile the application and run it, it works as expected, and on closing the form it exits without error.

Any hints to avoid the Ide crash?

Guest

  • Guest
Re: VB6 Ide crash using BASS_StreamUserCreate
« Reply #1 on: 3 Feb '18 - 20:28 »
if your use opendialog before?
if so then i think the Trouble come from CoInitialize, CoUninitialize.

open the file without opendialog control..
test it with OpenDialog over Win32API instead.

jpf

  • Posts: 51
Re: VB6 Ide crash using BASS_StreamUserCreate
« Reply #2 on: 4 Feb '18 - 18:17 »
if your use opendialog before?
if so then i think the Trouble come from CoInitialize, CoUninitialize.

open the file without opendialog control..
test it with OpenDialog over Win32API instead.

Thanks for your hint.

I guess you mean test it using "GetOpenFileNameA" from "comdlg32.dll" instead of the comdlg32.ocx control.

Well, I followed your advice and did it. To make sure that the ocx control won't be loaded anyway I deleted the control from the form and commented out the lines referencing it.

Unfortunately the crash still happens just like before.

I went a step further and removed the references to comdlg32.dll as well, and hardcoded a filename to make up for the missing file dialogue:
Code: [Select]
Private Sub cmdStreamAdd_Click()
    ...
    StreamHandle = BASS_StreamUserCreate("E:\Audio\A revisar\Mp3\Chorus - Your Zowie Face.mp3", 0)
    ...
End Sub
No change; the crash still happens just like before.

However I'd like to learn what would be the mechanism by which CoInitialize and CoUninitialize together with BASS_StreamUserCreate & related stuff would lead to the crash. Will you please give me a detailed description of the process? Mind that I'm mostly ignorant of the internals of the VB6 Ide (and the VB6 runtime as well).
Maybe this would help me grasp what's the problem here.

Thanks !

Guest

  • Guest
Re: VB6 Ide crash using BASS_StreamUserCreate
« Reply #3 on: 4 Feb '18 - 19:07 »
deaktivate Bass_Free for testing before Close your File.

Guest

  • Guest
Re: VB6 Ide crash using BASS_StreamUserCreate
« Reply #4 on: 4 Feb '18 - 19:11 »
StrPtr(DLG.FileName) ?? missing on  BASS_StreamUserCreate
or is not needed.

Guest

  • Guest
Re: VB6 Ide crash using BASS_StreamUserCreate
« Reply #5 on: 4 Feb '18 - 19:19 »
and not found BASS_StreamUserCreate but BASS_StreamCreateFileUser

Ian @ un4seen

  • Administrator
  • Posts: 20764
Re: VB6 Ide crash using BASS_StreamUserCreate
« Reply #6 on: 5 Feb '18 - 13:43 »
VB6 doesn't really support multi-threading, so using VB6 functions in a callback function can cause problems. Can you try using the Win32 file functions instead, eg. CreateFile and ReadFile?

jpf

  • Posts: 51
Re: VB6 Ide crash using BASS_StreamUserCreate
« Reply #7 on: 5 Feb '18 - 15:21 »
VB6 doesn't really support multi-threading, so using VB6 functions in a callback function can cause problems. Can you try using the Win32 file functions instead, eg. CreateFile and ReadFile?

Thanks, Ian, I'll try this.

and not found BASS_StreamUserCreate but BASS_StreamCreateFileUser
It's defined in my module.

StrPtr(DLG.FileName) ?? missing on  BASS_StreamUserCreate
or is not needed.
My function accepts "ByVal FileName As String" as parameter.

deaktivate Bass_Free for testing before Close your File.
But Ian's example in the help file said to close it inside the FILECLOSEPROC (my module is just a translation of Ian's example). I'll try Ian's suggestion first, because yours will make my module useless: if I free bass at the end of each playing file all the other files playing will be killed as well.

Anyway I'll keep your basic idea in mind. Maybe running the "Close User" statement asyncronously outside the FILECLOSEPROC callback, which probably runs in a different thread as the Open statement, can make a difference. I should then do a PostMessage to the form, subclass it, and close the files inside the WinProc callback, which supposedly is in the same thread as the Open statement. However this still leaves the LOC(), EOF() and Seek() file functions inside callback procedures, so it's not completelly unsyncing the file access interface. Ian's suggestion is way cleaner, so I'll try it first.