Software Archive
Read-only legacy content
17061 Discussions

Pointers on pointers (or any other way :-) ) to access structure given address

dpbozarth
Beginner
1,136 Views
Many Win32 APIs return an integer handle to astructure rather
than passing the structure itself. For example, consider the structure
PRINTDLG (for the printer dialog box). When PrintDlg returns, element pd%hDevNames contains the location of a DEVNAMES
structure. Then in a DEVNAMES structure, there are offsets to C-strings containing the information on the printer itself. For example, if define TYPE (DEVNAMES) dn, then element dn%wDeviceOffset is the offset from the origin of dn to the beginning of the string containing the printer name.

Now, the question: I have the address (as INTEGER*4) of the internally assigned buffer in pd%hDevNames of the origin of the DEVNAMES structure. How can I use that to get at the values of the members of the structure and subsequently to the actual data strings?

I've been away from FORTRAN (except for pure computation that doesn't require anything fancy) for years (actually almost all coding, not just FORTRAN) and am having no success in figuring out the syntax req'd....any help greatly appreciated....
0 Kudos
8 Replies
Steven_L_Intel1
Employee
1,136 Views
You posted the same question in the comp.lang.fortran newsgroup, where I just answered it. I didn't know what compiler you were using, so my answer was somewhat generic. Here it is, with more detail...

That's because standard Fortran doesn't have the feature you're
looking for. An extension supported by many compilers, including
Compaq Visual Fortran, is known by the name "integer POINTER" or "Cray
Pointer". (In the Compaq Fortran Language Reference Manual, it's
documented in section B.11)

The syntax is as follows:

POINTER (P,R)

where P is an INTEGER variable of the appropriate size to hold an
address. This declaration states that when R is accessed (R can be
most any type of variable), its location is taken from the contents of
P. A caveat is that this form of POINTER cannot be used in a derived
type declaration.

The way you would use it is something like this:
	TYPE (T_PRINTDLG) pd
	TYPE (T_DEVNAMES) MyDevNames
	POINTER (pDevNames, MyDevNames)
	...
	! assume pd has a PRINTDLG structure
	!
	pDevNames = pd%hDevNames
	!
	! Now MyDevNames is a DEVNAMES structure


Steve
0 Kudos
Jugoslav_Dujic
Valued Contributor II
1,136 Views
Hi,
There are so-called "Cray" or "integer" pointers which do
the task you want. Integer pointers are, strictly speaking,
non-standard (though I think that most modern compilers
support them, and they are in F2000 draft). Cray pointer
consists of two parts: pointer variable (of type integer -
more strictly, of type "address") and pointed-to variable
(of any type). The declaration is as follows:

TYPE(T_DEVMODE):: DM !Pointed-to variable

POINTER(pDM,DM) !pDM is integer pointer

The initial address of DM is undefined (NULL). DM gets
its address whenever pDM receives a value in valid
address range. This declaration is similar to C's:

DEVMODE* pDM = NULL;

This enables you to define a sort of more flexible EQUIVALENCE.
So, you'll need something like:

TYPE(T_PRINTDLG):: PDialog


TYPE(T_DEVNAMES):: DN; POINTER(pDN,DN)


CHARACTER*64:: szPrinter; POINTER(pszPrinter,szPrinter)



...

pDN=GlobalLock(PDialog%hDevNames)


pszPrinter=pDN+DN%wDeviceOffset


WRITE(*,*) szPrinter



(Note: hDevNames is _not_ address of DEVNAMES, but handle of memory
that should be dereferenced using GlobalLock and _allocated_ using
GlobalAlloc before PrintDlg is invoked).
Btw, regarding the PrintDlg and DEVNAMES, this would require a lot
of acrobacy if you _really_ ought to have printer names on disposal.
PrintDlg is supposed to be kind of "plug'n'play": call PrintDlg and get
printer PD%hDC back, while hDevMode and hDevNames should be NULL if
your sole goal is to get something printed. I have a sample
with application-defined "Print" dialog so I can send it if you want.
In another app, where I just want to print something, it's just:

PD%lStructSize = 66


PD%hDevMode = NULL


PD%hDevNames = NULL


PD%Flags = PD_RETURNDC


PD%hwndOwner = hFrame


PD%hDC = NULL


PD%nFromPage = 1


PD%nToPage = 1


PD%nMinPage = 0


PD%nMaxPage = 0


PD%nCopies = 1


PD%hInstance = NULL


PD%lCustData = 0


PD%lpfnPrintHook = NULL


PD%lpfnSetupHook = NULL


PD%lpPrintTemplateName = NULL


PD%lpSetupTemplateName = NULL


PD%hPrintTemplate = NULL


PD%hSetupTemplate = NULL



bSt=PrintDlg(PD)



IF (bSt) THEN


CALL PrintPlacement(PD%hDC)



Regards
Jugoslav
jdujic@uns.ns.ac.yu
0 Kudos
dpbozarth
Beginner
1,136 Views
Hi, Jugoslav....thanks for the in depth reply....you pointed out something I misinterpreted from the SDK docs....I THOUGHT it implied if hDevNames is input as NULL, then PrintDlg would allocate the memory for it and the handle returned was the address.....I'm obviously not a W-doze programmer, so I stand to be corrected....and, since I'm not getting the data back, obviously I'm not doing it right, yet...

