Wrong version of shell32.lib? (for Win2k)

I had to change my sources file from:
_NT_TARGET_VERSION=$(_NT_TARGET_VERSION_WIN2K)

To this:
_NT_TARGET_VERSION=$(_NT_TARGET_VERSION_WINXP)

When linking with the Win2k libraries, I got two unresolved external
symbol errors:
[snip]
i:\winddk\6000\lib\w2k\i386\shell32.lib
[snip]
c:\svn\source\virtualprinter\portmonitor\monitor.obj : error LNK2019:
unresolved external symbol __imp__PathYetAnotherMakeUniqueName@16
referenced in function “int __stdcall MyStartDocPort(void *,unsigned
short *,unsigned long,unsigned long,unsigned char *)”
(?MyStartDocPort@@YGHPAXPAGKKPAE@Z)

It has an identical objection to PathCleanupSpec().

The Windows SDK docs says “Windows 2000” for both these functions and
“shell32.dll version 5.0 or later”. Win2k shipped with version 5 of
shell32.dll according to the DLL Help database.

AFAICT; either the SDK docs are wrong, or the shell32.lib library is messed up?

No biggie, I will just link with the XP libraries, but it would be
nice to know if I am missing something obvious. (haven’t touched C in
ten years+, so chances are good that I am missing something)


Rune

> AFAICT; either the SDK docs are wrong, or the shell32.lib library is messed up?

Well, you can easily find it out yourself if you have a binary of W2K’s version of DLL - just dump DLL’s export section, and see if the target function is being exported. If yes, then there must be something wrong with .lib file that you use, otherwise, documentation is wrong…

No biggie, I will just link with the XP libraries,

Check the exports first - if the target function is, indeed, missing under W2K, running your app under W2K is going to be rather problematic, don’t you think?

Anton Bassov

xxxxx@hotmail.com wrote:

> No biggie, I will just link with the XP libraries,

Check the exports first - if the target function is, indeed,
> missing under W2K, running your app under W2K is
> going to be rather problematic, don’t you think?

Maybe it is not problematic. :slight_smile:

In the bulkusb sample from Microsoft, the author deliberately links to
the XP libraries – and also to some functions that are not present in
pre-XP platforms like Win98SE, WinME or Win2000.

However, the code that uses these functions does a platform check, and
they are only called on XP or later.

This way the same WDM driver binary runs on all platforms from WinME up
to Vista32 - using some required advanced function calls only where they
are actually available. :slight_smile:

References: WDK6000
bulkusb.c/BulkUsb_AddDevice/L372 ff
bulkpnp.c/HandleStopDevice/L1178

Example:
if(WinXpOrBetter == deviceExtension->WdmVersion) {
/* call functions that do not exist on earlier platforms */
}

> However, the code that uses these functions does a platform check,

and they are only called on XP or later.

Well, this is already a different story, don’t you think??? Certainly if you do a platform check in your code everything is going to be just fine. However, judging from the OP’s post, this is not what he plans to do - instead, he just plans to link to XP libraries instead of W2K ones, and that’s it. Therefore, running his code under W2K is going to be rather problematic if functions that he relies upon are not present there and he does not adjust his code accordingly. In any case, he has to check whether these functions are actually exported on W2K before he does any adjustments to his code …

Anton Bassov

On Jan 14, 2008 12:35 PM, wrote:
> he has to check whether these functions are actually exported on W2K before
> he does any adjustments to his code …

I think I still have a Win2k CD at home, I’ll dig out shell32.dll from
there and check its exports.

I just hoped someone else had noticed the shell32.lib discrepancy
already, and could give me a quick ‘no, the docs are wrong’ kind of
response.


Rune

xxxxx@hotmail.com wrote:

Certainly if you do a platform check in your code everything is
> going to be just fine.

…and we both don’t know, whether the OPs code (e.g. a modified MS
sample?) does the necessary checks, or not.

Because I have stumbled across it myself(*), I just wanted to point out
that there is a mechanism that can provoke such an error message.

In any case, he has to check whether these functions are actually
> exported on W2K before he does any adjustments to his code …

Ummm… actually not, Anton. This information is in his mail:

  • The OPs code does link with _NT_TARGET_VERSION_WINXP.

  • From the “unresolved external symbol” error messages thrown with
    _NT_TARGET_VERSION_WIN2K, we know that the functions are definitely not
    exported on W2K.

Anton, I assume you actually wanted to say:

“In any case, he has to check whether these functions are actually
CALLED on W2K before he does any adjustments to his BUILD ENVIRONMENT OR
code …”

In the case of bulkusb.sys, some functions are not available in the W2K
libs. As they are never called when the driver runs on W2K, it is OK to
link with the WXP libs instead.

General truths:

  • All drivers must be designed so that (during runtime on a “supported”
    platform) they never call any unsupported function ! In fact, this is
    true for ANY running program/application on any given OS.

  • Whenever a build/link reports an error, you have to investigate and
    make sure you understand exactly what’s going on.

BR, -H


(*)During my first compile of bulkusb.sys on W2K I got the build.exe
error message “Platform not supported”.

As I did not understand why this error was thrown - for a driver for
which its developer notes state it is useable for W2K/WXP and Vista - I
tried to compile manually, and ran into the link problem.

When I investigated what these “missing” functions actually do, I learnt
that (a) it is required to use them and the XP libraries to provide
proper PnP support on XP and later, and (b) it is safe for earlier
platforms to link to them b/c the code checks the platform and they are
never invoked there.

The error I made was to assume a driver must be buildable on all
supported platforms.

This is not true - in fact, a multi-platform driver must be built on the
most recent platform that supports all required functionality.

