t-benw@microsoft.UUCP (Benjamin Waldmin) (08/19/88)
Does anyone out there have a suggestion for sharing data between a cdev and a patch installed as an INIT? To be more precise, I have a cdev which a user uses to set options which change the behavior of an INIT. For example, in a screen saver, the user sets the time until screen blanking in the control panel, and then the screen saver (presumably an INIT which patched a trap) changes its behavior accordingly. So, the problem is: how does the cdev know where to put the data so that the INIT can find it, or how does the INIT know where the cdev put the data? The cdev can either put data in some block or change the patch that the INIT has installed, but there's no way for the cdev to find the patch either (using GetTrapAddress won't work, since another patch may have been installed on top of mine). I've thought of allocating space for the variables (in the system heap) when the INIT is loaded, then saving the address of this space in a resource on the disk, and having the cdev read this resource. The problem with this is that I have to write to disk, which I'd prefer not to do (What if the user has the disk locked - then the cdev crashes, since the address it reads from disk will br bogus). Alternatively, I could have the cdev try to find the patch in the system heap (looking for a certain byte pattern to identify it). The problem with this is that I can't just traverse blocks in the heap to look for my block, since I can't assume memory manager data structure formats, since Apple says not to (I don't know why - I can't imagine Apple changing these). Thus, I'd have to look through every byte in the heap, which would be slow. So, after all this, does anyone have any suggestions? Thanks a lot in advance! Ben Waldman uw-beaver!microsoft!t-benw
lsr@Apple.COM (Larry Rosenstein) (08/19/88)
In article <1739@microsoft.UUCP> t-benw@microsoft.uucp (Benjamin Waldman) writes: >Does anyone out there have a suggestion for sharing data between a cdev >and a patch installed as an INIT? Here's what I have done in my cdevs that have INITs. First, I keep configuration information in a resource in the file. When the INIT installs itself, it copies this information into the system heap. The INIT saves the address of the data (eg, a handle) in some well-defined place. (Generally, I reserve a few bytes of storage in the same heap block containing the installed code.) I also had the INIT installer record in a special resource, where the INIT was installed. The cdev can then read this resource, locate the INIT, and read/set its configuration. I also have the INIT leave some 4-byte ID around in memory. The cdev checks this to ensure that the address it has is valid. (You could increase this to 8-bytes for extra insurance.) The cdev needs to at least change the configuration resource stored in the file. If it can locate the installed INIT in RAM, then it cal also change the configuration in RAM, which will cause changes to take effect immediately. If the cdev can't locate the INIT in RAM (because it hasn't been installed, or the special ID wasn't located), then changes will take effect when you reboot, andI added a little message to that effect in the cdev window. This does require that the INIT be able to write to the disk, which means the modification date on the file changes each time you boot. If the disk is write-protected, then the INIT won't be able to record its location in RAM. In some cases, the INIT would be installed in the same spot as last time, so the cdev will still be able to locate it. Otherwise, configuration changes won't take effect immediately. (If the disk is always write-protected, then there is no way to save any configuration changes.) I wouldn't try to scan through the system heap for the reasons you mentioned. An alternative is to make configuration changes take effect when you reboot. This is easy to implement, since the cdev doesn't have to do anything with the INIT, but it is inconvenient for the user. You could also use a shared configuration file. The cdev can easily modify that file, but the INIT would have to periodically check to see if it has changed. (You could watch for changes in modification dates.) Larry Rosenstein, Object Specialist Apple Computer, Inc. 20525 Mariani Ave, MS 46-B Cupertino, CA 95014 AppleLink:Rosenstein1 domain:lsr@Apple.COM UUCP:{sun,voder,nsc,decwrl}!apple!lsr
t-benw@microsoft.UUCP (Benjamin Waldmin) (08/20/88)
In article <15808@apple.Apple.COM> lsr@apple.com.UUCP (Larry Rosenstein) writes: >In article <1739@microsoft.UUCP> t-benw@microsoft.uucp (I) wrote: >>Does anyone out there have a suggestion for sharing data between a cdev >>and a patch installed as an INIT? > >Here's what I have done in my cdevs that have INITs. > >First, I keep configuration information in a resource in the file. When the >INIT installs itself, it copies this information into the system heap. >The INIT saves the address of the data (eg, a handle) in some well-defined >place. (Generally, I reserve a few bytes of storage in the same heap block >containing the installed code.) > >I also had the INIT installer record in a special resource, where the INIT >was installed. The cdev can then read this resource, locate the INIT, and >read/set its configuration. I also have the INIT leave some 4-byte ID >around in memory. The cdev checks this to ensure that the address it has is >valid. (You could increase this to 8-bytes for extra insurance.) The problem with this is that the INIT has to write to disk at startup time, which I'd rather not do. Actually, I've found a rather neat solution -- the device manager!! I create a device driver. In response to the open call, it patches the trap I want to patch (and I open the driver at startup, in an INIT). In response to a status call, I return the address of my variables that I want the cdev to access. The only trick part is for the cdev to figure out the refnum of the driver. But Apple has already solved that problem - they tell you how to do this in Tech note #71. Unfortunately, there's one problem - Think C 3.0!!! My driver has to be in the system heap, so it can stay alive all the time. But while THINK C lets you set the resource flags for a code resource, it doesn't let you do this for a driver. So every time, after building the driver, I have to start ResEdit, and set the system heap bit. But, wait, it gets worse. Think C lets you have global data in your drivers by allocating a block in the heap for you, locking it, pointing A4 to it, and referencing your globals off of A4. But my data has to be in the system heap!!! So, in my open routine, I have to allocate another block, in the system heap this time, copy my globals from where Think C put them, and point A4 to my globals. (Actually, I store the handle somewhere in my code, and when my trap patch is called, I get the handle from this location, lock it, dereference it, and set A4 to the dereference). There's still one problem, however. Think C locks the handle that IT allocated every time my driver is called. Suppose I call my driver later on, after the application heap has been reinitialized (which is OK, since my driver is in the system heap). The handle that THINK C allocated is no longer valid. I wonder if THINK C's driver glue will check the return value of its call to HLock, and what it will do after this. If it just calls me blindly anyway, it's fine, since I'll just unlock Think C's handle and return. Otherwise, I don't know what will happen. Things are complicated further by the fact that that old handle may still point to a valid block (someone else's), or may not point to anything at all. #include <LSC_is_so_great_I_could_just_die.h> Yes, I really do like LSC, but I really think that this is a severe flaw. I suppose what I really should do is hack through Think C's driver glue, find their newhandle call, and change some bits so that it allocates a block in the system heap for the global data rather than the application heap. Rich, could you be of any help here? Is there some magic word I could change in THINK C so that the newhandle call is done to allocate a block in the system heap? Also, will version 3.1 let us keep drivers in the system heap? Thanks, Ben Waldman Software Design Engineer, Microsoft Corp. Disclaimer: These are my own thoughts, opinions, and ideas, and in no way represent the views of my employer.
joachim@iraul1.ira.uka.de (Joachim Lindenberg) (08/20/88)
In article <1739@microsoft.UUCP> t-benw@microsoft.uucp (Benjamin Waldman) writes: >Does anyone out there have a suggestion for sharing data between a cdev >and a patch installed as an INIT? > Use the INIT to load a driver which does the actual work. The driver may use a handle stored in its DCtlEntry to hold its variables. The cdev will have to scan the unit table for the driver and use the same handle. Joachim
castan@munnari.oz (Jason Castan) (08/22/88)
In article <1745@microsoft.UUCP>, t-benw@microsoft.UUCP (Benjamin Waldmin) writes: > Actually, I've found a rather neat solution -- the device manager!! > > I create a device driver. In response to the open call, it patches the trap > I want to patch (and I open the driver at startup, in an INIT). In response > to a status call, I return the address of my variables that I want the > cdev to access. The only trick part is for the cdev to figure out the refnum > of the driver. But Apple has already solved that problem - they tell you > how to do this in Tech note #71. > > But, wait, it gets worse. Think C lets you have global data in your > drivers by allocating a block in the heap for you, locking it, pointing > A4 to it, and referencing your globals off of A4. But my data has to > be in the system heap!!! So, in my open routine, I have to allocate > another block, in the system heap this time, copy my globals from where > Think C put them, and point A4 to my globals. (Actually, I store the > handle somewhere in my code, and when my trap patch is called, I get > the handle from this location, lock it, dereference it, and set A4 to > the dereference). > You are doing the same algorithm that moire uses except that i use a control call to modify moire's behaviour. To make Think C allocate your globals in the system heap, just set the system heap bit for your DATA -16000 resource ! Yes, i agree its a flaw that Think C doesnt allow easy handling of resources. I just got 3.0 today :-) and had to reconcile myself that i wont be able to use its debugger with moire ;-( because of its design. However under multifinder, its a trivial thing to write a program that modifies all the bits to load the DRVR and DATA rez's to the system heap. For a solution involving less code and more hack to inter-process communication, try patching an uncommonly used trap like DebugStr(). Set your INIT to patch DebugStr(). When you want to communicate with the INIT, save ToolScratch (or CurApName) and put a signature in the low mem global. DebugStr checks the low mem global, sees that it's actually a message for the INIT, and the stringPtr passed is actually the message. DebugStr merely returns after processing the message. if the signature is not valid, call the real trap. On return from DebugStr, restore the old value of the global. I just thought of this today actually while working on another problem. I like it a whole lot, and should be reliable if you choose a good signature (if ShowInit does it, so can i !). > Thanks, > > Ben Waldman > Software Design Engineer, > Microsoft Corp. > Hope this helps, John Lim ps : cant help but give another plug for Think C 3.0. Great work ! Cant wait for the bugs to sprout out of the screen so i can squash them...
anson@spray.CalComp.COM (Ed Anson) (08/23/88)
In article <1745@microsoft.UUCP> t-benw@microsoft.uucp (Benjamin Waldman) writes: >But, wait, it gets worse. Think C lets you have global data in your >drivers by allocating a block in the heap for you, locking it, pointing >A4 to it, and referencing your globals off of A4. But my data has to >be in the system heap!!! When you allocate globals for a driver, they are stored in a DATA resource. You could try just setting the System bit for that resource. It may solve your problem. Im not sure, but it looks like LSC is using GetResource, not NewHandle. -- ===================================================================== Ed Anson, Calcomp Display Products Division, Hudson NH 03051 (603) 885-8712, anson@elrond.CalComp.COM
t-benw@microsoft.UUCP (Benjamin Waldmin) (08/24/88)
In article <2413@spray.CalComp.COM> anson@spray.UUCP (Ed Anson) writes: >In article <1745@microsoft.UUCP> t-benw@microsoft.uucp (Benjamin Waldman) writes: >>But, wait, it gets worse. Think C lets you have global data in your >>drivers by allocating a block in the heap for you, locking it, pointing >>A4 to it, and referencing your globals off of A4. But my data has to >>be in the system heap!!! > >When you allocate globals for a driver, they are stored in a DATA resource. >You could try just setting the System bit for that resource. It may solve >your problem. > >Im not sure, but it looks like LSC is using GetResource, not NewHandle. Actually, someone from THINK mailed me a neat suggestion (the day after my posting - how's that for customer service!). Since my driver is being opened by an INIT, I can just save the current zone, set the zone to be the system heap, and open my driver. Since the system heap will be the current zone when the driver is opened, both it and its data will be in the system heap. Finally I restore the old zone. Since I do want to keep the driver in memory though, and not close it when the INIT is closed, I do a GetResource('DRVR',theID), OpenDriver(...), and a DetachResource. Still though, if I wasn't opening the driver at INIT time, I'd have to go and manually set the bits with ResEdit every time I rebuilt the driver, which is a pain. I guess this is just a small oversight on THINK's part, which, one hopes, will be corrected in the next release. Ben Waldman Software Design Engineer, Microsoft Corp. Disclaimer: These are my thoughts, opinions, and ideas only, and do not reflect those of my employer in any way.
jmunkki@santra.HUT.FI (Juri Munkki) (08/26/88)
In <1745@microsoft.UUCP> t-benw@microsoft.uucp (Benjamin Waldman) writes: >The problem with this is that the INIT has to write to disk at startup >time, which I'd rather not do. Right... I did this by looking at memory manager structures the way that is suggested in the QuicKeys manual. >Actually, I've found a rather neat solution -- the device manager!! I think this is a better solution than the method I use. I haven't read TN#71, so there are some points I do not understand. How about some code fragments? >Unfortunately, there's one problem - Think C 3.0!!! >My driver has to be in the system heap, so it can stay alive all the time. >But while THINK C lets you set the resource flags for a code resource, it >doesn't let you do this for a driver. So every time, after building the >driver, I have to start ResEdit, and set the system heap bit. Ok. I had the same problem when building an INIT with LSC 2.15. That's why I wrote a small Fixer program to do the job. It also does some other things, but that's the reason I wrote it for. I posted it here a few months ago and it has been archived at least at macserve@pucc (BITNET). >But, wait, it gets worse. Think C lets you have global data in your >drivers by allocating a block in the heap for you, locking it, pointing >A4 to it, and referencing your globals off of A4. But my data has to >be in the system heap!!! So, in my open routine, I have to allocate >another block, in the system heap this time, copy my globals from where >Think C put them, and point A4 to my globals. (Actually, I store the >There's still one problem, however. Think C locks the handle that IT >allocated every time my driver is called. Suppose I call my driver >later on, after the application heap has been reinitialized (which is >OK, since my driver is in the system heap). The handle that THINK C >allocated is no longer valid. I wonder if THINK C's driver Since you open your driver from an INIT, you can simply set the current zone to the system heap. This will most probably make LSC allocate your variables from the system heap. I haven't tried this exactly, but I set the current zone in my INIT before I allocate some buffers & stuff and it works fine. I couldn't figure out how to make LSC allocate system heap blocks otherwise. When the driver returns, restore the correct heap zone. (You have to get it, change it, open your driver and restore the zone). I hope this works. Please try to write a document & post it. Juri Munkki jmunkki@santra.hut.fi jmunkki@fingate.bitnet