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
it's complicated, lparam seems to be a clmData, maybe replacing:
#<clmData>tData2 = ##<clmData>lparam
with
#<clmData>tData2 = lparam
not sure at all.
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
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.
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
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.
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
Paul,
Attached is a REALLY stripped down version.
Thanks again for taking the time to look at it.
Larry
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.
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
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.