如何通过程序屏蔽win98的“非法操作”??(300分)

  • 主题发起人 主题发起人 萧月禾
  • 开始时间 开始时间
Tip 55: Diagnosing "Error in Loading DLL" with LoadLibrary
Created: April 17, 1995

Abstract
When developing applications in Visual Basic® that run on different computer systems, you must process error conditions such as missing dynamic-link library (.DLL) files. The Windows® application programming interface (API) LoadLibrary, FreeLibrary, and SetErrorMode functions can be used to create an error-handling routine that will capture and process the "Error in Loading DLL" error message returned when Windows cannot find the specified .DLL file on the target machine. This article explains how your application can determine if a .DLL is on the user's system.

Trapping Errors When DLLs Are Missing
When an application calls a function in a dynamic-link library (.DLL) file, it loads the .DLL into memory and executes the specified function. However, if the .DLL file does not exist on the user's machine, Windows® responds by displaying an "Error in loading DLL" error message.

In a Visual Basic® application, you can write your own routine to determine if the specified .DLL file exists and prevent Windows from generating its own critical error message (Int 24h). This can be done by using the Windows application programming interface (API) LoadLibrary, FreeLibrary, and SetErrorMode functions.

The LoadLibrary function loads the specified .DLL into memory. To use this function in your Visual Basic program, include the following Declare statement in the General Declarations section of your form:

Declare Function LoadLibrary Lib "Kernel" (ByVal f$) As Integer

The LoadLibrary function requires only one argument—the name of the library file you want to load. After calling this function, LoadLibrary returns an integer value that contains the instance handle of the .DLL or an error code (the value returned is less than 32, indicating an error has occurred). The following error codes and their meanings are returned by the LoadLibrary function.

0 System was out of memory, executable file was corrupt, or relocations were invalid.
2 File was not found.
3 Path was not found
5 Attempt was made to dynamically link to a task, or there was a sharing or network-protection error.
6 Library required separate data segments for each task.
8 There was insufficient memory to start the application.
10 Windows version was incorrect.
11 Executable file was invalid. Either it was not a Windows-based application or there was an error in the .EXE image.
12 Application was designed for a different operating system.
13 Application was designed for MS-DOS® version 4.0.
14 Type of executable file was unknown.
15 Attempt was made to load a real-mode application (developed for an earlier version of Windows).
16 Attempt was made to load a second instance of an executable file containing multiple data segments that were not marked read-only.
19 Attempt was made to load a compressed executable file. The file must be decompressed before it can be loaded.
20 Dynamic-link library (.DLL) file was invalid. One of the .DLLs required to run this application was corrupt.
21 Application requires Microsoft® Windows 32-bit extensions.


The Windows API FreeLibrary function unloads a previously loaded .DLL. The FreeLibrary function should be called after you have tried to load a .DLL file with the LoadLibrary function. This function's declaration statement is as follows:

Declare Sub FreeLibrary Lib "Kernel" (ByVal h As Integer)

To unload a .DLL from memory, you simply call the FreeLibrary function with the module's instance handle.

If your Visual Basic application attempts to load a .DLL that does not exist, Windows will respond with a critical-error-handler message box. You can use the Windows API SetErrorMode function to tell Windows to handle the error or to tell Windows that your program will process the error condition itself. The declaration statement for SetErrorMode is as follows:

Declare Function SetErrorMode Lib "Kernel" (ByVal wMode As Integer) As Integer

This function requires only one argument: a constant value that tells Windows how to handle Interrupt 24h errors. The value you pass to SetErrorMode may be a combination of these values:

SEM_FAILCRITICALERRORS Windows does not display the critical-error-handler message box and so returns the error to the calling application.
SEM_NOGPFAULTERRORBOX Windows does not display the general-protection-fault message box. This flag should be set only by debugging applications that handle GP faults themselves.
SEM_NOOPENFILERRORBOX Windows does not display a message box when it fails to find a file.


After calling the SetErrorMode function, an integer value is returned. This value is the previous state of the error-mode flag.

In a Visual Basic application, you can use the SetErrorMode function in conjunction with the LoadLibrary and FreeLibrary functions to determine if a user's system has the .DLL files your program needs.

Example Program
The following program shows how to trap Error Code 48, "Error in loading DLL", from within your Visual Basic application.

Create a new project in Visual Basic. Form1 is created by default.