Hagen,

This is not only the question of calling a function…

Before you can call a function you have to load your binary, in the first place. Therefore, before your program starts, a loader is going to fill your IAT with the addresses of all functions that you import. For each DLL that you import from, it will do the following:

  1. Load DLL into your address space

  2. Take a name of a function that you import, match it against the target DLL’s export section,
    and, if the match is found, write the address of this function as it is known in your address space (i.e. imported DLL’s Base Address+ target function’s RVA) to IAT

Now consider what happens under W2K if the target function is exported by XP but not W2K and you link against the XP library - the name of the problem function is in your binary’s IAT
(because you have linked it against XP library where it is present), but a loader is unable to find its match in the target DLL export section (because W2K does not export it). What is the loader supposed to do under these circumstances, apart from refusing to load your binary???

Therefore, assuming that you don’t want to have 2 separate binaries for W2K and XP, you have 2 options here:

A. Write a code that does not rely upon the target function, and that’s it

B Write the code the following way

if (W2k) do_things_as_if _you_took_option_A;

else

get_function’s_address_by_GetProcAddress_and_call_it;

If you take option B you can link against either library - you just have to make sure that you call
the target function under some proxy name, rather than its real one (otherwise, you will fail to link if you link against W2K library or loader will refuse to load your binary on W2K if you link against XP library). In other words, you have to make sure that the target’s function name does not appear in your IAT, no matter what…

This is what I meant by “adjusting the code accordingly”…

Anton Bassov

'On Jan 14, 2008 10:32 AM, wrote:
> Well, you can easily find it out yourself if you have a binary of W2K’s version of DLL - just

FWIW: The export is missing from version 5.0.2920.0 of shell32.dll.

So the SDK docs are inaccurate. The .lib is fine.

But one of the service packs could have updated this .dll… Sigh. (I
guess I could download the service pack)


Rune

> FWIW: The export is missing from version 5.0.2920.0 of shell32.dll.

Very old. My w2k SP4 with all patches has 5.0.3900.7105


Maxim Shatskih, Windows DDK MVP
StorageCraft Corporation
xxxxx@storagecraft.com
http://www.storagecraft.com

On Jan 14, 2008 6:42 PM, Maxim S. Shatskih wrote:
> Very old. My w2k SP4 with all patches has 5.0.3900.7105

yeeees… And if you have it there, right in front of you… Do you
happen to see the missing exports? Alternatively, could you chuck the
.dll my way? Hopefully gmail.com won’t shave off the attachment.
(damned child safety!)


Rune

> happen to see the missing exports?

C:\WINNT\system32>dumpbin /exports shell32.dll | grep -i path
320 56 0006E470 SHGetFolderPathA
321 57 0002075A SHGetFolderPathW
327 5F 00024CED SHGetPathFromIDList
328 60 00024CED SHGetPathFromIDListA
329 61 0001FD3F SHGetPathFromIDListW
332 64 0006E4B0 SHGetSpecialFolderPathA
333 65 00020733 SHGetSpecialFolderPathW
342 6E 00083138 SHPathPrepareForWriteA
343 6F 0008309F SHPathPrepareForWriteW
351 77 0007DF4A SheConvertPathW
352 78 0007D821 SheFullPathA
353 79 0007D8E7 SheFullPathW
358 7E 0007D220 SheGetPathOffsetW
362 82 0007DAA4 SheShortenPathA
363 83 0007DAFD SheShortenPathW
30 [NONAME] (forwarded to shlwapi.PathBuildRootW)
37 [NONAME] (forwarded to shlwapi.PathCombineW)
39 [NONAME] (forwarded to shlwapi.PathIsUNCW)
40 [NONAME] (forwarded to shlwapi.PathIsRelativeW)
57 [NONAME] (forwarded to shlwapi.PathGetDriveNumberW)

C:\WINNT\system32>


Maxim Shatskih, Windows DDK MVP
StorageCraft Corporation
xxxxx@storagecraft.com
http://www.storagecraft.com

On Jan 14, 2008 7:27 PM, Maxim S. Shatskih wrote:
> C:\WINNT\system32>dumpbin /exports shell32.dll | grep -i path

Ah, thanks a bunch. I was obviously grasping at straws. Back to the
drawing board. :slight_smile:


Rune

xxxxx@hotmail.com wrote:

Now consider what happens under W2K if the target function is exported by XP but not W2K and you link against the XP library - the name of the problem function is in your binary’s IAT
(because you have linked it against XP library where it is present), but a loader is unable to find its match in the target DLL export section (because W2K does not export it). What is the loader supposed to do under these circumstances, apart from refusing to load your binary???

Absolutely correct, thanks for pointing this out – I mixed up the
switch for calls to existing Kernel functions (the ones that are
required on XP and later, e.g. for PnP) with calls to functions that do
not exist on some platforms.

The cannot-link-to-unavailable-functions problem is exactly the reason
why Walter Oney implemented stubs for the missing WDM functions on e.g.
Win98SE. His clever trick makes the same USB WDM driver code useable
from Win98SE up to Vista64.

get_function’s_address_by_GetProcAddress_and_call_it;

This way you would use the system’s DLL loader/linker to link (and
provide a fast call method) for the exports that are “safe”, and do a
manual call to the functions that are possibly missing. Which is the
fastest method (wrapping this in a LIB or DLL does not help).

If we assume that actually a shell32.dll version for W2K exists that
contains the missing functions, the OP could also solve his problem by
checking the shell32.dll version during install and offer an update to
the user.
Safer is undoubtedly the dynamic checking if the functions are
available that you suggest, Anton.

Thanks for the correction! -H