Welcome to MSDN Blogs Sign in | Join | Help

What did MakeProcInstance do?

MakeProcInstance doesn't do anything.

#define MakeProcInstance(lpProc,hInstance) (lpProc)

What's the point of a macro that doesn't do anything?

It did something back in 16-bit Windows.

Recall that in 16-bit Windows, the HINSTANCE was the mechanism for identifying a data segment; i.e., a bunch of memory that represents the set of variables in use by a module. If you had two copies of Notepad running, there was one copy of the code but two sets of variables (one for each copy). It is the second set of variables that establishes the second copy of Notepad.

When you set up a callback function, such as a window procedure, the callback function needs to know which set of variables it's being called for. For example, if one copy of Notepad calls EnumFonts and passes a callback function, the function needs to know which copy of Notepad it is running in so that it can access the correct set of variables. That's what the MakeProcInstance function was for.

The parameters to MakeProcInstance are a function pointer and an instance handle. the MakeProcInstance function generated code on the fly which set the data segment register equal to the instance handle and then jumped to the original function pointer. The return value of MakeProcInstance is a pointer to that dynamically-generated code fragment (known as a thunk), and you used that code fragment as the function pointer whenever you needed another function to call you back. That way, when your function was called, its variables were properly set up. When you no longer needed the code fragment, you freed it with the FreeProcInstance function.

Those who have worked with ATL have seen this sort of code fragment generation already in the CStdCallThunk class. The operation is entirely analogous with MakeProcInstance. You initialize the CStdCallThunk with a function pointer and a this parameter, and it generates code on the fly which converts a static function into a C++ member function by setting the this pointer before calling the function you used to initialize the thunk.

The creation of these code fragments on 16-bit Windows had to be done by the kernel because the 8086 processor did not have a memory management unit. There was no indirection through a translation table; all addresses were physical. As a result, if the memory manager had to move memory around, it also had to know where all the references to the moved memory were kept so it can update the pointers. If a data segment moved, the kernel had to go fix up all the MakeProcInstance thunks so that they used the new instance handle instead of the old one.

It was Michael Geary who discovered that all this MakeProcInstance work was unnecessary. If the callback function resided in a DLL, then the function could hard-code its instance handle and just load it at the start of the function; this technique ultimately became known as __loadds. Since DLLs were single-instance, the DLL already knew which set of variables it was supposed to use since there was only one set of DLL variables to begin with! (Of course, the hard-coded value had to be recorded as a fix-up since the instance handle is determined at run time. Plus the kernel needed to know which values to update if the instance handle changed values.) On the other hand, if the callback function resided in an executable, then it could obtain its instance handle from the stack selector; this technique ultimately became known as __export. Each program ran on a single stack (no multi-threading here), and the stack, data segment, and local heap all resided in the same selector by convention. And in a strange bit of coming full circle which I discovered as I wrote up this reminiscence, Michael Geary's copy of the original readme for his FixDS program that brought this technique to the public contains an introduction which links back to me...

Published Thursday, February 07, 2008 7:00 AM by oldnewthing
Filed under:

Comments

# re: What did MakeProcInstance do?

Thursday, February 07, 2008 12:17 PM by Dave

In DOS, there were lots of different segment models (tiny, small, medium, large, huge). Maybe Windows standardized on SS==DS after MakeProcInstance was created, or the design was trying to leave open the possibility of supporting the large/huge memory models? It's all a distant nightmare and I try not to think about it.

# re: What did MakeProcInstance do?

Thursday, February 07, 2008 1:05 PM by hito

I'm glad I hadn't write code in such old days.

I didn't even know what MakeProcInstance is or it exist.

# re: What did MakeProcInstance do?

Thursday, February 07, 2008 5:36 PM by RaduS

I seem to remember there were some special cases where callbacks were being called with a SS of a different "process", so care had to be taken in those cases not to use the too smart methods.

One of those callbacks was a notification fired when a particular block of memory was discarded; it was being called with the SS of the process that allocated some memory and forced the discarding..

Lots of fun..

# re: What did MakeProcInstance do?

Thursday, February 07, 2008 5:47 PM by steveg

I'd like to call those the "good ol' days", but in many ways Win 3.x programming was a pain in the butt (where 3.1 was light years better than 3.0 due its much stronger API parameter checking in the debug build). It was not particularly forgiving (eg BSODs, UAEs, and the need to regularly reinstall the O/S etc).

You wouldn't recognise the compiler/IDE scene if you have only used recent versions of Visual Studio. Microsoft's IDE was... well you wouldn't, if you could use the alternative (can I say Borland?).

And they came with manuals! API documentation in paper -- the best way to learn the API, flick through it while waiting for a compile to grind its way through.