Add the following Declare statements to the General Declarations section of Form1 (note that each Declare statement must be typed as a single line of text):
Declare Function LoadLibrary Lib "Kernel" (ByVal f$) As Integer
Declare Sub FreeLibrary Lib "Kernel" (ByVal h As Integer)
Declare Function SetErrorMode Lib "Kernel" (ByVal wMode As Integer) As Integer

Add the following code to the Form_Load event for Form1:
Sub Form_Load()
Dim NameofDLL As String
Dim IsThere As Integer
Dim ErrNumber As Integer
Dim ErrText As String

NameofDLL = "kernel.dll"
IsThere = DoesLibraryExist(NameofDLL, ErrNumber, ErrText)

If IsThere = True Then
text1.Text = "DLL exists!"
Else
text1.Text = Str$(ErrNumber) + " " + ErrText
End If

End Sub

Add a Text Box control to Form1. Text1 is created by default.


Create a new function called DoesLibraryExist. Add the following code to this function (note that the first line, the OriginalErrorValue% lines, and all Explain$ lines must be typed as a single line of code):
Function DoesLibraryExist(DllName$, ErrorReturned%, ErrorExplanation$)
As Integer
Dim hInst As Integer
Dim ReturnValue As Integer
Dim Explain$
Dim OriginalErrorValue%
Const SEM_NOOPENFILEERRORBOX = &H8000
Const SEM_FAILCRITICALERRORS = &H1

ReturnValue = True
OriginalErrorValue% = SetErrorMode(SEM_NOOPENFILEERRORBOX Or
SEM_FAILCRITICALERRORS)
hInst = LoadLibrary(DllName$)
OriginalErrorValue% = SetErrorMode(OriginalErrorValue)
If hInst > 32 Then
ReturnValue = True
FreeLibrary (hInst)
Else
ReturnValue = False
Select Case hInst
Case 0
Explain$ = "System is out of memory, executable file is corrupt, or
relocations are invalid."
Case 2
Explain$ = "File not found."
Case 3
Explain$ = "Path not found."
Case 5
Explain$ = "Sharing or network protection error."
Case 6
Explain$ = "Library required separate data segments for each task."
Case 8
Explain$ = "Insufficient memory."
Case 10
Explain$ = "Incorrect Windows version."
Case 11
Explain$ = "It was either not a Windows application or there was an
error in the file."
Case 12
Explain$ = "It was designed for a different operating system."
Case 13
Explain$ = "It was designed for MS-DOS 4.0."
Case 14
Explain$ = "File type unknown."
Case 15
Explain$ = "The file was designed for an earlier Version of Windows."
Case 16
Explain$ = "An attempt was made to load a second instance of an
executable file containing multiple data segments not marked
read-only."
Case 19
Explain$ = "Attempt was made to load a compressed file. It must be
decompressed before it can be loaded."
Case 20
Explain$ = "DLL file is invalid. This file or one called by it is
corrupt."
Case 21
Explain$ = "The file requires Microsoft Windows 32-bit extensions."
Case Else
Explain$ = "The reason it wouldn't load is unclear. Error code " &
Trim(Str(hInst)) & "."
End Select
ErrorReturned = Int(hInst)
ErrorExplanation$ = Explain$
End If
DoesLibraryExist = ReturnValue
End Function

When you run this program, it should display the message "DLL Exists" in the Text Box. Change the NameofDLL string variable to "WIN.COM" and run the application a second time. You should receive an error number and error message in the Text Box because there is no .DLL file by the name of WIN.COM.






