![]() |
(SST) ShlWAPI.pas Version 1.08 |
---|---|
Developer Reference |
Function name and prototype/template declaration for a function that returns information on the version of a dynamic link library (dll). |
Scope |
---|
Not applicable (see remarks, below). |
Syntax |
---|
Function DllGetVersion(dllversioninfop : PDllVersionInfo) : HRESULT; |
Parameters | |
---|---|
dllversioninfop [in] | Pointer to, or address of a record/structore of type TDllVersionInfo or TDllVersionInfo2. . |
Return Values |
---|
DllGetVersion implementations should return S_OK (= 0) to indicate successful execution and a COM-defined error code*1 if they fail. |
The implementation as found in ShlWAPI.dll version 6.0.6001.18000 (as is part of Windows Vista Business, with SP 1 & IE8) returns S_OK (= 0) to indicate success and, based on a superficial tests, 0x80070057 ("The parameter is incorrect") when simulating a caller's typical implementation errors, such as passing an invalid pointer/address to the function or forgetting to initialize the record/structure's cbSize field. |
Remarks | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Although DllGetVersion is implemented in and exported by name by many Windows, shell/common control (ComCtrl) dlls, including the ShlWAPI.dlls, it is merely a recommendation for a function that returns a dynamic link library's version. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Even if the function is starting to/has become a de facto standard *2, its implementation is by no means mandatory and its existence in a dll should not be taken for granted. It should therefore never be listed in the in the hard-coded "imports" table of a binary (PE) executable, as this will prevent the application's execution in the event that a dll, in which it is not exported, is loaded. That could happen for a number of reasons, ranging from a faulty build (of the dll) to an incomplete/incorrect installation, or as a result of the paths listed in the PATH environment variable(s). | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
(*1)
The Microsoft documentation on the function refers to the error codes returned by the
function in the event of failure as COM-defined error codes.
Even if this is by no means incorrect, it is slightly misleading, in that it suggests
that the error codes that are (or should be) returned, were generated by COM functions
and/or are actually COM specific error codes.
Whereas, in fact, the schema that applies to all (32-bit) Windows error codes
is closely related to the Windows NT event log and message text resource APIs.
All error codes are therefore assumed to have the format shown in the table below and
should be defined and processed accordingly.
Thus, when split into its components, the error code 0x80070057 tells us that the function
that returned this value was unable to initiate and/or complete the operation as intended
(i.e. faultlessly) and that the error code in the low word is a system error code.
Which, brings us to the values that should be returned when implementing DllGetVersion
functions and why it is necessary to keep the relationship between error codes' values
and the Windows event log (and message text resources) in mind.
Developers of DllGetVersion functions are, of course, free to return any error
codes they see fit, even if they are only meaningful to the manufacturer of the dll.
However, such error codes can easily defeat the purpose for implementing the function,
this being to provide a standardized method for retrieving version information from the dll.
Furthermore, it would probably also entail the following issues/problems:
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
(*2) Numerous dlls, including the dlls of third party manufacturers, that aren't part of the Windows shell, have implemented and export the function. . |
Example How to Implement |
---|
The example below, demonstrates how to implement a DllGetVersion function. To use it, create a Delphi, Dll project and add a unit with the example code to the project. Finally, export the DllGetVersion function by adding an "Exports" clause with DllGetVersion to the dll's project source code (i.e. the .dpr file). Note, that the function has to be exported by name and not (only) by ordinal. |
unit DllGetVerExample01; interface USES Windows, SyncObjs, ShlWAPI; ... const MYDLL_MAJORVERSION = 1; const MYDLL_MINORVERSION = 0; const MYDLL_BUILDNUM = 42; const MYDLL_PLATFORMIDBOTH = DLLVER_PLATFORM_WINDOWS; //= $00000001; const MYDLL_PLATFORMIDWINNT = DLLVER_PLATFORM_NT; //= $00000002; const MYDLL_QFE = 88; ... FUNCTION DllGetVersion(dllversioninfop : PDllVersionInfo) : HRESULT; STDCALL; FORWARD; FUNCTION DllRetVersionInfo(dllversioninfop : PDllVersionInfo) : HRESULT; FORWARD; ... implementation ... Function DllGetVersion(dllversioninfop : PDllVersionInfo) : HRESULT; Var retval : HRESULT; Var critsection : TCriticalSection; Begin retval := 0; //= S_OK critsection := NIL; Try critsection := TCriticalSection.Create(); Try critsection.Enter(); retval := DllRetVersionInfo(dllversioninfop); critsection.Leave(); Finally critsection.Free(); end; Except raise; //Or implement some other form of error handling end; DllGetVersion := retval; End; Function DllRetVersionInfo(dllversioninfop : PDllVersionInfo) : HRESULT; Var retval : HRESULT; begin retval := 0; //= S_OK if dllversioninfop <> NIL then begin if IsBadWritePtr(dllversioninfop, SizeOf(DWORD)) = FALSE then begin if dllversioninfop^.cbSize >= SizeOf(TDllVersionInfo) then begin if IsBadWritePtr(dllversioninfop, SizeOf(TDllVersionInfo)) = FALSE then begin dllversioninfop^.dwMajorVersion := MYDLL_MAJORVERSION; dllversioninfop^.dwMinorVersion := MYDLL_MINORVERSION; dllversioninfop^.dwBuildNumber := MYDLL_BUILDNUM; //If the dll was built for and requires Windows NT //dllversioninfop^.dwPlatformID := MYDLL_PLATFORMIDWINNT; //else //othervise dllversioninfop^.dwPlatformID := MYDLL_PLATFORMIDBOTH; end else retval := $80070057; //= $80070000 + ERROR_INVALID_PARAMETER or ERROR_NOACCESS (= 998) if (retval = S_OK) and (dllversioninfop^.cbSize = SizeOf(TDllVersionInfo2)) then begin if IsBadWritePtr(dllversioninfop, SizeOf(TDllVersionInfo2)) = FALSE then begin PDllVersionInfo2(dllversioninfop)^.dwFlags := 0; PDllVersionInfo2(dllversioninfop)^.ullVersion := Int64(MakeDllVerULL(MYDLL_MAJORVERSION, MYDLL_MINORVERSION, MYDLL_BUILDNUM, MYDLL_QFE)); end else retval := $80070057; //= $80070000 + ERROR_MORE_DATA or ERROR_NOACCESS (= 998) end end else begin dllversioninfop^.cbSize := SizeOf(TDllVersionInfo2); retval := $800700EA; //ERROR_MORE_DATA (= 234) or ERROR_INSUFFICIENT_BUFFER (= 122) end; end else retval := $80070057; //= $80070000 + ERROR_INVALID_PARAMETER; end else retval := $80070057; //= $80070000 + ERROR_INVALID_PARAMETER; DllRetVersionInfo := retval; end; end; //End of unit |
Example How to Call |
---|
FUNCTION TForm4.GetDllHandle(adllanme : STRING) : HMODULE; VAR rethandle : HMODULE; BEGIN rethandle := 0; rethandle := GetModuleHandle(PChar(adllanme)); GetDllHandle := rethandle; END; FUNCTION TForm4.IsDllVerInfoImplemted(adllhandle : HMODULE; VAR aprocaddr : POINTER) : BOOLEAN; VAR retval : BOOLEAN; BEGIN retval := FALSE; IF (adllhandle <> 0) AND (adllhandle <> INVALID_HANDLE_VALUE) THEN BEGIN aprocaddr := GetProcAddress(adllhandle, 'DllGetVersion'); IF aprocaddr <> NIL THEN retval := TRUE; END; IsDllVerInfoImplemted := retval; END; FUNCTION TForm4.GetDllVersionInfoVer(aprocaddr : POINTER; VAR adllverinforec : TDllVersionInfo2) : INTEGER; //Although some DllGetVersion implementations, may return the size of //the supported record when called with the cbSize member set to 0, //others may not. It is thus safer to call the function with the //larger record first and evaluate the return value. VAR retval : INTEGER; VAR getverretval : HRESULT; VAR newinfoline : STRING; BEGIN retval := 0; getverretval := 0; newinfoline := ''; IF aprocaddr <> NIL THEN BEGIN adllverinforec.info1.cbSize := SizeOf(adllverinforec); getverretval := TDllGetVersionProc(aprocaddr)(@adllverinforec); IF getverretval = S_OK THEN retval := 2 ELSE retval := 1; END ELSE retval := - 1; GetDllVersionInfoVer := retval; END; FUNCTION TForm4.GetDllVersionInfo(aprocaddr : POINTER; VAR adllverinforec : TDllVersionInfo) : BOOLEAN; VAR retval : BOOLEAN; VAR getverretval : HRESULT; BEGIN retval := FALSE; getverretval := 0; IF aprocaddr <> NIL THEN BEGIN FillChar(adllverinforec, SizeOf(adllverinforec), #0); adllverinforec.cbSize := SizeOf(adllverinforec); getverretval := TDllGetVersionProc(aprocaddr)(@adllverinforec); IF getverretval = S_OK THEN retval := TRUE; END; GetDllVersionInfo := retval; END; FUNCTION TForm4.GetDllVersionInfo2(aprocaddr : POINTER; VAR adllverinforec : TDllVersionInfo2) : BOOLEAN; VAR retval : BOOLEAN; VAR getverretval : HRESULT; BEGIN retval := FALSE; getverretval := 0; IF aprocaddr <> NIL THEN BEGIN FillChar(adllverinforec, SizeOf(adllverinforec), #0); adllverinforec.info1.cbSize := SizeOf(adllverinforec); getverretval := TDllGetVersionProc(aprocaddr)(@adllverinforec); IF getverretval = S_OK THEN retval := TRUE; END; GetDllVersionInfo2 := retval; END; PROCEDURE TForm4.TestDllGetVersion(Sender : TObject); VAR dllhandle : HMODULE; VAR verinfosupported : BOOLEAN; VAR procaddr : POINTER; VAR dllverinfover : INTEGER; VAR dllverinfo2rec : TDllVersionInfo2; VAR getverretval : BOOLEAN; VAR ullversionval : WORD; VAR newinfoline : STRING; BEGIN dllhandle := 0; verinfosupported := FALSE; procaddr := NIL; dllverinfover := 0; FillChar(dllverinfo2rec, SizeOf(dllverinfo2rec), #0); getverretval := FALSE; newinfoline := ''; dllhandle := GetDllHandle('ShlWAPI.dll'); verinfosupported := IsDllVerInfoImplemted(dllhandle, procaddr); IF verinfosupported THEN BEGIN dllverinfover := GetDllVersionInfoVer(procaddr, dllverinfo2rec); IF dllverinfover >= 1 THEN BEGIN newinfoline := 'The loaded ShlWAPI.dll supports DllGetVersion, version ' + IntToStr(dllverinfover) + ' records'; Memo1.Lines.Add(newinfoline); IF dllverinfover = 1 THEN getverretval := GetDllVersionInfo(procaddr, dllverinfo2rec.info1) ELSE IF dllverinfover = 2 THEN getverretval := GetDllVersionInfo2(procaddr, dllverinfo2rec); IF getverretval = TRUE THEN BEGIN newinfoline := 'DllGetVersion returned the following version information: '; Memo1.Lines.Add(newinfoline); newinfoline := 'Major version : ' + IntToStr(dllverinfo2rec.info1.dwMajorVersion); Memo1.Lines.Add(newinfoline); newinfoline := 'Minor version : ' + IntToStr(dllverinfo2rec.info1.dwMinorVersion); Memo1.Lines.Add(newinfoline); newinfoline := 'Build number : ' + IntToStr(dllverinfo2rec.info1.dwBuildNumber); Memo1.Lines.Add(newinfoline); newinfoline := 'Platform ID : ' + IntToStr(dllverinfo2rec.info1.dwPlatformID); Memo1.Lines.Add(newinfoline); IF dllverinfover = 2 THEN BEGIN newinfoline := 'ullVersion : 0x' + IntToHex(dllverinfo2rec.ullVersion, 16); Memo1.Lines.Add(newinfoline); newinfoline := 'ullVersion broken down into : '; Memo1.Lines.Add(newinfoline); //Make the unwieldy term on the right a little easier to handle ullversionval := HIWORD(ULARGE_INTEGER(dllverinfo2rec.ullVersion).HighPart); newinfoline := 'Major version : ' + IntToStr(ullversionval) + ' (0x' + IntToHex(ullversionval, 4) + ')'; Memo1.Lines.Add(newinfoline); ullversionval := LOWORD(ULARGE_INTEGER(dllverinfo2rec.ullVersion).HighPart); newinfoline := 'Minor version : ' + IntToStr(ullversionval) + ' (0x' + IntToHex(ullversionval, 4) + ')'; Memo1.Lines.Add(newinfoline); ullversionval := HIWORD(ULARGE_INTEGER(dllverinfo2rec.ullVersion).LowPart); newinfoline := 'Build number : ' + IntToStr(ullversionval) + ' (0x' + IntToHex(ullversionval, 4) + ')'; Memo1.Lines.Add(newinfoline); ullversionval := LOWORD(ULARGE_INTEGER(dllverinfo2rec.ullVersion).LowPart); newinfoline := 'QFE : ' + IntToStr(ullversionval) + ' (0x' + IntToHex(ullversionval, 4) + ')'; Memo1.Lines.Add(newinfoline); END; END ELSE BEGIN newinfoline := 'Retrieving the version information failed'; Memo1.Lines.Add(newinfoline); END; END ELSE //IF dllverinfover >= 1 THEN BEGIN newinfoline := 'Determining the version of the version info record supported by DllGetVersion failed.'; Memo1.Lines.Add(newinfoline); END; END ELSE BEGIN newinfoline := 'The loaded ShlWAPI.dll does not support DllGetVersion'; Memo1.Lines.Add(newinfoline); END; Memo1.Lines.Add(''); TestExampleDllGetVersion(Sender); END; |
Text: |
The loaded ShlWAPI.dll supports DllGetVersion, version 2 records DllGetVersion returned the following version information: Major version : 6 Minor version : 0 Build number : 6001 Platform ID : 1 ullVersion : 0x0006000017714650 ullVersion broken down into : Major version : 6 (0x0006) Minor version : 0 (0x0000) Build number : 6001 (0x1771) QFE : 18000 (0x4650) The loaded MyExampleDll01.dll supports DllGetVersion, version 2 records DllGetVersion returned the following version information: Major version : 1 Minor version : 0 Build number : 42 Platform ID : 1 ullVersion : 0x00010000002A0058 ullVersion broken down into : Major version : 1 (0x0001) Minor version : 0 (0x0000) Build number : 42 (0x002A) QFE : 88 (0x0058) |
Requirements | |
---|---|
Unit: | Not applicable. |
Library: | Not applicable. |
Unicode: | Not applicable. |
Min. ShlWAPI.dll version according to MS SDK doc.: | 4.71 |
Min. ShlWAPI.dll version based on SST research: | 4.71 |
Min. OS version(s) according to Microsoft SDK doc.: | Windows 98, Windows NT 4.0 with Internet Explorer 4.0, Windows 2000 |
Min. OS version(s) according to SST research.: | Windows 98, Windows NT 4.0 with shell/IE version 4.0 |
See Also |
---|
TDllVersionInfo, TDllVersionInfo2, MakeDllVerULL, TDllGetVersionProc. |
Windows APIs: DLLVERSIONINFO, DLLVERSIONINFO2, DllGetVersion, GetLastError, SetLastError, SetLastErrorEx. |
Document/Contents version 1.03 Page/URI last updated on June 15, 2022 |
Copyright © Stoelzel Software Technologie (SST) 2010 - 2022 |
Suggestions and comments mail to: webmaster@stoelzelsoftwaretech.com |