Announcement

Collapse
No announcement yet.

Very unusual problem.

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

  • Tim Lakinir
    replied
    Thank you Sir Hutchesson, I learn much from here. Also Thank you to Everyone here.

    Leave a comment:


  • Jim Fritts
    replied
    Thanks Steve!

    Leave a comment:


  • Steve Hutchesson
    replied
    If you have a strong enough stomach, here is how to use the CALL DWORD notation to call a function in a DLL dynamically. The help file is about as clear as mud.
    Code:
    ' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
    
        #include "\basic\include\win32api.inc"
    
      ' -------------------------------------
      ' Make a prototype for the DLL function
      ' -------------------------------------
        DECLARE FUNCTION MyMBox LIB "tim.dll" ALIAS "MyMsgbox" _
                         (BYVAL hWnd AS DWORD,lpText AS ASCIIZ, _
                         lpCaption AS ASCIIZ,BYVAL dwType AS DWORD) AS LONG
    
    ' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
    
    FUNCTION PBmain as LONG
    
        LOCAL rval as DWORD
        LOCAL hLib as DWORD
        LOCAL MyMsgBox as DWORD
    
        hLib = LoadLibrary("tim.dll")
        MyMsgbox = GetProcAddress(hLib,"MyMsgbox")
    
      ' ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
    
        CALL DWORD MyMsgBox USING MyMBox(0,"How D","Title",%MB_OK) TO rval
    
      ' ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
    
        FreeLibrary hLib
    
    End FUNCTION
    
    ' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

    Leave a comment:


  • Steve Hutchesson
    replied
    Something I did not take enough notice of with the comments for Tim was how you have to call a dynamically linked DLL (the reason why they are called DYNAMIC link libraries). PB does not have a tidy way of calling functions from a DLL dynamically and you are stuck with CALL DWORD notation which is really clunky to code. I personally do DLL calls of this type in assembler as its far faster to code and a lot easier to read but its not a common technique for folks who code in high level basic.

    If anyone is interested, here is how I would do it.
    Code:
    ' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
    '                                       compile with pbwin10
    ' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
    
        #compile exe "call2.exe"
        #option largemem32
        #include "\basic\include\win32api.inc"
    
        MACRO FUNCTION rvcall4(procedure,arg1,arg2,arg3,arg4)
          MACROTEMP rval
          LOCAL rval as DWORD
          ! push arg4
          ! push arg3
          ! push arg2
          ! push arg1
          ! call procedure
          ! mov rval, eax
        END MACRO = rval
    
        MACRO FUNCTION localstr(quoted_text,bytecount)
          MACROTEMP szstring
          LOCAL szstring as STRINGZ * bytecount
          szstring = quoted_text
        END MACRO = VarPtr(szstring)
    
    ' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
    
     FUNCTION PBmain as LONG
    
        LOCAL hLib as DWORD
        LOCAL MyMsgbox as DWORD
        LOCAL rval as DWORD
        LOCAL ptxt as DWORD
        LOCAL pttl as DWORD
    
        hLib = LoadLibrary("tim.dll")
        MyMsgbox = GetProcAddress(hLib,"MyMsgbox")
    
        ptxt = localstr("How D Awl",64)
        pttl = localstr("Title",64)
    
      ' |||||||||||||||||||||||||||||||||||||||||||
    
        rval = rvcall4(MyMsgbox,0,ptxt,pttl,%MB_OK)
    
      ' |||||||||||||||||||||||||||||||||||||||||||
    
        rval = FreeLibrary(hLib)
    
     End FUNCTION
    
    ' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
    This is the test DLL.
    Code:
    ' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
    '                                       compile with pbwin10
    ' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
    
        #COMPILE DLL
    
        GLOBAL DLLinstance as DWORD      ' the DLLs instance handle
    
        #INCLUDE "\basic\include\win32api.inc"
    
    ' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
    
    FUNCTION LibMain(BYVAL hInst    as LONG, _
                     BYVAL Reason   as LONG, _
                     BYVAL Reserved as LONG) as LONG
    
        LOCAL RetVal as DWORD
    
        Select Case Reason
          Case %DLL_PROCESS_ATTACH
            DLLinstance = hInst     ' make DLL instance global
            RetVal = 1              ' needed so DLL will start
    
        End Select
    
        FUNCTION = RetVal
    
    END FUNCTION
    
    ' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
    
    FUNCTION MyMsgbox ALIAS "MyMsgbox"( ByVal hwnd as DWORD, _
                                        ptxt as ASCIIZ, _
                                        titl as ASCIIZ, _
                                        ByVal styl as DWORD _
                                      ) EXPORT as LONG
    
        MessageBox hwnd,ptxt,titl,styl
    
        FUNCTION = 0
    
    END FUNCTION
    
    ' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

    Leave a comment:


  • Michael Mattias
    replied
    To answer your question, FreeLibrary() releases any memory used by the DLL.
    It also causes notifications (DLL_THREAD_DETACH, DLL_PROCESS_DETACH) to be sent to the entry point function of the DLL ("DLLMAIN", "LIBMAIN") and you can perform any required "cleanup" at that time. .

    Leave a comment:


  • Michael Mattias
    replied
    Are there additional memory clearance statements kinda similar to RESET and ERASE which we can use so that variables used in the DLLs are cleared
    when we exit these DLLs ?
    As noted by Mr. Pringels, you do not "exit" a DLL.

    And unless you have done some fairly unusual things, any variables used by procedures in your DLL are not visible in your main program, so resetting or clearing hardly seems necessary. They really cannot be using "that much" memory.. and if they are you should probably be explicity resetting them in your using procedures prior to exiting those procedures.

    All that said, there are certain calls which produce system objects (e.g GLOBAL string variables , GDI objects created by LoadImage() and the like, COM objects (NEWCOM, ANYCOM) , some others) and unless explicitly reset or closed will remain part of your process, consuming memory until the process ends, at which time the Windows operating system will deallocate them. .

    Leave a comment:


  • Steve Hutchesson
    replied
    Tim,

    Yes if you split up the resources into separate DLLs and load them on demand. It means using LoadLibrary(), GetProcAddress() and FreeLibrary() but it is a really efficient way to handle large amounts of data rather than just allocating very large amounts of memory in a single application. The allocation is done by the EXE you create but you get nothing for nothing, it just does it for you.

    To answer your question, FreeLibrary() releases any memory used by the DLL.

    Leave a comment:


  • Steven Pringels 3
    replied
    Originally posted by Tim Lakinir View Post
    Thank you Everyone

    One more question related to Steve's response



    Does this means that instead of executing one big program, you can have one main program MainProg.exe calling several DLLs
    say child1.dll , child2.dll and child3.dll each of which would load a portion of the original big program into memory.

    Doing this way, it would be more efiicient in terms of memory allocation than having to execute one big program ?

    The question is that :
    If we have called say child2.dll and then close it and then go back to the MainProg.exe , will the memory of child2.dll
    still persist after we have close up child2.dll ?

    Are there additional memory clearance statements kinda similar to RESET and ERASE which we can use so that variables used in the DLLs are cleared
    when we exit these DLLs ?
    That doesn't work that way. You can't 'close' a DLL. you may unload it from memory if you're using implicit linking through loadlibrary and a lot of hocus pocus with getting the pointer to each of the exposed functions. To invoke those implicit functions then you should use "Call Dword ..... using .... "

    In normal circumstances when explicit linking is used, DLL's stay linked to the process it was executed with, in this case MainProg.exe. The only benefit DLLs have is maintainability if patches need to be distributed only DLLs need to be downloaded if the main executable is kept as small as possible and another use-case is re-using functions for other executables. Download a program called Dependency Walker and see for yourself what DLLs an executable depends upon when launched.

    Leave a comment:


  • Tim Lakinir
    replied
    Thank you Everyone

    One more question related to Steve's response

    If you have some reason for massive resources, putting them into DLLs would spread the load so it is more manageable for the calling executable.
    Does this means that instead of executing one big program, you can have one main program MainProg.exe calling several DLLs
    say child1.dll , child2.dll and child3.dll each of which would load a portion of the original big program into memory.

    Doing this way, it would be more efiicient in terms of memory allocation than having to execute one big program ?

    The question is that :
    If we have called say child2.dll and then close it and then go back to the MainProg.exe , will the memory of child2.dll
    still persist after we have close up child2.dll ?

    Are there additional memory clearance statements kinda similar to RESET and ERASE which we can use so that variables used in the DLLs are cleared
    when we exit these DLLs ?

    Leave a comment:


  • Michael Mattias
    replied
    RE
    If you have some reason for massive resources, putting them into DLLs would spread the load so it is more manageable for the calling executable. You will still run into absolute memory limits but if you are handling resources that big collectively you would load the start address of each DLL and dynamically load each one as you need it and free it after.
    Also useful if you want to change other program data such as pictures, text or whatever without having to recompile - and re-test - the program itself. The "resource only" DLL makes for a nice maintenance tool IMO.

    MCM

    Leave a comment:


  • Steve Hutchesson
    replied
    Tim,

    Stack memory is assigned to an executable file, default in most is 1 meg but 2 or 4 meg are viable. You tend to increase the stack allocation if you are using recursion or run something that allocates a massive amount of LOCAL variables. Under Win32 on a 32 bit system, you can allocate collectively just under 2 gigabytes and if you use #option largemem32 you get another block of memory, 7 to 800 meg to operate on the first big allocation. On a 64 bit system you get a bit more with a 32 bit app. Virtual memory (IE: Disk emulation of memory) is used by the OS to swap out some apps memory so that more can be allocated in dynamic memory (RAM).

    Leave a comment:


  • Stuart McLachlan
    replied
    Originally posted by Tim Lakinir View Post
    I have seen somewhere in the forum, some members uses #STACK 4194304 statement
    does this stack statement would be able to kinda stabilize the available virtual memory to load a large file from the resource
    That just makes the stack 4MB instead of the default 1MB. Nothing to do with the HEAP .

    You may be able to get a larger file with #OPTION LARGEMEM32 directive:
    "For 32-bit Windows applications, this option sets the "Large Memory Model" flag. This allows your application to use more than the original limit of 2 Gigabytes of memory. Depending upon the version of Windows in use, and the installed memory, the exact increase may vary from computer to computer. In most cases, you will likely be limited to a total of approximately 3 Gigabytes".


    Leave a comment:


  • Tim Lakinir
    replied
    Thanks to all, except that in https://forum.powerbasic.com/forum/u...454#post771454

    Under Win/32, the number of processes which may each use 2 GB memory is limited only by the total available VIRTUAL memory on the system, which is the amount of installed RAM plus the max size of the swap file.
    I have seen somewhere in the forum, some members uses #STACK 4194304 statement
    does this stack statement would be able to kinda stabilize the available virtual memory to load a large file from the resource, see

    https://forum.powerbasic.com/forum/u...645#post796645

    Leave a comment:


  • Steve Hutchesson
    replied
    If you have some reason for massive resources, putting them into DLLs would spread the load so it is more manageable for the calling executable. You will still run into absolute memory limits but if you are handling resources that big collectively you would load the start address of each DLL and dynamically load each one as you need it and free it after.

    Leave a comment:


  • Stuart McLachlan
    replied
    Originally posted by Tim Lakinir View Post

    By the way, what would be the maximum amount of data that can be stored in a resource? I believe it is around 2GB ?
    See https://forum.powerbasic.com/forum/u...mit#post771041

    Leave a comment:


  • Stuart McLachlan
    replied
    Originally posted by Michael Mattias View Post

    Not that it matters because I would NEVER (on purpose) create two resources of same type with same ID but...

    How do you access a resource by ordinal? I cannot find any WinAPI functions which do that. I only have reference thru Win/XP here so maybe there is a new function(?)

    MCM
    One way is to use ResourceHacker

    Within your application, just use Loadmage or whatever. In the case of a bitmap/icon/cursor:

    If the image resource is to be loaded by ordinal from the module, use the MAKEINTRESOURCE macro to convert the image ordinal into a form that can be passed to the LoadImage function.

    Leave a comment:


  • Tim Lakinir
    replied
    The actual amount of data is about 350k of RTF format text and this seems to be the problem.
    By the way, what would be the maximum amount of data that can be stored in a resource? I believe it is around 2GB ?

    Leave a comment:


  • Michael Mattias
    replied
    FWIW: If there are duplicate Resource name/ID for the same type of resource, both resources get compiled, either one may be accessed by ordinal number but only the first by ID. If you have two different types of resources with the same name/id both may be accessed by name/id.
    Not that it matters because I would NEVER (on purpose) create two resources of same type with same ID but...

    How do you access a resource by ordinal? I cannot find any WinAPI functions which do that. I only have reference thru Win/XP here so maybe there is a new function(?)

    MCM

    Leave a comment:


  • Steve Hutchesson
    replied
    What surprised me was that it ran when it tried to write to memory that was not allocated by the app. Normally you get a GP fault with an error of that type. It was a pain to isolate because of that. Once I found the line by narrowing down where the error occurred, the rest was reasonably straight forward. Some of the innards of Windows still fascinates me.

    Leave a comment:


  • Stuart McLachlan
    replied
    Originally posted by Michael Mattias View Post
    For that matter, if you built your executable with duplicate IDs for type RCDATA resources using '#RESOURCE' statements, that should* have been caught at compile time.

    MCM
    * should does not mean "does" .. I have found a number of PB intrinsics which don't always return a PB error.
    FWIW: If there are duplicate Resource name/ID for the same type of resource, both resources get compiled, either one may be accessed by ordinal number but only the first by ID. If you have two different types of resources with the same name/id both may be accessed by name/id.


    Leave a comment:

Working...
X