Thought as much...
Ah, yes, that's Hutch's automatic utility I was mentioning, I do believe...
Basically, yes...
TASM is slightly less fussy because it doesn't even bother with the
parameters it takes...for example, inside "import32.lib", you'd find
just "ExitProcess", whereas MASM calls it something like
"_ExitProcess@4"...although, despite the ugly syntax, MASM offers an
improvement on TASM here because it'll also allow you to type "call
__imp__ExitProcess@4", which links in a more direct and faster way
than TASM (or MASM using "call _ExitProcess@4") does...this more
"direct" version actually makes an indirect call - assembled to
something like "call [420000h]" - whereas the less direct way
assembles to "call 42000h" and, at the address it calls (420000h),
there's a "JMP" statement which makes the actual final jump to the DLL
function...
The need for this weirdness is because, at compile-time and link-time,
it cannot know the final run-time addresses of the DLLs (the addresses
will be different for different versions of the DLL...plus, DLLs can
be relocated to different places in memory that it's not possible to
"hard-wire" exact addresses into your final code

...so the code is
assembled to make calls to an "import address table"...the actual
Windows loader then fills out this table with the DLL run-time
addresses when the module (DLL or EXE) is loaded...the headers for
your executable will be filled in by the linker with the names of the
DLLs and DLL functions you need, which the loader reads so as to know
exactly what addresses you want put into the "import address table"
(IAT for short)...
With MASM's "direct" method, it makes an indirect call via the
addresses stored in the IAT ("call [ 420000h ]" grabbing the address
stored at 420000h - where the IAT starts in my example here - and then
calls the DLL function directly)...with TASM and MASM when you're not
using the more "direct" method of calling functions, the assembled
instruction looks more like "call 420000h"...and every DLL function is
actually NOT called directly but is called _via_ the "Import Address
Table"...inside the IAT, in fact, you'd find a series of "JMP"
instructions and this is what is actually called by your
program...though the "JMP" instructions, of course, doesn't effect the
return address on the stack which the "CALL" instruction made so it'll
"JuMP" to the DLL function and when that function issues "RET", it
correctly returns back to your program...
This is somewhat complicated, granted, but, really, there's little
choice about doing it this way...because, as DLLs can have different
versions where the same functions could be at different addresses
(e.g. Windows XP's KERNEL32.DLL has been modified and improved on
Windows 95's KERNEL32.DLL...the XP version still has all the same
basic functions in it but they've been changed, improved or extra
functions added

...and, also, DLLs can be "relocated" in memory too
(e.g. one DLL is loaded at 800000h and then another DLL asks to be
loaded into the same location...well, this is not possible because the
other DLL is there...so, the loader simply uses the relocation
information in the DLL and moves it elsewhere in memory...which, by
the way, is why you _should_ have relocation information attached for
DLLs but you _DON'T_ strictly need relocation information for an EXE
because every EXE gets its own address space and, thus, by definition,
every EXE _will_ get its chosen base address...the only exception to
this was "WIN32S" which was an extension that MS added to Windows 3.x
to make it able to run some Win32 programs...I'm presuming that,
basically, you won't be using Windows 3.x or that you'd want WIN32S
compatibility, as no-one uses Windows 3.x anymore

...
Because there's no way of knowing at assemble-time / link-time which
version of the DLLs you're going to be linking to (nor whether that
DLL has been "relocated"...for efficiency reasons of not wasting
memory, Windows does try to load the system DLLs into the same place
for all processes so that it only needs to load a single copy of the
DLL into memory and all processes can share this same copy, so that
only _one_ KERNEL32.DLL needs to be loaded for all the programs
running...Windows will, in situations where this is somehow not
possible, load multiple copies of a DLL...but its default behaviour is
to try its best to load them all to the same locations...note, also,
that the main Windows system DLLs have been linked so that they all
have different base addresses near the end of memory to ensure that
none of them "collide"...it's good practice, also, for any DLLs you
might also create to try to find a memory location where it won't be
"clashing" with any other DLL or system DLL, to avoid the need of
relocating it...it will still work if you don't - it'll just relocate
the DLL - but things are much more efficient when the base addresses
are pre-calculated to best avoid any need for relocation

...so,
though complicated and slightly slower than a direct call straight to
the DLL would be, your EXE will actually be calling all its DLL
functions _via_ the "Import Address Table"...the loader itself will
fill out this table with the actual _exact_ addresses for the
functions when it loads your program (this is the reason, by the way,
that DLLs are always loaded first before any EXE that references
them...it has to know for certain where the DLLs are going to finally
reside in memory to know what addresses to fill out in the "Import
Address Table"

...
The "Import Address Table" is basically just a table of "JMP address"
instructions for each DLL function you need...as this is slightly
confusing, let's try to explain it more clearly just to make it
perfectly clear what's happening (note, in the following, I'll be
putting a space in the MASM names after the "@" sign...this space
shouldn't actually be in a real program at all but it has to be added
to stop newsreaders like Outlook Express thinking that it's an Email
address - because of the "@" sign - and turning it into a hyperlink

...
For MASM's "direct" way:
CALL __imp__ExitProcess@ 4
Assembles to something like:
CALL [ 420001h ] ; note, actual address varies and will almost
; certainly be different...but I'm using this
; address as an example value
At address 420001h, we find the address "76543210h", for
example...again, this address is just an example...but the address
will basically be the _actual_ address of the real "ExitProcess" API
in the KERNEL32 DLL copy loaded into memory...this address is actually
calculated at _load-time_ by the loader...
For TASM (and MASM's "indirect" way), it's an almost similar situation
except that the CALL instruction is slightly different...it now looks
something like:
TASM: CALL ExitProcess
MASM: CALL _ExitProcess@ 4
Assembles to:
CALL 420000h
And, this time, rather than the CALL instruction just using the
address value stored in the "Import Address Table", it actually makes
a call into it...so, we literally call address 420000h...at this
address, we find something like:
JMP 76543210h
And this JMP jumps directly to the start of the actual DLL
function...note that the "JMP" instruction doesn't effect the return
address that was pushed to the stack by "CALL" at all, so the DLL
function's "RET" instruction will still work as expected and return
back your program (the instruction after the CALL) rather than back to
the IAT...
[ Amazingly, this process is actually be done for every call to a DLL
function (including all the OS API

you make in your program...plus,
if you think that's bad, then, on NT-based systems (NT, XP

, the
DLLs like KERNEL32.DLL actually often don't do the work themselves but
they themselves use another DLL - NTDLL.DLL - to actually do the real
work...well, I say "real work" but, even then, this DLL often has to
make slow "user -> kernel" priviledge level transitions too...before
it goes on to defer it through multiple layers of the OS, potentially
all the way down a perhaps long chain of "layers" until it actually
reaches a device driver which does any actual interfacing with the
real hardware...
And people wonder why I'm not exactly the greatest fan of "layered" OS
architectures and am not always "nice" about Window's speed and
design...if only they knew what was going on then they'd realise I'm
not be at all unreasonable in finding all this often extraneous stuff
not exactly the best thing since sliced bread

]
The Import Library contains information about the functions inside a
particular DLL...unlike an ordinary static library, this information
actually _isn't_ the exact address of the function inside the
DLL...this information _can't_ be known at link-time (as we don't know
which version of a DLL we've going to be linking to...nor whether it's
been "relocated" from its usual base address) but is only known at
load-time...so, actually, there are no "addresses" in the import
library...but there is information in them about each DLL function
that the linker uses to fill out the EXE's headers...when the loader
is loading in your EXE, it looks at this information to know which
DLLs to load into memory...once it does this, it looks through more
information in the EXE headers which tell it which "imports" you
actually want from the DLLs and, with this information, it fills out
the _exact_ DLL function addresses into the "Import Address
Table"...your EXE was assembled and linked to work with the "Import
Address Table"...
The rough idea of what you heard is basically right...but, strictly,
the import library does not have information about the exact
addresses, it has information about the DLLs and the DLL functions
which the linker puts into the EXE headers so that the _loader_ knows
how to fill out the "import address table" properly with the right
addresses...
[ In fact, though the import library is a binary file, it's still
instructional for you to simply open up something like "import32.lib"
or "kernel32.lib" with Notepad...as it's not a text file but a binary
file, there'll be lots of junk characters...but every so often, you'll
see ASCII text sequences like "KERNEL32.DLL" and "ExitProcess"...well,
this is the basic information that an import library contains...not
addresses but names of DLLs, names of API, how many parameters they
take and that sort of thing...this information is used by the
_loader_...so, when it sees "KERNEL32.DLL" listed in the EXE headers,
it knows to load in KERNEL32.DLL into memory...the information about
the API functions in the EXE headers tell the linker exactly which API
function it is that you want to use and it then gets the address of
the named API and puts them in the right "Import Address Table"
positions...once it's done this, the EXE is ready to run because it'll
make all of it's CALLs via this import table...oh, if you do look at
the contents of these files in Notepad, remember NOT to "save changes"
when you close it...you don't want to alter it or it might stop
working properly...think of it as "read only"

]
But, yes, the whole process is rather confusing and
convoluted...unfortunately, it basically has to be this way due to the
design of Windows (flat memory model) and in order to allow for
different version of the same DLLs and to allow the DLLs to be
relocated at load-time / run-time...
[ Interestingly, COM (as used by DirectX and OLE

uses an
object-orientated way that automatically "links" at run-time...so,
other than the initial "CreateDirectDraw" API or whatever needed to
get the first "object", it actually doesn't suffer as much pointless
overhead as the "static" linking way...so much for all those people
who claim that object-orientation makes things less efficient, eh? COM
actually uses the more "direct" indirect CALL instructions all the
time and doesn't require the EXE headers to be filled up with
information for the loader...this is why Microsoft are using COM more
and more for all their new DLLs, like DirectX...unfortunately, the
main system DLLs - KERNEL32.DLL, USER32.DLL, GDI32.DLL - were
originally using the other method and basically have to continue to do
so for "backwards compatibility" reasons...or, otherwise, looking at
how MS are making all their new DLLs COM-based, it appears they've
decided that this new method is infinitely better...
Plus, of note, you can also do all of the linking _manually_ at
run-time using the "LoadLibrary", "GetProcAddress" and "FreeLibrary"
APIs in KERNEL32.DLL (these three will have to be statically linked in
the usual way but, thereafter, you can do all the loading and linking
at run-time using these API rather than linking with import
libraries)...
Unfortunately, though, both of these methods - COM and run-time
linking - are a _LOT_ more hard work to actually code...so, it
actually sort of "cancels out" the benefits because you have to write
a lot more complicated code to do things this way...so, it's NOT
really worth doing these things UNLESS you have a good reason to do so
(for example, if you are using "plug-ins" where you'd load a DLL at
run-time which may or may not be there...for instance, looking inside
a "PlugIns" folder on the hard drive for DLLs and then loading
them...which is stuff in the "very advanced" category, really...it's
very nice how things like Internet Explorer and Netscape Navigator can
do all this "plug-in" business...but, well, it's very complicated and
a lot of work to actually code this sort of thing

...use the import
library way if you've not got any reason to do otherwise because the
other ways - though they have their uses - are very headache-causing

]
Yes, this probably also works...because all the needed information is
available...
Note, actually, that "lib.exe" (which you'd use to create your import
libraries in MASM

_is_ "link.exe"...Microsoft actually combined the
librarian and the linker and so forth into the same "link.exe" file
and the "/lib" switch makes it behave as "LIB" rather than "LINK" (if
you type "link /lib", you'll notice that it calls itself "LIB" in the
help output, exactly as if you'd typed "lib" alone..."lib.exe" is not
actually a separate program - as link.exe now includes both "link" and
"lib" in the same utility - but is a "shortcut" program which simply
calls "link" with the "/lib" switch always enabled

...
Thus, because of the fact that, really, "lib" and "link" are actually
the same program then it does make sense that you could just use
"ml.exe", "link.exe" and the appropriate ".def" file...because
"link.exe" can just temporarily change to its "lib.exe" alter ego,
process the ".def" file (as you'd use "lib.exe" to create any import
library, anyway

and then switch back to being "link.exe" again to
finish off the linking...
This, no doubt, is exactly the reason _why_ Microsoft combined
"lib.exe" and "link.exe" into the same utility...an attempt to make
linking easier...because, yes, that whole "import library" thing can
often be problematic as well as confusing...
I've personally never tried the "/DLL" way you're mentioning
here...but it makes perfect sense that "link.exe" would be able to do
this, as long as you supply the correct ".def" file...well, you learn
something new every day...when I get time, I'll have a go at doing
this, I think, just to see if it really does work
sure.
Well, I don't know for sure either...but it's certainly possible and
would actually make plenty of sense
It's simple, really...the MASM32 package doesn't actually come with
"kernel32.lib", "user32.lib", etc. installed as files...instead, Hutch
has taken a rather clever route to getting these files instead...when
you install MASM32, it grabs the _actual system DLLs_ on your hard
drive and runs those programs you mention to generate all the
necessary ".lib" files for each system DLL it finds on your system...
"inc32.exe", if I've got it right, is actually responsible for
creating all the ".inc" files...these aren't installed in the package
either...instead, just as it does for creating a ".lib" file out of
each of the system DLL, it uses "inc21.exe" on each DLL file also to
create the corresponding ".inc" file...
[ Interestinly, if you actually look at the "kernel32.inc" file that
"inc21.exe" creates, then _all_ parameters are "DWORDs"...there's no
"HINSTANCE" or "HWND" like there is in the Win32 do***entation...the
reason for this is actually rather ingenious...under WIN32, _ALL_
parameters to API just so happen to be "DWORDs" (with only one or two
rare exceptions)...thus, "inc21.exe" is able to create the include
files just by looking at the system DLLs without having to know
anything special about them...the DLL already carries information
about how many bytes of parameters an API function takes (you'll note
that, in MASM, you actually type this information in yourself as part
of the function's name: "_ExitProcess@ 4" (again, the space isn't in
the real name, I have to put it in to stop Outlook thinking that it's
an Email address and turning it into a hyperlink

)...so, Hutch's
tool actually does something very simple but, ingeniously, it works
perfectly every time thanks to the fact that _all_ WIN32 API use DWORD
parameters...it just divides the amount of bytes an API function takes
by 4 and then spits out that many "DWORDs" in the API function's
prototype for the include file...as "dumb" and "blind" as this might
sound, it actually works brilliantly due to the fact that Microsoft
are totally consistent in making every parameter a DWORD in size

]
The reason for these programs running many times whilst you install
MASM32 is that they are being called for each system DLL one at a
time, in order to create the corresponding ".lib" and ".inc" file for
each system DLL you have installed on your hard drive...after all, it
would actually be a waste of space for the MASM32 package to carry
around these files when all the information in them _already exists_
on your system _actually inside_ the system DLLs themselves...plus,
theoretically, MASM32 can handle any new system DLLs that Microsoft
come up with, without needing to be updated, just by having these
tools run on the new system DLL file...hence, it also makes Hutch's
life a hundred times easier to keep MASM32 up-to-date...he just needs
to add any new system DLLs to the installation procedure and the tools
will automatically spit out the necessary ".lib" and ".inc"
files...this is thanks to Microsoft being very consistent with their
system DLLs...it's actually quite a sensible approach because Windows
DLLs are numerous and massive that manually writing your own ".inc"
files by hand would simply take forever to do (and it would be very
tedious...after all, it's a very "automatic" translation because,
well, MASM32 installation _does_ actually do it all automatically

...
I Hope that explains it all to you
Beth