Announcement

Collapse
No announcement yet.

Is DWORD FILL only used with DLL's?

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Mike Doty
    replied
    This works correctly
    Posted in case someone else has trouble using DWORD FILL
    DWORD FILL can be removed when complete and the size will be the same.
    Note 3 rules on page 526 of the manual
    Code:
    #COMPILE EXE
    #DIM ALL
    TYPE MyType 'DWORD FILL 
    '                               Start Length  Total
      A AS INTEGER                ' 1     2       2
      B AS STRING * 7             ' 3     7       9
      C AS STRING * 20            ' 10    20      29
      D AS STRING * 20            ' 30,   20      49
      E AS STRING * 10            ' 50    10      59
      F AS STRING * 11            ' 60    11      70
      DUMMY1 AS STRING * 2        ' 71    2       72   make divisible by 4
                                  '
      G AS LONG                   ' 73    4       76
      H AS STRING * 30            ' 77    30      106
      I AS STRING * 30            ' 107   30      136
      J AS STRING * 20            ' 137   20      156
      K AS STRING * 2             ' 157   2       158
      L AS STRING * 1             ' 159   1       159
      M AS STRING * 7             ' 160   7       166
      DUMMY2 AS STRING * 2        ' 167   2       168  make divisible by 4
                                  '
      N AS INTEGER                ' 169   2       170
      DUMMY3 AS STRING * 2        ' 171   2       172  make divisible by 4
     
      O AS LONG                   ' 173   4       176
      P AS LONG                   ' 177   4       180
      Q AS INTEGER                ' 181   2       182
      R AS STRING * 2             ' 183   2       184
      S AS STRING * 3             ' 185   3       187
      T AS STRING * 3             ' 188   3       190
      U AS STRING * 8             ' 191   8       198
      V AS STRING * 4             ' 199   4       202
      DUMMY4 AS STRING * 2        ' 203   2       204
     
      W AS INTEGER                ' 205   2       206
      X AS STRING * 1             ' 207   1       207
      Y AS STRING * 4             ' 208   4       211
    ' No padding needed with DWORD FILL at end of structure
    END TYPE
    FUNCTION PBMAIN() AS LONG
      MSGBOX STR$(SIZEOF(MyType))
    END FUNCTION
    Last edited by Mike Doty; 3 Feb 2008, 05:12 PM. Reason: Missed the need for DUMMY4

    Leave a comment:


  • Michael Mattias
    replied
    1) Is the file access by the length of the new DWORD FILL length (increasing the size on disk from 203 to ?
    The record size is SIZEOF(UDT_var)

    '2) Can just the 203-bytes be accessed and the structure copied to another structure with DWORD FILL?
    If you mean with one assignment statement, no. You'd have to move each member individually.
    '3) Is this structure only 205-bytes?
    See answer to #1
    '4) VB will make this structure 392 bytes with unicode.
    A. So what?

    B. Then you are passing it to your I-O module incorrectly from your VB program.

    MCM

    Leave a comment:


  • Mike Doty
    replied
    'PBIO.BAS
    '1) Is the file access by the length of the new DWORD FILL length (increasing the size on disk from 203 to ?
    '2) Can just the 203-bytes be accessed and the structure copied to another structure with DWORD FILL?
    '3) Is this structure only 205-bytes?
    '4) VB will make this structure 392 bytes with unicode.

    '
    Code:
     
    [FONT=Courier New][SIZE=4]#COMPILE EXE[/SIZE][/FONT]
    [FONT=Courier New][SIZE=4]TYPE ClientType DWORD FILL[/SIZE][/FONT]
    [SIZE=4][FONT=Courier New]'                 'Start  Length[/FONT][/SIZE]
    [SIZE=4][FONT=Courier New]A AS INTEGER      '1           2[/FONT][/SIZE]
    [SIZE=4][FONT=Courier New]B AS STRING * 7   '3           7[/FONT][/SIZE]
    [SIZE=4][FONT=Courier New]C AS STRING * 20  '10         20[/FONT][/SIZE]
    [SIZE=4][FONT=Courier New]D AS STRING * 20  '30         20[/FONT][/SIZE]
    [SIZE=4][FONT=Courier New]E AS STRING * 10  '50         10[/FONT][/SIZE]
    [SIZE=4][FONT=Courier New]F AS STRING * 11  '60         11[/FONT][/SIZE]
    [SIZE=4][FONT=Courier New]G AS LONG         '71          4[/FONT][/SIZE]
    [SIZE=4][FONT=Courier New]H AS STRING * 30  '75         30[/FONT][/SIZE]
    [SIZE=4][FONT=Courier New]I AS STRING * 30  '105        30[/FONT][/SIZE]
    [SIZE=4][FONT=Courier New]J AS STRING * 20  '135        20[/FONT][/SIZE]
    [SIZE=4][FONT=Courier New]K AS STRING * 2   '155         2[/FONT][/SIZE]
    [SIZE=4][FONT=Courier New]L AS STRING * 1   '157         1[/FONT][/SIZE]
    [SIZE=4][FONT=Courier New]M AS STRING * 7   '158         7[/FONT][/SIZE]
    [SIZE=4][FONT=Courier New]N AS INTEGER      '165         2[/FONT][/SIZE]
    [SIZE=4][FONT=Courier New]O AS LONG         '167         4[/FONT][/SIZE]
    [SIZE=4][FONT=Courier New]P AS LONG         '171         4[/FONT][/SIZE]
    [SIZE=4][FONT=Courier New]Q AS INTEGER      '175         2[/FONT][/SIZE]
    [SIZE=4][FONT=Courier New]R AS STRING * 2   '177         2[/FONT][/SIZE]
    [SIZE=4][FONT=Courier New]S AS STRING * 3   '179         3[/FONT][/SIZE]
    [SIZE=4][FONT=Courier New]T AS STRING * 3   '182         3[/FONT][/SIZE]
    [SIZE=4][FONT=Courier New]U AS STRING * 8   '185         8[/FONT][/SIZE]
    [SIZE=4][FONT=Courier New]V AS STRING * 4   '193         4[/FONT][/SIZE]
    [SIZE=4][FONT=Courier New]W AS INTEGER      '197         2[/FONT][/SIZE]
    [SIZE=4][FONT=Courier New]X AS STRING * 1   '199         1[/FONT][/SIZE]
    [SIZE=4][FONT=Courier New]Y AS STRING * 4   '200         4[/FONT][/SIZE]
    [SIZE=4][FONT=Courier New]END TYPE[/FONT][/SIZE]
    [FONT=Courier New][SIZE=4]FUNCTION PBMAIN AS LONG[/SIZE][/FONT]
    [SIZE=4][FONT=Courier New]LOCAL CLIENT AS clienttype[/FONT][/SIZE]
    [SIZE=4][FONT=Courier New]MSGBOX STR$(LEN(CLIENT))      'Total 205 bytes using DWORD FILL[/FONT][/SIZE]
     
    [SIZE=4][FONT=Courier New]END FUNCTION[/FONT][/SIZE]
    [SIZE=4][FONT=Courier New]'[/FONT][/SIZE]
    Last edited by Mike Doty; 1 Feb 2008, 04:21 PM. Reason: Trying to change font

    Leave a comment:


  • Mike Doty
    replied
    That makes sense. Thanks, again.

    Leave a comment:


  • Michael Mattias
    replied
    Oh, I see, you want to match the VB definition? Not create a 'new' UDT which does not suffer from different aligments?

    Then just make your PB UDT 'DWORD FILL' aligned

    If you add DUMMY members, VB will re-align those, too because it don't know from "dummy."

    If you have the luxury of defining the UDT from scratch, all you do is change STRING*1, 2 or 3 to STRING*4, STRING*5,6,or 7 to STRING*8, etc... round each member to next multiple of four in size. You can probably do some by twos, but as long as you are redesigning just 'do it' and have it done with for all time.

    Leave a comment:


  • Mike Doty
    replied
    Except, I thought VB also uses some method of natural alignment to place adjacent binary fields within the same boundary.
    Plus, do I place DUMMY string members after the members?
    DUMMY1 AS STRING * 1, DUMMY2 AS STRING * 2, etc ...
    Last edited by Mike Doty; 30 Jan 2008, 04:10 PM.

    Leave a comment:


  • Michael Mattias
    replied
    Yes, I should figure out how to align the 203-byte structure above.
    Maybe someone will do it for me with this as a reward
    ???

    I do this all the time, not that it's so hard... just round every member up in size to the the next highest multiple of four.

    Leave a comment:


  • Mike Doty
    replied
    PowerBASIC I/O from Visual Basic

    Edwin,
    Yes, I should figure out how to align the 203-byte structure above.
    Maybe someone will do it for me with this as a reward .

    The code below uses only PB code for I/O from Visual Basic using PBIO.DLL.
    An example program with VB is also included.

    Code:
    'PBIO.BAS        PB File I/O from Visual Basic
    #COMPILE EXE    '#COMPILE EXE to test, #COMPILE DLL to create DLL
    DECLARE FUNCTION GetModuleFileName LIB "KERNEL32.DLL" ALIAS "GetModuleFileNameA" (BYVAL hModule AS DWORD, _
                     lpFileName AS ASCIIZ, BYVAL nSize AS DWORD) AS DWORD
    DECLARE FUNCTION GetModuleHandle LIB "KERNEL32.DLL" ALIAS "GetModuleHandleA" (lpModuleName AS ASCIIZ) AS DWORD
    DECLARE FUNCTION PBOPEN(FilName AS STRING)AS LONG 'rename if using win32api.inc
    DECLARE FUNCTION PBLOCKFILE(FileHandle AS LONG) AS LONG
    DECLARE FUNCTION PBUNLOCKFILE(FileHandle AS LONG) AS LONG
    DECLARE SUB      PBGET(FileHandle AS LONG, RecordNumber AS LONG,Buffer AS STRING, Ecode AS LONG)
    DECLARE FUNCTION PBPUT(FileHandle AS LONG, RecordNumber AS LONG,Buffer AS STRING) AS LONG
    DECLARE FUNCTION PBCLOSE(FileHandle AS LONG) AS LONG
    DECLARE FUNCTION PBFLUSH(FileHandle AS LONG) AS LONG
    DECLARE FUNCTION PBKILL(FileNam AS STRING) AS LONG
    DECLARE FUNCTION PBLOF(TheFileHandle AS LONG) AS LONG
    DECLARE FUNCTION PBProgramName AS STRING
    DECLARE FUNCTION PBPROGRAMDIR AS STRING
     
    FUNCTION PBLockFile(FileHandle AS LONG) EXPORT AS LONG
      DIM Attempt&,MaxAttempts&
      MaxAttempts = 10
      Attempt = 0   'lock record/get/update/flush/unlock
      DO
        ERRCLEAR
        LOCK #FileHandle
        IF ERR THEN
          INCR Attempt
          SLEEP 100
        END IF
      LOOP UNTIL ERR = 0 OR Attempt => MaxAttempts
      IF Attempt => MaxAttempts THEN FUNCTION = ERRCLEAR
    END FUNCTION
    FUNCTION PBUnLockFile(FileHandle AS LONG) EXPORT AS LONG
      DIM Attempt&,MaxAttempts&
      MaxAttempts = 10
      Attempt = 0   'lock record/get/update/flush/unlock
      DO
        ERRCLEAR
        UNLOCK #FileHandle
        IF ERR THEN
          INCR Attempt
          SLEEP 100
        END IF
      LOOP UNTIL ERR = 0 OR Attempt => MaxAttempts
      IF Attempt THEN
        IF Attempt => MaxAttempts THEN
          FUNCTION = ERRCLEAR
        END IF
      END IF
    END FUNCTION
    FUNCTION PBLof(TheFileHandle AS LONG) EXPORT AS LONG
      LOCAL temp AS LONG
      Temp = LOF(TheFileHandle)
      IF ERR = 0 THEN
          FUNCTION = Temp
      ELSE
        FUNCTION = -ERRCLEAR
      END IF
    END FUNCTION
    SUB PBGet(FileHandle AS LONG, RecordNumber AS LONG, Buffer AS STRING, Ecode AS LONG) EXPORT
      Ecode = 0
      GET #FileHandle,RecordNumber,buffer
      IF ERR THEN Ecode = ERRCLEAR
    END SUB
    FUNCTION PBPut(FileHandle AS LONG, RecordNumber AS LONG, Buffer AS STRING) EXPORT AS LONG
      PUT #FileHandle,RecordNumber,buffer
      IF ERR THEN FUNCTION = ERRCLEAR
    END FUNCTION
    FUNCTION PBFlush(FileHandle AS LONG) EXPORT AS LONG
      FLUSH #FileHandle
      IF ERR THEN FUNCTION = ERRCLEAR
    END FUNCTION
    FUNCTION PBClose(FileHandle AS LONG) EXPORT AS LONG
      CLOSE #FileHandle
      IF ERR THEN FUNCTION = ERRCLEAR
    END FUNCTION
    FUNCTION PBOpen(FilName AS STRING) EXPORT AS LONG
      DIM Attempt AS LONG
      DIM MaxAttempts AS LONG
      DIM FileHandle AS LONG
      MaxAttempts& = 10
      Attempt = 0
      DO
        ERRCLEAR
        FileHandle = FREEFILE
        OPEN FilName FOR BINARY LOCK SHARED AS #FileHandle
        IF ERR THEN
          INCR Attempt
          SLEEP 100
        END IF
      LOOP UNTIL ERR = 0 OR Attempt => MaxAttempts
      IF Attempt => MaxAttempts THEN
          FUNCTION = -ERRCLEAR
          EXIT FUNCTION
      END IF
      FUNCTION = FileHandle
    END FUNCTION
    FUNCTION PBKill(FilName AS STRING) EXPORT AS LONG
      KILL FilName
      IF ERR THEN FUNCTION = ERRCLEAR
    END FUNCTION
    FUNCTION PBProgramName() EXPORT AS STRING
      LOCAL hModule AS LONG
      LOCAL temp AS ASCIIZ * 256
      hModule = GetModuleHandle(BYVAL 0&)
      GetModuleFileName hModule, Temp, 256
      FUNCTION = Temp
    END FUNCTION
    FUNCTION PBProgramDir AS STRING
      LOCAL sTemp AS STRING
      LOCAL org AS LONG
      sTemp$ = PBProgramName
      org = INSTR(-1,sTemp,"\")
      IF org THEN FUNCTION = LEFT$(sTemp, org)
    END FUNCTION
     
    #IF 0
    'VBTest.bas
    OPTION EXPLICIT
    PRIVATE DECLARE FUNCTION PBOPEN LIB "PBIO.DLL" (FilName AS STRING) AS LONG 'rename if using win32api.inc
    PRIVATE DECLARE FUNCTION PBLOCKFILE LIB "PBIO.DLL" (FileHandle AS LONG) AS LONG
    PRIVATE DECLARE FUNCTION PBUNLOCKFILE LIB "PBIO.DLL" (FileHandle AS LONG) AS LONG
    PRIVATE DECLARE SUB PBGET LIB "PBIO.DLL" (FileHandle AS LONG, RecordNumber AS LONG, Buffer AS STRING, Ecode AS LONG)
    PRIVATE DECLARE FUNCTION PBPUT LIB "PBIO.DLL" (FileHandle AS LONG, RecordNumber AS LONG, Buffer AS STRING) AS LONG
    PRIVATE DECLARE FUNCTION PBCLOSE LIB "PBIO.DLL" (FileHandle AS LONG) AS LONG
    PRIVATE DECLARE FUNCTION PBFLUSH LIB "PBIO.DLL" (FileHandle AS LONG) AS LONG
    PRIVATE DECLARE FUNCTION PBKILL LIB "PBIO.DLL" (FileNam AS STRING) AS LONG
    PRIVATE DECLARE FUNCTION PBLOF LIB "PBIO.DLL" (TheFileHandle AS LONG) AS LONG
    PRIVATE DECLARE FUNCTION PBProgramName LIB "PBIO.DLL AS STRING" ()
    PRIVATE DECLARE FUNCTION PBPROGRAMDIR LIB "PBIO.DLL" () AS STRING
    PRIVATE SUB Form_Load()
      CHDIR App.Path  'so VB finds DLL in default directory
      DIM FilName$, Buffer$, hits&, RecNum&, L$, programname$, programdir$, org&
      DIM RecordsToWrite&, Attempt&, FileHandle&, result&, RecordNumber&, RecordLen&
      RecordsToWrite = 10
      RecordLen = 10
      Buffer = SPACE$(RecordLen)
      FilName = "test.txt"
      result = PBKILL(FilName)                            'kill
      FileHandle = PBOPEN(FilName)                        'open
      IF FileHandle < 1 THEN EXIT SUB
      result = PBLOCKFILE(FileHandle)                     'lock
      FOR RecNum = 1 TO RecordsToWrite
        LSET Buffer = FORMAT$(PBLOF(1) + 1)               'lof
        RecordNumber = PBLOF(FileHandle) + 1              '
        result = PBPUT(FileHandle, RecordNumber, Buffer)  'put
      NEXT
      result = PBFLUSH(FileHandle)                        'flush
      result = PBUNLOCKFILE(FileHandle)                   'unlock
      FOR RecNum = 1 TO PBLOF(FileHandle) \ LEN(Buffer)
        RecordNumber = (RecNum - 1) * LEN(Buffer) + 1
        PBGET FileHandle, RecordNumber, Buffer, result    'get
      NEXT
      result = PBCLOSE(FileHandle)                        'close
      SHELL "notepad.exe " + FilName, vbNormalFocus      'show file
      Unload Me
    END SUB
    #ENDIF
    FUNCTION PBMAIN AS LONG
      DIM FilName$,buffer$,hits&,RecNum&, L$,programname$,programdir$,org&
      DIM RecordsToWrite&,Attempt&,FileHandle&,result&,RecordNumber&, RecordLen&
      RecordsToWrite = 10
      RecordLen = 10
      Buffer = SPACE$(RecordLen)
      FilName = "test.txt"
      result = PBKILL(FilName)                            'kill
      FileHandle = PBOPEN(FilName)                        'open
      IF FileHandle < 1 THEN EXIT FUNCTION
      result = PBLockFile(FileHandle)                     'lock
      FOR RecNum = 1 TO RecordsToWrite
        LSET buffer = FORMAT$(PBLOF(1)+1)                 'lof
        RecordNumber = PBLOF(FileHandle) + 1              '
        result = PBPut(FileHandle, RecordNumber, Buffer)  'put
      NEXT
      result = PBFlush(FileHandle)                        'flush
      result = PBUnLockFile(FileHandle)                   'unlock
      FOR RecNum = 1 TO PBLOF(Filehandle) \ LEN(Buffer)
        RecordNumber = (RecNum -1) * LEN(Buffer) + 1
        PBGet FileHandle, RecordNumber, Buffer, result    'get
      NEXT
      result = PBCLOSE(FileHandle)                        'close
      SHELL "notepad " + filname                          'show file
    END FUNCTION

    Leave a comment:


  • Edwin Knoppert
    replied
    Even if you solve this with PB your structure is still a very uncommon nowadays.
    Better align to dword anyway.
    This would make it somewhat easier with other languages as well.
    The structure *may* ever be used to be passed through functions as well.

    Leave a comment:


  • Mike Doty
    replied
    Michael, that is it!
    I'll handle all I/O in a PB/DLL the same as when using CGI programs.

    Code:
    'CGIWRITE.BAS    Demonstrates open/get/put/lock/unlock/flush/close functions on the internet
    DECLARE FUNCTION GetModuleFileName LIB "KERNEL32.DLL" ALIAS "GetModuleFileNameA" (BYVAL hModule AS DWORD, _
                     lpFileName AS ASCIIZ, BYVAL nSize AS DWORD) AS DWORD
    DECLARE FUNCTION GetModuleHandle LIB "KERNEL32.DLL" ALIAS "GetModuleHandleA" (lpModuleName AS ASCIIZ) AS DWORD
    DECLARE FUNCTION OpenFile(FilName AS STRING)AS LONG 'rename if using win32api.inc
    DECLARE FUNCTION LockFile(FileHandle AS LONG) AS LONG
    DECLARE FUNCTION UNLockFile(FileHandle AS LONG) AS LONG
    DECLARE FUNCTION GetRecord(RecordNumber AS LONG, Buffer AS STRING,FileHandle AS LONG) AS LONG
    DECLARE FUNCTION PutRecord(RecordNumber AS LONG,Buffer AS STRING,FileHandle AS LONG) AS LONG
    DECLARE FUNCTION CloseFile(FileHandle AS LONG) AS LONG
    DECLARE FUNCTION FlushFile(FileHandle AS LONG) AS LONG
    DECLARE FUNCTION KillFile(FileNam AS STRING) AS LONG
    DECLARE FUNCTION exename AS STRING

    Leave a comment:


  • Michael Mattias
    replied
    I'm not quite sure what the VB program does and what the PB code must do, but another possibility is to put ALL the I-O into a PB DLL and call those functions from both programs whenever I-O is required.

    Leave a comment:


  • Mike Doty
    replied
    I' will check it out. Thank you.
    For now, I'm just passing through a disk buffer which wouldn't
    be too bad if no disk activity took place. The memory mapped file
    seems like a good solution.

    Leave a comment:


  • Michael Mattias
    replied
    >There may be a better way, but haven't found it

    Read and write the file using a memory-mapped file object. Then it will always "look like" memory and utilize the DWORD FILL alignment.

    See this demo for an example:
    Memory Mapped Files instead of RANDOM disk file access 5-8-04

    That's not set up for I-O, but that is just a couple of small changes which you can look up in your Windows API reference.

    Or maybe it *is* set up for I-O, I can't remember. I know my library version of the MapTHisFile function is set up with an I-O flag parameter but I don't know if that demo came before I did that or not.

    MCM

    Leave a comment:


  • Mike Doty
    replied
    When reading/writing the data does not need to be aligned so
    the structures can be the same. If passing data in memory it
    appears the Visual Basic structure must be padded
    There may be a better way, but haven't found it.

    Leave a comment:


  • Michael Mayerhoffer
    replied
    Aye says the blind one, just seen the word print ...forget that CC uses that.

    Leave a comment:


  • Michael Mattias
    replied
    DWORD FILL is used whenever you need or want that particular alignment of UDT members. Disk, memory, whatever.

    IIRC (and this is from a long time ago), Visual Basic itself may not treat writes to disk the same as it does passing in memory.
    Last edited by Michael Mattias; 29 Jan 2008, 06:00 PM.

    Leave a comment:


  • Mike Doty
    replied
    Thanks, but that is not it.
    I'm using GET and PUT.

    Leave a comment:


  • Michael Mayerhoffer
    replied
    Print will add a CR/LF aka 2-bytes if there is no ";" at the end of the print statement.

    Leave a comment:


  • Mike Doty
    started a topic Is DWORD FILL only used with DLL's?

    Is DWORD FILL only used with DLL's?

    Is DWORD FILL only used when passing values in memory?
    DWORD FILL adds 2-bytes to the structure when writing to disk.
    Without DWORD FILL the records are read correctly by a Visual Basic program using the same structure.

    Code:
    'Records are 203 bytes (if DWORD FILL is added they become 205 bytes)
    Type ClientType
      A As Integer              '1,2
      B As String * 7           '3,7
      C As String * 20          '10,20
      D As String * 20          '30,20
      E As String * 10          '50,10
      F As String * 11          '60,11
      G As Long                 '71,4
      H As String * 30          '75,30
      I As String * 30          '105,30
      J As String * 20          '135,20
      K As String * 2           '155,2
      L As String * 1           '157,1
      M Phone As String * 7     '158,7
      N As Integer              '165,2
      O As Long                 '167,4
      P As Long                 '171,4
      Q As Integer              '175,2
      R As String * 2           '177,2
      S As String * 3           '179,3
      T As String * 3           '182,3
      U As String * 8           '185,8
      V As String * 4           '193,4
      W As Integer              '197,2
      X As String * 1           '199,1
      Y As String * 4           '200,4
    End Type
     
    Function PBMAIN() As Long
        On Error Resume Next
        Dim hFile As Long, x As Long, sFileName As String, client As ClientType
        sFileName = "TEST.DAT"
        hFile = FreeFile
        Open sFileName For Binary As hFile
        For x = 1 To LOF(hFile) \ Len(client)
          Get #hFile, , client
          Print client.a; client.c
        Next
        client.a = x
        client.c = "Added record" + Str$(x)
        Put #hFile, , client
        Print client.a; client.c
        Close #hFile
    End Function
    Last edited by Mike Doty; 29 Jan 2008, 05:31 PM.
Working...
X