DDMM.CPP
/*========================================================================== * * Copyright (c) 1995 - 1997 Microsoft Corporation. All Rights Reserved. * * File: ddmm.cpp * Content: Routines for using DirectDraw on a multimonitor system * ***************************************************************************/ #include <streams.h> #include <ddraw.h> #include "ddmm.h" /* * FindDeviceCallback */ typedef struct { LPSTR szDevice; GUID* lpGUID; GUID GUID; BOOL fFound; } FindDeviceData; BOOL CALLBACK FindDeviceCallback(GUID* lpGUID, LPSTR szName, LPSTR szDevice, LPVOID lParam) { FindDeviceData *p = (FindDeviceData*)lParam; if (lstrcmpiA(p->szDevice, szDevice) == 0) { if (lpGUID) { p->GUID = *lpGUID; p->lpGUID = &p->GUID; } else { p->lpGUID = NULL; } p->fFound = TRUE; return FALSE; } return TRUE; } BOOL CALLBACK FindDeviceCallbackEx(GUID* lpGUID, LPSTR szName, LPSTR szDevice, LPVOID lParam, HANDLE hMonitor) { FindDeviceData *p = (FindDeviceData*)lParam; if (lstrcmpiA(p->szDevice, szDevice) == 0) { if (lpGUID) { p->GUID = *lpGUID; p->lpGUID = &p->GUID; } else { p->lpGUID = NULL; } p->fFound = TRUE; return FALSE; } return TRUE; } /* * DirectDrawCreateFromDevice * * create a DirectDraw object for a particular device */ IDirectDraw * DirectDrawCreateFromDevice(LPSTR szDevice, PDRAWCREATE DirectDrawCreateP, PDRAWENUM DirectDrawEnumerateP) { IDirectDraw* pdd = NULL; FindDeviceData find; if (szDevice == NULL) { DirectDrawCreateP(NULL, &pdd, NULL); return pdd; } find.szDevice = szDevice; find.fFound = FALSE; DirectDrawEnumerateP(FindDeviceCallback, (LPVOID)&find); if (find.fFound) { // // In 4bpp mode the following DDraw call causes a message box to be popped // up by DDraw (!?!). It's DDraw's fault, but we don't like it. So we // make sure it doesn't happen. // UINT ErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS); DirectDrawCreateP(find.lpGUID, &pdd, NULL); SetErrorMode(ErrorMode); } return pdd; } /* * DirectDrawCreateFromDeviceEx * * create a DirectDraw object for a particular device */ IDirectDraw * DirectDrawCreateFromDeviceEx(LPSTR szDevice, PDRAWCREATE DirectDrawCreateP, LPDIRECTDRAWENUMERATEEXA DirectDrawEnumerateExP) { IDirectDraw* pdd = NULL; FindDeviceData find; if (szDevice == NULL) { DirectDrawCreateP(NULL, &pdd, NULL); return pdd; } find.szDevice = szDevice; find.fFound = FALSE; DirectDrawEnumerateExP(FindDeviceCallbackEx, (LPVOID)&find, DDENUM_ATTACHEDSECONDARYDEVICES); if (find.fFound) { // // In 4bpp mode the following DDraw call causes a message box to be popped // up by DDraw (!?!). It's DDraw's fault, but we don't like it. So we // make sure it doesn't happen. // UINT ErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS); DirectDrawCreateP(find.lpGUID, &pdd, NULL); SetErrorMode(ErrorMode); } return pdd; }

 
老兄,该说的楼上的各位兄弟都说了,我也想不出什么了,
帮你UP一下吧.
//关注此题.
 
我完了。。。。。。 [:(]
 
该说的楼上的各位兄弟都说了,我也想不出什么了,
帮你UP一下吧.
//关注此题.
 
我说点个人的看法,不对之处请大家指教
我感觉还是因为win2k与win98的内存管理机制不同造成的,至于有什么不同,还是去问微软吧[:D][:D]
 
从资源监测窗口上可看出
应该有部分创建的对象未释放而导致内存不足引起错误
但究竟是哪些对象未释放却又查不出来 :(
 
不如推荐客户使用win2000操作系统好了。我的一个程序,在同样的配置下,
使用win2000的机器比使用win98的机器读取局域网数据库(interbase)时快好几倍。
 
客户那边都是用正版的
Win2000比较贵
 
见鬼了,所有创建的对象都Free了,内存还是不释放,发生什么事呀
是不是光Free还不行,还要给它赋值nil ??
 
定位GP错, 在BCB中倒可以用BCB自带的Code Guard功能来检测
在delphi中只好自己单步跟踪一下了

或者你将与对象创建和释放相关的代码部分删除来定位GP错的位置
 
防止显示严重错误

不管你的程序如何反复调试,交给用户之后,总有可能发生你意想不到的错误,如何避免Win95显示出白色的窗口,告诉你的用户发生了难堪的意外错误呢?我们可以这样做:

var
wOldErrorMode:Word;
begin
wOldErrorMode:=SetErrorMode(SEM_FAILCRITICALERRORS);
try
///////有可能出错的代码放在这儿
finally
SetErrorMode(wOldErrorMode);
end;
end;

 
为什么不试着把你的程序在98下编译一次呢。
 
土豆我教你一个办法啊,哈哈,

求我,求我,我就告诉你啊,[:D]
 
to ty_unix:
你的方法顶多就是让客户装2000,不说也知道 [:)]
 
最后没办法了,还是说服用户升级到2000了
理由是本软件功能强大,对系统要求高,而且以后肯定也是都用2000以上版本的。。。
 

Similar threads

S
回复
0
查看
3K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
2K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
1K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
905
SUNSTONE的Delphi笔记
S
后退
顶部