June 01, 2024, 11:53:03 AM

News:

IonicWind Snippit Manager 2.xx Released!  Install it on a memory stick and take it with you!  With or without IWBasic!


UDT and POINTER problem

Started by LarryMc, January 10, 2009, 07:33:49 AM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

LarryMc

January 10, 2009, 07:33:49 AM Last Edit: January 10, 2009, 09:08:57 AM by Larry McCaughn
1. My program defines a udt as an array and loads it with values
type clmData
int     setnum
uint   dat
int     cnt
pointer    datu
int     dstyle
uint   dcolor
int     colorsrc
endtype

clm_DATA z[21]
int c
for c=0 to 20
z[c].value1=RAND(20)+0.0
z[c].value2=RAND(20)+0.0
z[c].dcolor=rand(0xffffff)
next c

I then pass that to a subroutine that loads it into another structure"
AddDataSetCLM(d1,98,19,z,20)

sub AddDataSetCLM(win:WINDOW,id:UINT,setnum:int,datsrc:clm_data,cnt:int)
clmData p
p.setnum =setnum
p.cnt =cnt
print datsrc[5].value1                <---prints proper value
p.datu = datsrc
print "pointer ",p.datu
pointer v
v=p.datu
print #<clm_Data>v[5].value1       <---prints proper value
SENDMESSAGE win,msgCLMadddata,0,p,id
return


In the handler that the above message is sent to I load the reference to the array in a linked list:
case msgCLMaddData
pointer tdata2
tData2 = ListAdd(#pc.slist, NEW(clmData,1) )
#<clmData>tData2 = ##<clmData>lparam
_SetWindowLong(hwnd, GWL_USERDATA, pc)
InvalidateRect(hWnd, NULL, FALSE)


In the paint message handler I call a routine to retrieve the data:
SETTYPE pc, CLMPARAMS

pointer tData=0
FOR tData = EACH #pc.slist AS clmData
     PRINT #tData.setnum              <---- prints the expected value
      PRINT "hhh",#tData.datu       <---- prints the same pointer number as in the beginning
pointer v
v=#tData.datu
print "vvv",v                              <---- prints the same pointer number
print #<clm_data>v[5].value1    <--- WRONG VALUE


Clueless ???

Larry
LarryMc
Larry McCaughn :)
Author of IWB+, Custom Button Designer library, Custom Chart Designer library, Snippet Manager, IWGrid control library, LM_Image control library

fasecero

it's complicated, lparam seems to be a clmData, maybe replacing:
   #<clmData>tData2 = ##<clmData>lparam
with
   #<clmData>tData2 = lparam
not sure at all.

Ionic Wind Support Team


first:

SENDMESSAGE win,msgCLMadddata,0,&p,id