The coolest things about those days, sadly no longer supported, was the ability to have a 2nd monitor plugged in, generally run off a Hercules card. I kind of miss the soft amber (or green) phospher glow of a text-only monitor.

So if any of you youngsters hear an old fart talk about how much better it was programming for Win3.x. Ignore them. They're lying.

# re: What did MakeProcInstance do?

Thursday, February 07, 2008 6:14 PM by David Walker

Which reminds me...

Why do DLLs have a "preferred" load address?  

Why can't each DLL just be loaded into the next contiguous block of virtual memory that's big enough for it?

# re: What did MakeProcInstance do?

Thursday, February 07, 2008 6:19 PM by David Walker

That's a really interesting link of Michael Geary's that you pointed to.  Fascinating stuff.

# re: What did MakeProcInstance do?

Thursday, February 07, 2008 6:28 PM by Jules

@Dave: "Maybe Windows standardized on SS==DS after MakeProcInstance was created, or the design was trying to leave open the possibility of supporting the large/huge memory models?"

As I recall, the large & huge models were supported.  However, even MakeProcInstance couldn't support them fully (how does it know _which_ data segment to load?), so the general rule was that applications with those memory models forewent the standard function prolog code and loaded their own DS values, thus requiring them to only allow one instance to run at a time.

# re: What did MakeProcInstance do?

Thursday, February 07, 2008 6:29 PM by Yuhong Bao

>this technique ultimately became known as __export.

__export was originally for DLLs who want to export functions, not for this.

>If the callback function resided in a DLL, then the function could hard-code its instance handle and just load it at the start of the function; this technique ultimately became known as __loadds.

I think that was before FixDS.

# re: What did MakeProcInstance do?

Thursday, February 07, 2008 6:33 PM by Jules

@David Walker: "Why do DLLs have a "preferred" load address?  Why can't each DLL just be loaded into the next contiguous block of virtual memory that's big enough for it?"

It's an optimization.  Applications are linked against the DLLs with the assumption they'll be loaded at their preferred address.  That way, if the preferred address is available, no extra work is required at load time.     It also means pages with imported addresses stored in them can be reloaded from the executable file, rather than needing to be flushed to the paging file, if they need to be paged out.

# I always think about...

Thursday, February 07, 2008 6:44 PM by Igor Levicki

What would world be like if DLLs didn't exist?

# re: What did MakeProcInstance do?

Thursday, February 07, 2008 7:53 PM by Yuhong Bao

>Applications are linked against the DLLs with the assumption they'll be loaded at their preferred address.

BTW, DOS EXEs work in a similar way, only that the preferred address is 0000:0000. DOS EXEs have a fixup table that fixes up segment values to reflect the new base address.

# re: What did MakeProcInstance do?

Thursday, February 07, 2008 8:50 PM by oj

Like the current definition of MakeProcInstance, this posting is... pointless!

Thanks for reminding us old-timers how 80% of our careers in this industry have been learning about stuff that became totally obsolete.

I guess with the future as bleak as it is for the WinUser team, you might as well just endulge in nostalgia. Ah, glory days! (...ignoring the trail of nasty legacies they left for us along the way, that is!).

.manifest

# re: What did MakeProcInstance do?

Thursday, February 07, 2008 11:53 PM by Michael Geary

Raymond, thanks for the kind mention! This was truly a blast from the past.

You know, I had almost managed to forget MakeProcInstance and FixDS. Now it will be with me for another 20 years! :-)

@RaduS: "I seem to remember there were some special cases where callbacks were being called with a SS of a different 'process', so care had to be taken in those cases not to use the too smart methods."

Probably true, but those weren't an issue with FixDS. It was used only for ordinary application code where you were already relying on the fact that SS == DS, because you were compiling your code with a switch that said "Assume that SS == DS". If you used that switch when SS and DS were not the same, your code was already broken. FixDS wouldn't break it any worse. If it was safe to compile with that switch, then by definition it was also safe to use the FixDS technique.

Glad I'm coding in JavaScript, Ruby, and Python these days... :-) http://maps.google.com/decision2008

# re: What did MakeProcInstance do?

Friday, February 08, 2008 10:47 AM by David Walker

Loading each DLL at its preferred address, instead of loading them all contiguous to each other, means that virtual memory is fragmented.  Not that that's a bad thing necessarily.  Perhaps it doesn't matter.

# re: What did MakeProcInstance do?

Friday, February 08, 2008 11:34 AM by Kevin Eshbach

This is one skeleton in the closet that should have never been let out.  Programming Win16 (and DOS) apps was a pain in the you know what.  I'm glad those days are gone.

New Comments to this post are disabled
 
Page view tracker