[futurebasic] Re: [FB] Mad file disease

Message: < previous - next > : Reply : Subscribe : Cleanse
Home   : April 2002 : Group Archive : Group : All Groups

From: Alain Pastor <apastor@...>
Date: Mon, 22 Apr 2002 10:06:27 +0200
Robert Purves wrote:
> 
> >I've got a local fn that receives a data handle and a pointer to an
> >FSSpec structure transmitted via an Apple Event.
> >The FSSpec structure describes a file that the function will rename
> >then move to another folder. Then the function stores the data in a
> >new created file with the same original name as the incoming file and
> >at the same original location. Finally, the new created file is opened
> >in an appropriate application.
> >I came to write the function below that seems to do the job except for
> >the last part: the old renamed file is launched instead of the new
> >one. How can I fix that bug?
> 
> Without seeing more of your code, I cannot answer the question.
> A safer alternative to your method would be along these lines:

I didn't think the other parts were relevant since they seem to work
as expected, but perhaps the fault is in the launching mechanism.
> 
> 1. Create the "Archives" folder if it does not already exist.
> 
> 2. Create a file inside "Archives". The file's name is
>        Left$( originalFile.name, 25 ) + " (old)"
> 3. Write your data to that file
>    copy all resources from the original to that file
>    set the creator and type of that file.
> 
> {up to now, the original file is completely untouched, so that if anything
> goes wrong you have done no damage to it, and there is nothing to repair}
> 
> 6. If no error has occurred in steps 2-3, call FSpExchangeFiles.
> 
OK, this is a good idea. My first quick attempt gives the following:

Clear Local
'~'8
Local Fn DoAEModeSave( dataH As Handle, originalFile As .FSSpec )
'~'9
  Dim As Long     err, @ dirID
  Dim As FSSpec   archiveFolder, newCreatedFile
  Dim As Str63    fldName, newName
  Dim pb.128

  newName = Left$( originalFile.name, 25 ) + " (old)"
  fldName = "Archive"
  err = Fn FSMakeFSSpec( originalFile.vRefNum, originalFile.parID,
fldName, archiveFolder )
  Long If err
    Fn FSpDirCreate( archiveFolder, _smCurrentScript, dirID )
  Xelse
    pb.ioVRefNum% = originalFile.vRefNum
    pb.ioNamePtr& = @fldName
    pb.ioDirID&   = originalFile.parID
    err = Fn PBGetCatInfoSync( pb )
    dirID = pb.ioDirID&
  End If
  Long If err = _noErr
    err = Fn FSMakeFSSpec( originalFile.vRefNum, dirID, newName,
newCreatedFile )
    Fn WriteHandleToFile( dataH, newCreatedFile  )
    Fn TransferResources( originalFile, newCreatedFile )
    err = Fn FSpExchangeFiles( #originalFile, newCreatedFile )
    If err = _noErr Then Fn OpenFSFileWithApplication( newCreatedFile )
  End If
End Fn

It seems to work exactly the same as the previous function, giving the
same bizarre result.
The rest of the code involved three functions that read like so:

Local Mode
'~'8
Local Fn WriteHandleToFile( theH  As Handle, fSpec As .FSSpec )
'~'9
  Dim As    id, err, state
  Dim As FSSpec spec

  spec = fSpec
  On Error End
  id = Fn FindUnusedFileRef
  Open "OD", id, @spec
  state = Fn HGetState( theH )
  HLock( theH )
  Write File id,[theH] +1 ,Fn GetHandleSize( theH ) - 2
  Close id
  HSetState( theH, state )

  Long If (Error And 255) <> _noErr
    err = 1
    Error = _noErr
  End If
  On Error Return

End Fn = err


Clear Local Mode
'~'8
Local Fn TransferResources( srcSpec As .FSSpec, destSpec As .FSSpec )
'~'9
  Dim As Int       tCount, idxT, rCount, idxR
  Dim As Int       oldWD, oldRes, srcRes, destRes,err
  Dim As FSSpec    dstSpec
  Dim As Hndl      resH 
  Dim As Int     @ rID
  Dim As ResType @ rType
  Dim As Str31     rName

  oldRes = Fn CurResFile
  srcRes = Fn FSpOpenResFile( #srcSpec, _fsRdPerm )
  If srcRes = -1 Or Fn ResError Then Exit Fn
  destRes = Fn FSpOpenResFile( #dstSpec, _fsWrPerm )
  Long If destRes = -1 Or Fn ResError != _noErr
    FSpCreateResFile(#dstSpec,_"FB^e",_"TEXT",_smSystemScript)
    If Fn ResError != _noErr Then Exit Fn
    destRes = Fn FSpOpenResFile( #dstSpec, _fsWrPerm )
    Long If destRes = -1 Or Fn ResError != _noErr
      If srcRes  != oldRes Then CloseResFile( srcRes )
      Exit Fn
    End If
  End If
  UseResFile( srcRes )
  tCount = Fn Count1Types
  Long If tCount
    For idxT = 1 To tCount
      If Fn CurResFile != srcRes Then UseResFile( srcRes )
      Get1IndType( rType, idxT )
      rCount = Fn Count1Resources( rType )
      If rCount = 0 Then Exit For
      For idxR = 1 To rCount
        If Fn CurResFile != srcRes Then UseResFile( srcRes )
        resH = Fn Get1IndResource( rType, idxR )
        Long If resH
          GetResInfo( resH, rID, rType, rName )
          DetachResource( resH )
          UseResFile( destRes )
          AddResource( resH, rType, rID, rName )
          Long If Fn ResError = _noErr
            WriteResource( resH )
            ReleaseResource( resH)
          Xelse
            DisposeHandle( resH )
          End If
        End If
      Next
    Next
    UpdateResFile(destRes)
  End If
  If destRes != oldRes Then CloseResFile( destRes )
  If srcRes  != oldRes Then CloseResFile( srcRes )
  UseResFile( oldRes )

End Fn


Clear Local Mode
'~'8
Local Fn OpenFSFileWithApplication( fSpec As .FSSpec )' adapted from
Herbie's work
'~'9
  Dim As OSErr    err
  Dim As OSType @ creator
  Dim As AEDesc   addrDesc,theAE,fList

  creator = _"MACS"
  err = Fn AECreateDesc( _"sign", @creator, Sizeof(OSType), addrDesc )
  IF err Then Exit "Dispose"
  err = Fn AECreateAppleEvent( _"aevt", _"odoc", addrDesc,¬
                          _kAutoGenerateReturnID, _kAnyTransactionID,
theAE )
  IF err Then Exit "Dispose"
  err = Fn AEcreateList(_nil,0,_false,fList)
  IF err Then Exit "Dispose"
  err = Fn AEPutPtr( fList, 1, _"fss ", fSpec, Sizeof( FSSpec ) )
  IF err Then Exit "Dispose"
  err = Fn AEPutKeyDesc( theAE, _"----", fList)
  IF err Then Exit "Dispose"
  err = Fn AESend( theAE, addrDesc, _kAEQueueReply_kAECanInteract,¬
                          _kAENormalPriority, _kAEDefaultTimeout,
_nil, _nil )
"Dispose"
  If addrDesc.dataHandle Then err = Fn AEDisposeDesc( addrDesc )
  If theAE.dataHandle    Then err = Fn AEDisposeDesc( theAE )
  If fList.dataHandle    Then err = Fn AEDisposeDesc( fList )

End Fn

I don't see in the above functions where is the problem. I thought it
might have been something to see with the opening of the file and I
tried to use the PARENTID statement after FN WriteHandleToFile to no avail.

> Your "don't know why" comment is easily explained:
> 
> >// rename the original file
> >    err  = Fn FSpRename( #originalFile, newName )
> >    Long If err = _noErr
> >// don't know why I have to do that for the FSpCatMove to work
> >      originalFile.name = newName
> 
> The originalFile FSSpec was made invalid by FSpRename; it no longer
> indicates any existing file.
> 
> >// move the renamed file to the archive folder
> >      err = Fn FSpCatMove( #originalFile, archiveFolder )
> 
Thanks, I would have expected the function to update the FSSpec in
that case.

-- 
Cheers,

Alain
------------------------------------------------------
                 Program different

                      E = FB^3

FutureBASIC^3 in Europe:  http://euro.futurebasic.com/
------------------------------------------------------