I'm using a lot of STATIC variables in the CALLBACK functions of my dialogs. After ending of a dialog the memory occupied by the STATIC variables normally is no more needed and should be released. But this, at least by means of DDT, is not possible. The doc says: "Static variables retain their values as long as the program is running." What is the apporiate method to use variables, which are visible throughout the CALLBAK during the lifetime of the dialog, and which can be "destroyed" after "DIOLOG END..." so that the memory is released? GlobalAlloc() / GlobalFree() is obviously not the recommended way for use in DDT CALLBACKs...
Announcement
Collapse
No announcement yet.
Static Variables And Memory
Collapse
X
-
Can't be done.
The space for those variables is in your program's data segment which is TOTALLY under the control of compiler-generated code.
But how many STATIC variables can you have that it makes a difference?
But let's just say it does make a difference... if so, you can allocate that space yourself (here GlobalAlloc could be useful, or that new thing in 9x, whats that GLOBAL MEM ALLOC?), save the 4-byte handle to the block somewhere, and GlobalFree the block on WM_DESTROY.
Heck, you'd have to do this anyway if you needed your dialog procedure to be re-entrant, so go ahead and do it now.
MCMMichael Mattias
Tal Systems (retired)
Port Washington WI USA
[email protected]
http://www.talsystems.com
-
I came to these considerations when looking for memory leaks. Every time when I call a dialog containing a %LBS_NODATA listbox with an array of more than thousand items the memory occupied by the program is increasing. I checked the usual "suspects" like missing DeleteObject() but can't find a mistake. The dialog is - as most of my dialogs - situated in a DLL. Any idea?
Comment
-
LBS_NODATA
Specifies a no-data list box. Specify this style when the count of items in the list box will exceed one thousand. A no-data list box must also have the LBS_OWNERDRAWFIXED style, but must not have the LBS_SORT or LBS_HASSTRINGS style.Michael Mattias
Tal Systems (retired)
Port Washington WI USA
[email protected]
http://www.talsystems.com
Comment
-
Code:CASE %WM_DRAWITEM, %WM_MEASUREITEM IF CBWPARAM = idlist THEN SubclassArtilistproc GetDlgItem(CBHNDL, CBWPARAM), CBMSG, CBWPARAM, CBLPARAM END IF IF CBWPARAM = %IDC_ListSaldoLBL THEN SubClassArtiSaldoTBXProc GetDlgItem(CBHNDL, CBWPARAM), CBMSG, CBWPARAM, CBLPARAM END IF IF CBWPARAM = %IDC_ListSaldo2LBL THEN SubClassArtiSaldo2TBXProc GetDlgItem(CBHNDL, CBWPARAM), CBMSG, CBWPARAM, CBLPARAM END IF
Comment
-
Heere is the %WM_DRAWITEM-section of ent SubClassproc:
Code:FUNCTION SubclassArtilistproc(BYVAL hWnd AS LONG, BYVAL wMsg AS LONG, _ BYVAL wParam AS LONG, BYVAL lParam AS LONG) AS LONG LOCAL lpdis AS DRAWITEMSTRUCT PTR LOCAL ztxt AS ASCIIZ*%MAX_PATH LOCAL hPen AS DWORD,x AS DWORD LOCAL i AS LONG,t AS LONG,itd AS LONG LOCAL cnt AS LONG LOCAL fmt AS STRING LOCAL rc AS RECT LOCAL BkColorList,iLines,tabBMP,Topindex AS LONG LOCAL hBmp AS DWORD BkColorList = RGB(255, 255, 196) iLines = 2 SELECT CASE wMsg CASE %WM_DRAWITEM lpdis = lParam IF @lpdis.itemID = %TIME_ZONE_ID_INVALID THEN EXIT FUNCTION SELECT CASE @lpdis.itemAction CASE %ODA_DRAWENTIRE, %ODA_SELECT IF @lpdis.itemID MOD 2 = 0 THEN BkColorList = RGB(192, 192, 192) REDIM Colors(UBOUND(gTabsArtlist) + 1) AS LONG 'CLEAR BACKGROUND IF (@lpdis.itemState AND %ODS_SELECTED) = 0 THEN 'if not selected SetBkColor @lpdis.hDC, BkColorList SetTextColor @lpdis.hDC, GetSysColor(%COLOR_WINDOWTEXT) FillRect @lpdis.hDC, @lpdis.rcItem,CreateSolidBrush(BkColorList) ELSE SetBkColor @lpdis.hDC, GetSysColor(%COLOR_HIGHLIGHT) 'sel text background IF gWaren(@lpdis.itemID).gemerkt THEN SetTextColor @lpdis.hDC,RGB(0,255,0) 'sel text color ELSE SetTextColor @lpdis.hDC, GetSysColor(%COLOR_HIGHLIGHTTEXT) 'sel text color END IF FillRect @lpdis.hDC, @lpdis.rcItem, GetSysColorBrush(%COLOR_HIGHLIGHT) 'clear background END IF IF gWaren(@lpdis.itemID).gemerkt THEN FOR i = 0 TO UBOUND(Colors) Colors(i) = RGB(0,128,128) NEXT i ELSE SetTextColor @lpdis.hDC, GetSysColor(%COLOR_WINDOWTEXT) 'text color END IF 'draw gridlines between items hPen = CreatePen(%PS_SOLID, 1, GetSysColor(%COLOR_3DFACE)) hPen = SelectObject(@lpdis.hDC, hPen) MoveToEx @lpdis.hDC, 0, @lpdis.rcItem.nBottom - 1, BYVAL %NULL LineTo @lpdis.hDC, @lpdis.rcItem.nRight, @lpdis.rcItem.nBottom - 1 DeleteObject SelectObject(@lpdis.hDC, hPen) 'GET ITEM'S TEXT AND DRAW TEXT InflateRect @lpdis.rcItem, -2, -2 '1. line: ztxt = PARSE$(Get_ArtiListLines(Get_Parent(hWnd),@lpdis.itemID),$CRLF,1) IF INSTR(ztxt,"{bmp:Basissatz}") THEN hbmp = LoadBitmap(GetModuleHandle(BYVAL %NULL),BYVAL MAKLNG(%IDB_BITMAP17,0)) 'B ELSEIF INSTR(ztxt,"{bmp:Gebindesatz}") THEN hbmp = LoadBitmap(GetModuleHandle(BYVAL %NULL),BYVAL MAKLNG(%IDB_BITMAP19,0)) 'G END IF tabBMP = Txt_Width_Pix(Get_Parent(hWnd),EXTRACT$(ztxt,$TAB)) IF Ist_Gebindesatz(gWaren(@lpdis.itemID)) THEN Colors(4) = %GRAY END IF ListlinesClr Get_Parent(hWnd),2,ztxt,lpdis,gTabsArtlist(),Colors() 'DLLs\Dlgrout.inc '2. line: zTxt = PARSE$(Get_ArtiListLines(Get_Parent(hWnd),@lpdis.itemID),$CRLF,2) IF Ist_Gebindesatz(gWaren(@lpdis.itemID)) THEN IF gArtilistSaldo <> %SaldoArtikelAnzahl THEN Colors(4) = %GRAY ELSEIF gArtilistSaldo = %SaldoArtikelAnzahl THEN Colors(4) = 0 END IF END IF CONTROL SEND Get_Parent(hWnd), GetDlgCtrlID(hWnd), %LB_GETITEMHEIGHT, 0, 0 TO i 'Get height of one line IF hbmp THEN rc.nLeft = 3 : rc.nRight = rc.nLeft + 12 'Set cordinates rc.ntop = @lpdis.rcItem.ntop + i / iLines rc.nbottom = @lpdis.rcItem.nbottom - 1 DrawState @lpdis.hDC, 0&, 0&, hbmp, 0&, rc.nLeft, _ rc.nTop + 2, 0, 0, %DST_BITMAP DeleteObject hbmp END IF ListlinesClr Get_Parent(hWnd),i / 2,ztxt,lpdis,gTabsArtlist(),Colors() 'DLLs\Dlgrout.inc IF gWaren(@lpdis.itemID).DurchlPosten = "J" AND gArtilistSaldo <> %SaldoArtikelAnzahl THEN hbmp = LoadBitmap(GetModuleHandle(BYVAL %NULL),BYVAL MAKLNG(%IDB_BITMAP18,0)) 'd red rc.nLeft = tabBMP - 12 : rc.nRight = rc.nLeft + 12 'Set cordinates rc.ntop = @lpdis.rcItem.ntop + i / iLines rc.nbottom = @lpdis.rcItem.nbottom - 1 DrawState @lpdis.hDC, 0&, 0&, hbmp, 0&, rc.nLeft, _ rc.nTop + 2, 0, 0, %DST_BITMAP DeleteObject hbmp END IF 'FOCUS RECT AROUND SELECTED ITEM IF (@lpdis.itemState AND %ODS_SELECTED) THEN 'if selected CALL DrawFocusRect(@lpdis.hDC, @lpdis.rcItem) 'draw a focus rectangle around all END IF FUNCTION = %TRUE EXIT FUNCTION CASE %ODA_FOCUS DrawFocusRect @lpdis.hDC, @lpdis.rcItem 'draw focus rectangle END SELECT ... END SELECT DIALOG GET USER hWnd, 1 TO x FUNCTION = CallWindowProc(x, hWnd, wMsg, wParam, lParam) END FUNCTION
Comment
-
Umm.... probably..
That is, I think you were oin the right path looking for missing DeleteObject() calls... but without seeing the code where you Get/Create the objects to be deleted, nobody can tell if you are missing a DeleteObject().
That is, somewhere you are doing a CreatePen(), CreateBrush() or CreateFont() ; but we can't tell where where that function is not 'paired' with a DeleteObject() for same.
(BTW, don't call it a "subclass proc" unless the control is actually subclassed. Not that it is an error, it's just quite confusing because the term "subclass proc" is generally used only in this case).Michael Mattias
Tal Systems (retired)
Port Washington WI USA
[email protected]
http://www.talsystems.com
Comment
-
Well, here's one leak...
Code:FillRect @lpdis.hDC, @lpdis.rcItem,CreateSolidBrush(BkColorList)
MCMMichael Mattias
Tal Systems (retired)
Port Washington WI USA
[email protected]
http://www.talsystems.com
Comment
-
One more thing before you go...
This code is incorrect:
Code:SELECT CASE @lpdis.itemAction
Code:IF (@lpdis.itemAction AND %ODA_FOCUS) THEN ' Draw control in focused state.
Comment
-
Probably you are right. But almost all samples from the POFFs use it like I did, and it works
Taking the time to "do it right" will always pay for itself in the long run.Michael Mattias
Tal Systems (retired)
Port Washington WI USA
[email protected]
http://www.talsystems.com
Comment
-
I take it the question about de-allocating STATIC variables is now off the table?Michael Mattias
Tal Systems (retired)
Port Washington WI USA
[email protected]
http://www.talsystems.com
Comment
-
The most powerful debugging technique which I have used under similar circumstances is to cut out parts of the application until the problem goes away. Then I know that the last part cut out contained the problem. Then I build a miniature application with just enough functionality to demonstate the problem. If this does not lead me to the solution, then at least I have a compileable application which can be posted here for these world-class problem-solvers to get their teeth into!
Comment
-
... Is it shure that there is no connection with the allocated memory for STATIC variables which cannot be released?Michael Mattias
Tal Systems (retired)
Port Washington WI USA
[email protected]
http://www.talsystems.com
Comment
-
...can be posted here for these world-class problem-solvers to get their teeth into...
But this does not belong to the current thread. Concerning the memory issue I found something interesting: The lost of memory seems to be a problem of PowerBasic rather than of my faulty code. The following snippet shows: When you call, from a console application, a windows-dialog situated in a DLL, more and more memory is lost each time you call the function in the DLL. And this without one relevant line in the called function! I have tested the memory with the "process_memoryinfo"-tool: http://www.powerbasic.com/support/pb...ad.php?t=24120
Console-app:
Code:#INCLUDE "WIN32API.INC" #INCLUDE "process_memoryinfo.inc" DECLARE FUNCTION ShowTOPWindow LIB "MEMTEST.DLL" (BYVAL hParent AS DWORD) AS LONG DECLARE SUB Call_FunctionInDLL(BYVAL hPrnt AS LONG) FUNCTION WINMAIN(BYVAL hCurInstance AS LONG, _ BYVAL hPrevInstance AS LONG, _ lpszCmdLine AS ASCIIZ PTR, _ BYVAL nCmdShow AS LONG) AS LONG Call_FunctionInDLL GetDeskTopWindow() END FUNCTION SUB Call_FunctionInDLL(BYVAL hPrnt AS LONG) LOCAL s AS STRING, l AS LONG, i AS LONG LOCAL hFile AS LONG, szFile AS ASCIIZ * %MAX_PATH LOCAL pID AS DWORD, sBuff AS STRING LOCAL memcnt AS LONG FOR i = 1 TO 10 GOSUB memtest_1 ShowTOPWindow hPrnt GOSUB memtest_2 NEXT i EXIT SUB memtest_1: INCR memcnt szFile = "Process_memory_Statistics_" + FORMAT$(memcnt) + ".txt" hFile = FREEFILE OPEN szFile FOR OUTPUT AS hFile PID = GetCurrentProcessID sBUff = "Process Memory Statistics for Process ID " & STR$(PID) & " on " & DATE$ & " at " & TIME$ PRINT #hFile, sBUff PRINT #hFile, L = GetProcessMemoryStatistics (s) sBUff = "Process Memory Statistics 1" PRINT #hFile, sBuff PRINT #hFile, s PRINT #hFile, RETURN memtest_2: L = GetProcessMemoryStatistics (s) sBUff = "Process Memory Statistics 2" PRINT #hFile, sBuff PRINT #hFile, s PRINT #hFile, sBuff = "END OF REPORT" PRINT #hFile, sBuff CLOSE hFile PID = SHELLExecute (GetDesktopWindow, "open", szFile, BYVAL %NULL, BYVAL %NULL, %SW_SHOW) RETURN END SUB
Code:#COMPILE DLL "\Memtest.dll" #DIM ALL FUNCTION ShowTOPWindow(BYVAL hParent AS DWORD) EXPORT AS LONG ? "ShowTOPWindow() in DLL" END FUNCTION
Comment
-
application, a windows-dialog situated in a DLL, more and more memory is lost each time you call the function in the DLL
Ooops, does not apply when statically linked.
My Bad.Last edited by Michael Mattias; 20 Nov 2008, 09:30 AM.Michael Mattias
Tal Systems (retired)
Port Washington WI USA
[email protected]
http://www.talsystems.com
Comment
-
This is bad news. I have replaced almost all console-emelents in my apps by windows-dialogs (located in DLLs), and the console compiler will be obsolet for me within a few months. So it's not worth to buy the current version for the short remaining time. On the other hand I have this annoying memory leak...
Comment
-
I can't find it but I know there is a WinApi function which gives you a count of the current GDI objects owned by your application. That would be a handy thing for you in this case.
Maybe someone else remembers the name of that function.Michael Mattias
Tal Systems (retired)
Port Washington WI USA
[email protected]
http://www.talsystems.com
Comment
Comment