second:

   case msgCLMaddData
         pointer tdata2,ptemp
         tData2 = ListAdd(#pc.slist, NEW(clmData,1) )
                        ptemp = lparam+0
         #<clmData>tData2 = #<clmData>ptemp

         _SetWindowLong(hwnd, GWL_USERDATA, pc)


It is the simplest and most understandable way to do it.  Your passing an address in the sendmessage, and obtaining that address using lparam+0,   The way Emergence works is if you were to do ptemp = lparam, then ptemp would have the address of lparam, not the address of the UDT.
Paul
Ionic Wind Support Team

fasecero

January 10, 2009, 10:02:33 AM #3 Last Edit: January 10, 2009, 10:07:48 AM by fasecero
yes, it's work


' compile with debug activated to see the values

$INCLUDE "windows.inc"

CONST BUTTON_1 = 1
window w1
OPENWINDOW w1,0,0,300,202,0x80C80080,0,"Caption",&w1_handler
CONTROL w1,@BUTTON,"SendMessage",85,143,131,29,0x50000000,BUTTON_1

CONST msgCLMadddata=234

type clmData
int setnum
uint dat
int cnt
pointer     datu
int dstyle
int colorsrc


INT value1
INT value2
uint dcolor
endtype

clmData z[21]
int c
for c=0 to 20
z[c].value1=RAND(20)+0.0
z[c].value2=RAND(20)+0.0
z[c].dcolor=rand(0xffffff)
next c

INT OldDialogProc

salir=0
WAITUNTIL salir=1

SUB w1_handler
SELECT @MESSAGE
CASE @IDCREATE
CENTERWINDOW w1
/* Initialize any controls here */
OldDialogProc = _SetWindowLong(w1.hwnd, GWL_WNDPROC, &DialogProc)
CASE @IDCLOSEWINDOW
salir=1
_SetWindowLong(w1.hwnd, GWL_WNDPROC, OldDialogProc)
CLOSEWINDOW w1
CASE @IDCONTROL
SELECT @CONTROLID
CASE BUTTON_1
IF @NOTIFYCODE = 0
/*button clicked*/
AddDataSetCLM(98,19,z,20)
ENDIF
ENDSELECT
ENDSELECT
RETURN
ENDSUB

SUB DialogProc(hWnd:INT,uMsg:INT,wParam:INT,lParam:INT),INT
SELECT uMsg
CASE msgCLMadddata
pointer first
mylist = ListCreate()
pointer gg
gg=lParam+0
first=ListAdd(mylist,gg)
pointer element
FOR element = EACH myList AS clmData
DEBUGPRINT "hhh"+str$(#element.datu)       '<---- prints the same pointer number
NEXT
pointer v1
v1=#element.datu
DEBUGPRINT "vvv"+str$(v1)                             '<---- prints the same pointer number
DEBUGPRINT STR$(#<clmData>v1[5].value1)    '<--- WRONG VALUE
ENDSELECT
RETURN _CallWindowProc(OldDialogProc,hWnd,uMsg,wParam,lParam)
ENDSUB

sub AddDataSetCLM(id:UINT,setnum:int,datsrc:clmData,cnt:int)
clmData p
p.setnum =setnum
p.cnt =cnt
DEBUGPRINT "z[5].value1= "+str$(datsrc[5].value1)                '<---prints proper value
p.datu = datsrc
DEBUGPRINT "pointer z: "+str$(p.datu)
pointer v
v=p.datu
DEBUGPRINT "z[5].value1= "+str$(#<clmData>v[5].value1)       '<---prints proper value
print ""

SENDMESSAGE w1,msgCLMadddata,0,&p
ENDSUB



the last value is ok.

LarryMc

Paul
  I installed the 2 changes you instructed me to make.
  Compiled and ran the program and I still have the exact same problem.
  When I try to print the in the PAINT handler I get trash even though the pointer to that data "appears" to be the same pointer that is saved in the addData routine.
I attached a screen shot.

fasecero
  thanks for the taking all the time to try and help me.
  However, you changed my typedef and thus removed the last step of coding
  And it's that step of coding that my problem shows it self.
  There is a type clmData and a type clm_Data.
  You moved the 3 elements of clm_Data into the clmData structure.
  That completely changes the program.

type clmData
   int    setnum
   uint  dat
   int    cnt
   pointer   datu
   int    dstyle
   uint  dcolor
   int    colorsrc
endtype

type clm_DATA
   double value1
   double value2
   uint dcolor
endtype





LarryMc
Larry McCaughn :)
Author of IWB+, Custom Button Designer library, Custom Chart Designer library, Snippet Manager, IWGrid control library, LM_Image control library

Ionic Wind Support Team

Larry,
I answered based on what you posted, since I don't have any code I can test.  I couldn't really figure out what you were doing, and why.

I was initially going to mention that local variables only exist while the subroutine is executing, but without the complete picture can't tell if this is the case here.  For example:

_SetWindowLong(hwnd, GWL_USERDATA, pc)

Where is pc defined?  What is it?  And why would you set it each time that message was received?

And then you are doing more confusing things.

v=#tData.datu
print "vvv",v
print #<clm_data>v[5].value1

Why copy a pointer to a pointer?  You could just do:

print #tdata.#<clm_data>data[5].value1

Then there are other factors, which again without seeing the entire code, makes it hard to debug.


sub AddDataSetCLM(win:WINDOW,id:UINT,setnum:int,datsrc:clm_data,cnt:int)
clmData p
p.setnum =setnum
p.cnt =cnt
print datsrc[5].value1 
p.datu = datsrc <------this is a pointer to the UDT passed to the subroutine


Since UDT's are passed by reference by default I wonder if you changed that UDT's contents somewhere along after sending it to AddDataSetCLM.  Bitten by a global variable?

So if you really want help debugging it, create a test program the smallest size you can make it that illustrates the problem, and post it here.  I'll be happy to compile it and give you a more definitive answer, and perhaps a better way to structure it as it seems overly complex for what you want to accomplish.

Paul.







Ionic Wind Support Team

LarryMc

That's fair enough.
It'll take me a while.

This is part of my custom chart control.
pc is a pointer that is stored in GWL_USERDATA for each chart.
it pionts to a structure that is created with NEW when WM_CREATE is triggered for each control.
It holds all the configuration data for that instance of the control.
Each time the message handler for the custom chart is called pc is loaded with that charts data.

AddData adds an array of data to the configuaration data, pc
I went the pointer/linked list path to avoid having to use a predefined array size (thus the pointer) for the datapoints and a chart can have more than one dataset (thus the need for the linked list; no max limit on number of datasets per chart)

When WM_PAINT is triggered I call a plot routine for each type of data.
The plot routine for functions is working great using the !template scheme but that uses &function to pass an UINT
The rest of the plots need an array of data.

when I call the plot routines I pass pc as a parameter.
I have no trouble retrieving the non-point values.

Anyway,  I'll see if I can get it stripped down.

Thanks for spending the time, as always.

Larry
LarryMc
Larry McCaughn :)
Author of IWB+, Custom Button Designer library, Custom Chart Designer library, Snippet Manager, IWGrid control library, LM_Image control library

LarryMc

Paul,
Attached is a REALLY stripped down version.

Thanks again for taking the time to look at it.

Larry
LarryMc
Larry McCaughn :)
Author of IWB+, Custom Button Designer library, Custom Chart Designer library, Snippet Manager, IWGrid control library, LM_Image control library

Ionic Wind Support Team


SUB d1_handler
   SELECT @MESSAGE
      CASE @IDINITDIALOG
clm_DATA z[21] <===LOCAL VARIABLE
int c
for c=0 to 20
z[c].value1=RAND(20)+0.0
z[c].value2=RAND(20)+0.0
z[c].dcolor=rand(0xffffff)
next c
AddDataSetCLM(d1,98,19,z,20,2,rgb(255,0,0),0)
      CASE @IDCLOSEWINDOW
         CLOSEDIALOG d1,@IDOK
   ENDSELECT
RETURN
ENDSUB


Larry,
Local variables only exist while the subroutine is executing.  Once @IDINITDIALOG returns then that array is invalid, and you are passing that array by reference.  You either need to use NEW and create the 'z' array or use a global.

All I did was move it like so and it worked:


clm_DATA z[21]
SUB d1_handler
   SELECT @MESSAGE
      CASE @IDINITDIALOG
'clm_DATA z[21]
int c
for c=0 to 20
z[c].value1=RAND(20)+0.0
z[c].value2=RAND(20)+0.0
z[c].dcolor=rand(0xffffff)
next c
AddDataSetCLM(d1,98,19,z,20,2,rgb(255,0,0),0)
      CASE @IDCLOSEWINDOW
         CLOSEDIALOG d1,@IDOK
   ENDSELECT
RETURN
ENDSUB


However I would handle it like so:


$include "windows.inc"

AUTODEFINE "OFF"
$main
type clmData
int setnum
uint dat
int cnt
pointer datu
int dstyle
uint dcolor
int colorsrc
endtype

type clm_DATA
double value1
double value2
uint dcolor
endtype

type CLMPARAMS
pointer slist
int datacnt
endtype

Declare import, InvalidateRect(hwnd:UINT, WINRECT:POINTER, bErase:INT),INT
DECLARE IMPORT,SendMessageA(hwnd as UINT,uMsg as UINT,wParam as UINT,lParam as UINT),UINT

/*******************************************************************************************
  start of demo
********************************************************************************************/
global z

const CLM_XY =4
openconsole
dialog d1
CREATEDIALOG d1,0, 0, 960, 640,0x80CA0880,0,"Graph Demo",&d1_handler
CreateCLM(d1,"Chart 2",330,10,300,300,CLM_XY,2,98 )
DOMODAL d1
closeconsole
end

SUB d1_handler
   SELECT @MESSAGE
      CASE @IDINITDIALOG
pointer pclm_DATA = new(clm_DATA,21)
settype pclm_DATA,clm_DATA
int c
for c=0 to 20
#pclm_DATA[c].value1=RAND(20)+0.0
#pclm_DATA[c].value2=RAND(20)+0.0
#pclm_DATA[c].dcolor=rand(0xffffff)
next c
AddDataSetCLM(d1,98,19,pclm_DATA,20,2,rgb(255,0,0),0)
      CASE @IDCLOSEWINDOW
         CLOSEDIALOG d1,@IDOK
   ENDSELECT
RETURN
ENDSUB

/*******************************************************************************************
  end of demo
********************************************************************************************/

EXTERN _hinstance as UINT
const CS_GLOBALCLASS  = 0x4000
const WM_USER = 0x400
const msgCLMaddData=0x400  /*WM_USER*/
Declare import, LoadCursor alias LoadCursorA(hInstance:INT, lpCursorName:POINTER),UINT

global ChartLM_atom
word ChartLM_atom : ChartLM_atom=0

sub RegisterChartLMClass()
if ChartLM_atom = 0
WNDCLASSEX wc
wc.cbSize        = len(WNDCLASSEX)
wc.style          = CS_GLOBALCLASS | CS_HREDRAW | CS_VREDRAW | CS_OWNDC
wc.lpfnWndProc    = &ChartLMProc
wc.cbClsExtra    = 0
wc.cbWndExtra    = 0
wc.hInstance      = _hinstance
wc.hIcon          = NULL
wc.hCursor      = LoadCursor(NULL, IDC_ARROW)
wc.hbrBackground = NULL
wc.lpszMenuName  = NULL
wc.lpszClassName = "ChartLM_Class"
wc.hIconSm        = NULL
ChartLM_atom =_RegisterClassEx(wc)
endif
endsub

sub ChartLMProc(hWnd:UINT, uMsg:UINT, wParam:UINT, lParam:ANYTYPE),UINT
PAINTSTRUCT ps
pointer pc
pc = _GetWindowLong(hWnd, GWL_USERDATA)

select umsg
case WM_CREATE
pc = new(char,len(CLMPARAMS))
         SETTYPE pc, CLMPARAMS
#pc.slist = ListCreate( )
_SetWindowLong(hwnd, GWL_USERDATA, pc)
return 0
      case WM_PAINT
_BeginPaint(hWnd, ps)
PlotXY(pc)
_EndPaint(hWnd, ps)
return 0
      case WM_ERASEBKGND
return 0
case msgCLMaddData
pointer tdata2,ptemp
tData2 = ListAdd(#pc.slist, NEW(clmData,1) )
ptemp = lparam+0
         #<clmData>tData2 = #<clmData>ptemp
_SetWindowLong(hwnd, GWL_USERDATA, pc)
InvalidateRect(hWnd, NULL, FALSE)

     case WM_DESTROY
FOR tempData = EACH #pc.slist AS INT
PRINT #tempData
#tempData += 5
NEXT
pointer tData
REM ADDED
FOR tData = EACH #pc.slist AS clmData
if #tData.datu then delete #tData.datu
NEXT
REM
ListRemoveAll(#pc.slist, TRUE)

delete pc
return 0
endselect
return(_DefWindowProc(hWnd, uMsg, wParam, lParam))
endsub

global sub CreateCLM(win as WINDOW,title as string ,l as INT,t as INT,w as int,h as int,charttype as INT, border as int, id as UINT )
RegisterChartLMClass()
CONTROLEX win,"ChartLM_Class",title,l,t,w,h,charttype|0x800000,WS_CLIPSIBLINGS,id
return
endsub

global sub AddDataSetCLM(win:WINDOW,id:UINT,setnum:int,datsrc:pointer,cnt:int,dstyle:int,dcolor:uint,colorsrc:int)
clmData p 'tried making this global but same result
p.setnum =setnum
p.dstyle =dstyle
p.dcolor =dcolor
p.datu = 0
print #<clm_Data>datsrc[5].value1,"        <--- value of 5th element of array that was passed in"
p.datu = datsrc
print "pointer ",p.datu,"       <--- value of stored pointer"
print p.#<clm_Data>datu[5].value1,"    <--- same as passed in value"   
SENDMESSAGE win,msgCLMadddata,0,&p,id
return
endsub

sub PlotXY(pc:pointer)
SETTYPE pc, CLMPARAMS
pointer tData=0

FOR tData = EACH #pc.slist AS clmData
     PRINT #tData.setnum, "  <-- correct value tells me the llist worked  "
     PRINT #tData.datu,"'print #tData.datu shows the same pointer value as above"
print #tdata.#<clm_data>datu[5].value1,"   <----WRONG VALUE"
next
return
endsub


Note that I delete the alloacted array in WM_DESTROY

Paul.

Paul.
Ionic Wind Support Team

LarryMc

Paul,
I hope you get as much satisfaction out of showing me how dumb I am as I get frustration out of spending hours trying to get something to work and have you fix it in moments. ;)

However, I have a big enough ego to know I'm not stupid and that it's really just how skilled you are.

Thanks again,

Larry
LarryMc
Larry McCaughn :)
Author of IWB+, Custom Button Designer library, Custom Chart Designer library, Snippet Manager, IWGrid control library, LM_Image control library

Ionic Wind Support Team

Larry,
Your welcome.

Just experience is all.  Programming for 30 years now has its advantages.  I became really good a debugging others code back in the 90's when I had to work with multiple programmers on large projects, usually can spot it by seeing the big picture ;)

My satisfaction comes from solving the problem, not by judging anyones skills as I have made many a dumb mistake in my time as well.  Some that took me days to solve and if I would have just walked away and slept on it I probably would have fixed them sooner.

Paul.

Ionic Wind Support Team