All I really want to use PrintDlg for is with the PD_RETURNDEFAULT flag set to return the current default printer string so I can dynamically access that from a command line utility irrespective of whether I'm working on my home LAN, the company LAN, or my local laptop. These all have different configurations but have in common Postscript printers. Unfortunately, Windows doesn't like D&D of plain text files and I've not found a windows print utility that I like for source files, so I still use the existing DOS tools. In investigating the way various Windows platforms store the default printer in the registry, I discovered not only is it different between platforms (W95/NT/W98/...), but even two NT or W95 machines don't have the same keys so I was not able to find a way to query the registry that was not machine specific......how this works for Windows apps on these machines, I have no idea, but as I said I'm not a Windows programmer...
Anyway to make a long story short, PrintDlg was the only API I found that seemed to be nearly independent across platforms....

Given that as my objective, can you amplify just slightly on the allocation/deallocation of hDevNames a bit? I follow the gist of your comment (it ISN"T the actual address, just a handle), but I'm not quite up to speed on how to actually access it correctly....I'll study your sample code some more...

Thanks greatly for the response....maybe there's still hope..
0 Kudos
dpbozarth
Beginner
1,136 Views
Yes, thanks, Steve.....I did post on c.l.f as I thought I might get a few more viewpoints as well and I wasn't sure whether this qualified as a CVF question even though I'm using CVF....and, also, BTW, because the newsgroup format is so much easier than this forum to use.....as I know you tend to agree from reading some of the earlier thread on the new format!! :-)

Anyway, the essence of my reply there was "thanks, that's a big help getting started but...". Jugoslav posted here some code here in reply to my post I've got to study more as it may (and probably does) hold the key to my "but...". I responded to him (although I'm not sure this forum keeps thread sublevels?) asking for some more amplification on what the Windows handle really means and how to properly access it as I interpreted the returned handle as being the actual address if PrintDlg was passed pd%hDevNames a NULL value....I got that from my reading of the SDK help files for PrintDlg, but I may have interpreted it incorrectly.....as I'm not getting reasonable values under that assumption, it is probably the wrong one :-) ! I think the problem now revolves around how to use the Windows API correctly as much as the FORTRAN syntax, but I still am not quite sure how to most appropriately address the string itself once I do get the right memory addressed....any further light you can shed would be most appreciated.....
0 Kudos
Steven_L_Intel1
Employee
1,136 Views
I suggest you look at the Fortran_WinPrint example. It does some of what you're asking about. In particular, look at the treatment of the DEVMODE structure.

Steve
0 Kudos
dpbozarth
Beginner
1,136 Views
Steve/Jugoslav----Eureka! The last pointer about the handle not being the actual pointer was the final breakthrough, Jugoslav...thanks for thinking to point that out!

I have now two remaining points of non-understanding either/both may feel free to expound upon or ignore as the mood strikes....

First, is given that "Cray" pointers work this way which seems perfectly logical to me, what is the point of F90/95 pointers? It seems the standard should be able to accomplish the same thing, but I could figure no way out of type mismatches....am I missing something obvious here?

Second, I'm still looking for a more elegant way to allocate the memory for the ultimate string referenced by the pointer+offset other than simply allocating a buffer hopefully large enough for all time. Specifically, is there a clean way to determine the length of the szString and allocating the correct length string?

Thanks again to both....Duane
0 Kudos
Steven_L_Intel1
Employee
1,136 Views
Standard pointers deal with objects entirely inside Fortran, and also include shape and stride information for arrays.

Steve
0 Kudos
Jugoslav_Dujic
Valued Contributor II
1,136 Views

Hi Duane,


I also find printer management under Windoze unnecesarilly complicated. Apparently, that part was pretty much patched since Win3.x times. Well...

The default printer name is stored in win.ini in all windoze OSs ("logical", isn't it?) and name of the default printer can be retrieved simply using

 
CHARACTER*64::    szDefPrinter 
iSt=GetProfileString('windows'c,'device'c,sTemp,szDefPrinter,64) 

(as noted in SDK help on EnumPrinters)

I think that would be sufficient for the purpose you want; I did not work with allocation of PrintDlg%hDevNames, so I don't know whether it would be sufficient to GlobalAlloc only to SIZEOF(DEVNAMES)=16 or there should be more space for name buffers.

Printing can be done without invoking PrintDlg using EnumPrinters, OpenPrinter, ClosePrinter, DocumentProperties and CreateDC functions.
DEVMODE structure stores all printer settings necessary for printing;
it should be passed to CreateDC in order to obtain printer DC ("canvas")
handle, and then use GDI functions (TextOut, Rectangle, etc.) to draw on
it. DEVMODE, however, has special treatment: its first part is as described in SDK, and it is followed by a series of printer-dependent settings. Calling DocumentProperties with argument fMode=0 retrieves the actual number of bytes required for DEVMODE for the current printer; thus, one have to "EQUIVALENCE" DEVMODE and a larger BYTE or CHARACTER using "Cray"
pointers.

I apologize for extra information, but the topic is far from simple and really requires a lot of discussion... Feel free to write me at jdujic@uns.ns.ac.yu if you need some extra information or samples on that topic (I spent a lot of time making a custom print dialog work properly :-(, so I deem myself experienced enough).

Regards

Jugoslav
0 Kudos
Reply