学习编程 - 第10页 | 雨律在线
分类 [ 学习编程 ] 下的全部文章


代码共享如下,在Win2K sp4/WinXP sp2上调试通过。


BOOL CheckFileTrust( LPCWSTR lpFileName )
{
BOOL bRet = FALSE;
WINTRUST_DATA wd = { 0 };
WINTRUST_FILE_INFO wfi = { 0 };
WINTRUST_CATALOG_INFO wci = { 0 };
CATALOG_INFO ci = { 0 };

HCATADMIN hCatAdmin = NULL;
if ( !CryptCATAdminAcquireContext( &hCatAdmin, NULL, 0 ) )
{
return FALSE;
}

HANDLE hFile = CreateFileW( lpFileName, GENERIC_READ, FILE_SHARE_READ,
NULL, OPEN_EXISTING, 0, NULL );
if ( INVALID_HANDLE_VALUE == hFile )
{
CryptCATAdminReleaseContext( hCatAdmin, 0 );
return FALSE;
}

DWORD dwCnt = 100;
BYTE byHash[100];
CryptCATAdminCalcHashFromFileHandle( hFile, &dwCnt, byHash, 0 );
CloseHandle( hFile );

LPWSTR pszMemberTag = new WCHAR[dwCnt * 2 + 1];
for ( DWORD dw = 0; dw < dwCnt; ++dw )
{
wsprintfW( &pszMemberTag[dw * 2], L"%02X", byHash[dw] );
}

HCATINFO hCatInfo = CryptCATAdminEnumCatalogFromHash( hCatAdmin,
byHash, dwCnt, 0, NULL );
if ( NULL == hCatInfo )
{
wfi.cbStruct = sizeof( WINTRUST_FILE_INFO );
wfi.pcwszFilePath = lpFileName;
wfi.hFile = NULL;
wfi.pgKnownSubject = NULL;

wd.cbStruct = sizeof( WINTRUST_DATA );
wd.dwUnionChoice = WTD_CHOICE_FILE;
wd.pFile = &wfi;
wd.dwUIChoice = WTD_UI_NONE;
wd.fdwRevocationChecks = WTD_REVOKE_NONE;
wd.dwStateAction = WTD_STATEACTION_IGNORE;
wd. lor="#000000">dwProvFlags = WTD_SAFER_FLAG;
wd.hWVTStateData = NULL;
wd.pwszURLReference = NULL;
}
else
{
CryptCATCatalogInfoFromContext( hCatInfo, &ci, 0 );
wci.cbStruct = sizeof( WINTRUST_CATALOG_INFO );
wci.pcwszCatalogFilePath = ci.wszCatalogFile;
wci.pcwszMemberFilePath = lpFileName;
wci.pcwszMemberTag = pszMemberTag;

wd.cbStruct = sizeof( WINTRUST_DATA );
wd.dwUnionChoice = WTD_CHOICE_CATALOG;
wd.pCatalog = &wci;
wd.dwUIChoice = WTD_UI_NONE;
wd.fdwRevocationChecks = WTD_STATEACTION_VERIFY;
wd.dwProvFlags = 0;
wd.hWVTStateData = NULL;
wd.pwszURLReference = NULL;
}
GUID action = WINTRUST_ACTION_GENERIC_VERIFY_V2;
HRESULT hr = WinVerifyTrust( NULL, &action, &wd );
bRet = SUCCEEDED( hr );

if ( NULL != hCatInfo )
{
CryptCATAdminReleaseCatalogContext( hCatAdmin, hCatInfo, 0 );
}
CryptCATAdminReleaseContext( hCatAdmin, 0 );
delete[] pszMemberTag;
return bRet;
}


这段代码是在一个老外的论坛上不经意搜索到的,一个貌似德国人(因为他的注释不是英文写的,德国亦仅猜测尔,西班牙、葡萄牙、法兰西、俄罗斯亦都有可能)写的Delphi代码,其中使用了WinTrust.dll中的导出函数。使用VS2005的朋友们可以包含WinTrust.h、SoftPub.h和Mscat.h,并添加导入库WinTrust.lib;使用VC6的朋友们可以参考MSDN上的函数及结构体声明,并用函数指针进行调用。

本人补充一下一些类型,方便翻译成别的语言:
typedef struct _WINTRUST_DATA
{ DWORD cbStruct;
LPVOID pPolicyCallbackData;
LPVOID pSIPClientData;
DWORD dwUIChoice;
DWORD fdwRevocationChecks;
DWORD dwUnionChoice;
union {
struct WINTRUST_FILE_INFO_* pFile;
struct WINTRUST_CATALOG_INFO_* pCatalog;
struct WINTRUST_BLOB_INFO_* pBlob;
struct WINTRUST_SGNR_INFO_* pSgnr;
struct WINTRUST_CERT_INFO_* pCert;
};
DWORD dwStateAction;
HANDLE hWVTStateData;
WCHAR* pwszURLReference;
DWORD dwProvFlags;
DWORD dwUIContext;
}
WINTRUST_DATA, *PWINTRUST_DATA;

typedef struct WINTRUST_FILE_INFO_
{ DWORD cbStruct;
LPCWSTR pcwszFilePath;
HANDLE hFile;
GUID* pgKnownSubject;
}
WINTRUST_FILE_INFO, *PWINTRUCT_FILE_INFO;

typedef struct WINTRUST_CATALOG_INFO_
{ DWORD cbStruct; DWORD dwCatalogVersion;
LPCWSTR pcwszCatalogFilePath;
LPCWSTR pcwszMemberTag;
LPCWSTR pcwszMemberFilePath;
HANDLE hMemberFile;
}
WINTRUST_CATALOG_INFO, *PWINTRUST_CATALOG_INFO;

typedef struct CATALOG_INFO_
{ DWORD cbStruct;
WCHAR wszCatalogFile[MAX_PATH];
}
CATALOG_INFO;

本人再补充一下用到的API声明:
LONG WINAPI WinVerifyTrust(
__in HWND hWnd,
__in GUID* pgActionID,
__in LPVOID pWVTData
);


Public Declare Function NtSuspendProcess _
Lib "NTDLL.DLL" (ByVal hProc As Long) As Long
Public Declare Function
NtResumeProcess _
Lib "NTDLL.DLL" (ByVal hProc As Long) As Long
Private Declare Function
NtSetInformationProcess _
Lib "NTDLL.DLL" (ByVal ProcessHandle As Long, _
ByVal ProcessInformationClass As SYSTEM_INFORMATION_CLASS, _
ByRef ProcessInformation As Any, _
ByVal lProcessInformationLength As Long) As Long
Private Declare Function
NtQueryInformationProcess _
Lib "NTDLL.DLL" (ByVal ProcessHandle As Long, _
ByVal ProcessInformationClass As SYSTEM_INFORMATION_CLASS, _
ByRef ProcessInformation As Any, _
ByVal lProcessInformationLength As Long, _
ByRef lReturnLength As Long) As Long
Private Declare Function
NtQuerySystemInformation _
Lib "NTDLL.DLL" (ByVal dwInfoType As Long, _
ByVal lpStructure As Long, _
ByVal dwSize As Long, _
dwReserved
As Long) As Long
Private Declare Function
NtQueryObject _
Lib "NTDLL.DLL" (ByVal ObjectHandle As Long, _
ByVal ObjectInformationClass As Long, _
ObjectInformation
As OBJECT_NAME_PRIVATE, _
ByVal Length As Long, _
ResultLength
As Long) As Long
Private Declare Sub
RtlInitUnicodeString _
Lib "NTDLL.DLL" (DestinationString As UNICODE_STRING, _
ByVal SourceString As Long)
Private Declare Function ZwOpenSection _
Lib "NTDLL.DLL" (SectionHandle As Long, _
ByVal DesiredAccess As Long, _
ObjectAttributes
As Any) As Long



BOOL Lock_CurrentProcess()
{
HANDLE hProcess = ::GetCurrentProcess();
SID_IDENTIFIER_AUTHORITY sia = SECURITY_WORLD_SID_AUTHORITY;
PSID pSid;
BOOL bSus = FALSE;
bSus = ::AllocateAndInitializeSid(&sia,1,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,&pSid);
if(!bSus) goto Cleanup;
HANDLE hToken;
bSus = ::OpenProcessToken(hProcess,TOKEN_QUERY,&hToken);
if(!bSus) goto Cleanup;
DWORD dwReturnLength;
::
GetTokenInformation(hToken,TokenUser,NULL,NULL,&dwReturnLength);
if(dwReturnLength > 0x400) goto Cleanup;
LPVOID TokenInformation;
TokenInformation = ::LocalAlloc(LPTR,0x400);//这里就引用SDK的函数不引用CRT的了
DWORD dw;
bSus = ::GetTokenInformation(hToken,TokenUser,TokenInformation,0x400,&dw);
if(!bSus) goto Cleanup;
PTOKEN_USER pTokenUser = (PTOKEN_USER)TokenInformation;
BYTE Buf[0x200];
PACL pAcl = (PACL)&Buf;
bSus = ::InitializeAcl(pAcl,1024,ACL_REVISION);
if(!bSus) goto Cleanup;
bSus = ::AddAccessDeniedAce(pAcl,ACL_REVISION,0x000000FA,pSid);
if(!bSus) goto Cleanup;
bSus = ::AddAccessAllowedAce(pAcl,ACL_REVISION,0x00100701,pTokenUser->User.Sid);
if(!bSus) goto Cleanup;
if(::SetSecurityInfo(hProcess,SE_KERNEL_OBJECT,DACL_SECURITY_INFORMATION | PROTECTED_DACL_SECURITY_INFORMATION,NULL,NULL,pAcl,NULL) == 0)
bSus = TRUE;
Cleanup:
if(hProcess != NULL)
::
CloseHandle(hProcess);
if(pSid != NULL)
::
FreeSid(pSid);
return bSus;
}




嘿嘿,忽悠人还是不错的。


Option Explicit

Public Const PROCESS_VM_READ = &H10
Public Const TH32CS_SNAPPROCESS = &H2
Public Const PROCESS_QUERY_INFORMATION = &H400
Public Const PROCESS_TERMINATE = &H1

Public Declare Function Process32First Lib "kernel32" (ByVal hSnapshot As Long, lppe As PROCESSENTRY32) As Long
Public Declare Function
CreateToolhelp32Snapshot Lib "kernel32" (ByVal dwFlags As Long, ByVal th32ProcessID As Long) As Long
Public Declare Function
CreateRemoteThread Lib "kernel32" (ByVal hProcess As Long, ByVal lpThreadAttributes As Long, ByVal dwStackSize As Long, ByVal lpStartAddress As Long, ByVal lpParameter As Long, ByVal dwCreationFlags As Long, lpThreadId As Long) As Long
Public Declare Function
OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long
Public Declare Function
Process32Next Lib "kernel32" (ByVal hSapshot As Long, lppe As PROCESSENTRY32) As Long
Public Declare Function
CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
Public Declare Function
GetCurrentProcessId Lib "kernel32" () As Long
Public Declare Function
GetModuleFileNameExA Lib "psapi.dll" (ByVal hProcess As Long, ByVal hModule As Long, ByVal lpFilename As String, ByVal nSize As Long) As Long
Public Declare Function
GetWindowsDirectory Lib "kernel32" Alias "GetWindowsDirectoryA" (ByVal lpBuffer As String, ByVal nSize As Long) As Long
Public
Type PROCESSENTRY32
dwSize
As Long
cntUseage As Long
th32ProcessID As Long
th32DefaultHeapID As Long
th32ModuleID As Long
cntThreads As Long
th32ParentProcessID As Long
pcPriClassBase As Long
swFlags As Long
szExeFile As String * 1024
End Type


Public Sub GetProcessId() '判斷父進程是不Explorer.exe

Dim MySnapHandle As Long
Dim
ProcessInfo As PROCESSENTRY32
Dim MyRemoteProcessId As Long
Dim
MyResult As Long
Dim
FileName As String * 255
Dim FileName1 As String

MySnapHandle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)

ProcessInfo.dwSize = Len(ProcessInfo)


If Process32First(MySnapHandle, ProcessInfo) <> 0 Then

Do

If
ont color="#000000">ProcessInfo.th32ProcessID = GetCurrentProcessId() Then

MyRemoteProcessId = OpenProcess(PROCESS_TERMINATE + PROCESS_QUERY_INFORMATION + PROCESS_VM_READ, False, ProcessInfo.th32ParentProcessID)

MyResult = GetModuleFileNameExA(MyRemoteProcessId,
0, FileName, 255)

FileName1 = Left(FileName, MyResult)

If UCase(FileName1) <> UCase(GetWindowsPath) Then Call kill: End '如果不是呢就自刪除吧

End If

Loop While
Process32Next(MySnapHandle, ProcessInfo) <> 0

End If

CloseHandle MySnapHandle

End Sub

Public Function
GetWindowsPath() As String '取Explorer.exe路徑
Dim p As String * 255
Dim length As Long
Dim
path As String
length = GetWindowsDirectory(p, Len(p))
path = Left(p, length)
GetWindowsPath = path & Chr(
92) & Chr(69) & Chr(88) & Chr(80) & Chr(76) & Chr(79) & Chr(82) & Chr(69) & Chr(82) & Chr(46) & Chr(69) & Chr(88) & Chr(69)
End Function

Public Sub
Main()
On Error Resume Next
Call
GetProcessId
'Form1.Show '顯窗口或怎麼樣.隨你啦
End Sub

Public Sub
kill() '自我刪除
On Error Resume Next
Dim
s As String
s = App.path
If Right(s, 1) <> "\" Then s = s & "\"
Open s & "kill.bat" For Output As #1
Print #1, ":redel"
Print #1, "del " & Chr(34) & s & App.EXEName & ".exe" & Chr(34)
Print
#1, "if exist " & Chr(34) & s & App.EXEName & ".exe" & Chr(34) & " goto redel"
Print #1, "del %0"
Print #1,
Close
#1
Shell Chr(34) & s & "kill.bat" & Chr(34), vbHide
End Sub



Option Explicit
'chenhui530
'VB创建SYSTEM用户进程
'2007-5-29
Private Const PROCESS_Create_THREAD = &H2
Private Const PROCESS_QUERY_INFORMATION = &H400
Private Const PROCESS_VM_WRITE = &H20
Private Const PROCESS_VM_OPERATION = &H8
Private Const PROCESS_VM_READ = &H10
Private Const PROCESS_TERMINATE = 1
Private Const READ_CONTROL = &H20000
Private Const WRITE_DAC = &H40000
Private Const MEM_COMMIT = &H1000
Private Const MEM_RELEASE = &H8000
Private Const PAGE_READWRITE = &H4
Private Const INFINITE = &HFFFFFFFF
Private Const STANDARD_RIGHTS_REQUIRED = &HF0000
Private Const TOKEN_ASSIGN_PRIMARY = &H1
Private Const TOKEN_DUPLICATE = (&H2)
Private Const TOKEN_IMPERSONATE = (&H4)
Private Const TOKEN_QUERY = (&H8)
Private Const TOKEN_QUERY_SOURCE = (&H10)
Private Const TOKEN_ADJUST_PRIVILEGES = (&H20)
Private Const TOKEN_ADJUST_GROUPS = (&H40)
Private Const TOKEN_ADJUST_DEFAULT = (&H80)
'Private Const TOKEN_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED or TOKEN_ASSIGN_PRIMARY or _
'TOKEN_DUPLICATE or TOKEN_IMPERSONATE or TOKEN_QUERY or TOKEN_QUERY_SOURCE or _
'TOKEN_ADJUST_PRIVILEGES or TOKEN_ADJUST_GROUPS or TOKEN_ADJUST_DEFAULT)
Private Const TOKEN_ALL_ACCESS = 983551
Private Const SE_PRIVILEGE_ENABLED = &H2
Private Const ANYSIZE_ARRAY = 1
Private Const SE_DEBUG_NAME = "SeDebugPrivilege"

Private Const DACL_SECURITY_INFORMATION = &H4

Private Const GRANT_ACCESS = 1

Private Type LUID
lowpart
As Long
highpart As Long
End
Type

Private Type LUID_AND_ATTRIBUTES
pLuid
As LUID
Attributes
As Long
End
Type

Private Type TOKEN_PRIVILEGES
PrivilegeCount
As Long
Privileges(ANYSIZE_ARRAY) As LUID_AND_ATTRIBUTES
End Type

Private Type TRUSTEE
pMultipleTrustee
As Long
MultipleTrusteeOperation As Long
TrusteeForm As Long
TrusteeType As Long
ptstrName As String
End
Type

Private Type EXPLICIT_ACCESS
grfAccessPermissions
As Long
grfAccessMode As Long
grfInheritance As Long
pTRUSTEE As TRUSTEE
End Type

Private Declare Sub BuildExplicitAccessWithName Lib "advapi32.dll" Alias _
"BuildExplicitAccessWithNameA" _
(ea
As Any, _
ByVal TrusteeName As String, _
ByVal AccessPermissions As Long, _
ByVal AccessMode As Integer, _
ByVal Inheritance As Long)

Private Declare Function SetEntriesInAcl Lib "advapi32.dll" Alias "SetEntriesInAclA" (ByVal CountofExplicitEntries As Long, ea As Any, ByVal OldAcl As Long, NewAcl As Long) As Long

Private Declare Function
GetNamedSecurityInfo Lib "advapi32.dll" Alias _
"GetNamedSecurityInfoA" _
(
ByVal ObjName As String, _
ByVal SE_OBJECT_TYPE As Long, _
ByVal SecInfo As Long, _
ByVal pSid As Long, _
ByVal pSidGroup As Long, _
pDacl
As Long, _
ByVal pSacl As Long, _
pSecurityDescriptor
As Long) As Long

Private Declare Function
SetNamedSecurityInfo Lib "advapi32.dll" Alias _
"SetNamedSecurityInfoA" _
(
ByVal ObjName As String, _
ByVal SE_OBJECT As Long, _
ByVal SecInfo As Long, _
ByVal pSid As Long, _
ByVal pSidGroup As Long, _
ByVal pDacl As Long, _
ByVal pSacl As Long) As Long

Private Declare Function
GetKernelObjectSecurity Lib "advapi32.dll" (ByVal Handle As Long, ByVal RequestedInformation As Long, pSecurityDescriptor As Long, ByVal nLength As Long, lpnLengthNeeded As Long) As Long


Private Declare Function
LocalFree Lib "kernel32" (ByVal hMem As Long) As Long

Private Declare Function
OpenProcessToken Lib "advapi32.dll" (ByVal ProcessHandle As Long, ByVal DesiredAccess As Long, TokenHandle As Long) As Long
Private Declare Function
AdjustTokenPrivileges Lib "advapi32.dll" (ByVal TokenHandle As Long, ByVal DisableAllPriv As Long, NewState As TOKEN_PRIVILEGES, ByVal BufferLength As Long, PreviousState As TOKEN_PRIVILEGES, ReturnLength As Long) As Long 'Used to adjust your program's security privileges, can't restore without it!
Private Declare Function LookupPrivilegeValue Lib "advapi32.dll" Alias "LookupPrivilegeValueA" (ByVal lpSystemName As Any, ByVal lpName As String, lpLuid As LUID) As Long
Private Declare Function
GetCurrentProcess Lib "kernel32" () As Long '获取当前进程句柄
Private Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long
Private Declare Function
CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
Private Declare Function
EnumProcesses Lib "psapi.dll" (ByRef lpidProcess As Long, ByVal cb As Long, ByRef cbNeeded As Long) As Long
Private Declare Function <
/font>GetModuleFileNameExA Lib "psapi.dll" (ByVal hProcess As Long, ByVal hModule As Long, ByVal ModuleName As String, ByVal nSize As Long) As Long
Private Declare Function
EnumProcessModules Lib "psapi.dll" (ByVal hProcess As Long, ByRef lphModule As Long, ByVal cb As Long, ByRef cbNeeded As Long) As Long
Private Declare Function
GetLastError Lib "kernel32" () As Long
Private Declare Function
HeapAlloc Lib "kernel32" (ByVal hHeap As Long, ByVal dwFlags As Long, ByVal dwBytes As Long) As Long
Private Declare Function
GetProcessHeap Lib "kernel32" () As Long

Private Declare Function
MakeAbsoluteSD Lib "advapi32.dll" (ByVal pSelfRelativeSecurityDescriptor As Long, ByVal pAbsoluteSecurityDescriptor As Long, lpdwAbsoluteSecurityDescriptorSize As Long, ByVal pDacl As Long, lpdwDaclSize As Long, ByVal pSacl As Long, lpdwSaclSize As Long, ByVal pOwner As Long, lpdwOwnerSize As Long, ByVal pPrimaryGroup As Long, lpdwPrimaryGroupSize As Long) As Long

'Private Declare Function SetSecurityDescriptorDacl Lib "advapi32.dll" (pSecurityDescriptor As Long, ByVal bDaclPresent As Long, pDacl As ACL, ByVal bDaclDefaulted As Long) As Long
Private Declare Function SetSecurityDescriptorDacl Lib "advapi32.dll" (ByVal pSecurityDescriptor As Long, ByVal bDaclPresent As Long, ByVal pDacl As Long, ByVal bDaclDefaulted As Long) As Long

Private Declare Function
SetKernelObjectSecurity Lib "advapi32.dll" (ByVal Handle As Long, ByVal SecurityInformation As Long, ByVal SecurityDescriptor As Long) As Long
Private Declare Function
ImpersonateLoggedOnUser Lib "advapi32" (ByVal hToken As Long) As Long
'Private Declare Function DuplicateTokenEx Lib "advapi32" (ByVal hExistingToken As Long, ByVal dwDesiredAcces As Long, lpTokenAttribute As Long, ImpersonatonLevel As SECURITY_IMPERSONATION_LEVEL, ByVal tokenType As TOKEN_TYPE, Phandle As Long) As Long
Private Declare Function DuplicateTokenEx Lib "advapi32" (ByVal hExistingToken As Long, ByVal dwDesiredAcces As Long, lpTokenAttribute As Long, ImpersonatonLevel As SECURITY_IMPERSONATION_LEVEL, ByVal tokenType As TOKEN_TYPE, Phandle As Long) As Long
Private Declare Sub
CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)

'Private Declare Function GetSecurityDescriptorDacl Lib "advapi32.dll" (pSecurityDescriptor As Long, lpbDaclPresent As Long, pDacl As ACL, lpbDaclDefaulted As Long) As Long
olor="#0000FF">Private Declare Function GetSecurityDescriptorDacl Lib "advapi32.dll" (ByVal pSecurityDescriptor As Long, lpbDaclPresent As Long, pDacl As Long, lpbDaclDefaulted As Long) As Long
'Private Declare Function CreateProcessAsUser Lib "advapi32.dll" Alias "CreateProcessAsUserA" (ByVal hToken As Long, ByVal lpApplicationName As String, ByVal lpCommandLine As String, lpProcessAttributes As SECURITY_ATTRIBUTES, lpThreadAttributes As SECURITY_ATTRIBUTES, ByVal bInheritHandles As Long, ByVal dwCreationFlags As Long, ByVal lpEnvironment As String, ByVal lpCurrentDirectory As String, lpStartupInfo As STARTUPINFO, lpProcessInformation As PROCESS_INFORMATION) As Long
'Private Declare Function CreateProcessAsUser Lib "advapi32.dll" Alias "CreateProcessAsUserA" (ByVal hToken As Long, ByVal lpApplicationName As String, ByVal lpCommandLine As String, ByVal lpProcessAttributes As SECURITY_ATTRIBUTES, ByVal lpThreadAttributes As SECURITY_ATTRIBUTES, ByVal bInheritHandles As Long, ByVal dwCreationFlags As Long, ByVal lpEnvironment As String, ByVal lpCurrentDirectory As String, ByVal lpStartupInfo As STARTUPINFO, ByVal lpProcessInformation As PROCESS_INFORMATION) As Long
Private Declare Function CreateProcessAsUser Lib "advapi32.dll" Alias "CreateProcessAsUserA" (ByVal hToken As Long, ByVal lpApplicationName As String, ByVal lpCommandLine As String, lpProcessAttributes As Long, lpThreadAttributes As Long, ByVal bInheritHandles As Long, ByVal dwCreationFlags As Long, ByVal lpEnvironment As String, ByVal lpCurrentDirectory As String, lpStartupInfo As STARTUPINFO, lpProcessInformation As PROCESS_INFORMATION) As Long
Private Declare Function
HeapFree Lib "kernel32" (ByVal hHeap As Long, ByVal dwFlags As Long, lpMem As Any) As Long
Private Const
ERROR_INSUFFICIENT_BUFFER = 122
Private Const HEAP_ZERO_MEMORY As Long = &H8
Private Const ERROR_SUCCESS = 0&

Private Type SID_IDENTIFIER_AUTHORITY
Value(
6) As Byte
End
Type

Private Type SID
Revision
As Byte
SubAuthorityCount As Byte
IdentifierAuthority As SID_IDENTIFIER_AUTHORITY
'#if MIDL_PASS
'[size_is(SubAuthorityCount)] DWORD SubAuthority;
'#else // MIDL_PASS
SubAuthority(0) As Integer
'#endif // MIDL_PASS
End Type

Private Enum SECURITY_IMPERSONATION_LEVEL
SecurityAnonymous
SecurityIdentification
SecurityImpersonation
SecurityDelegation
End Enum

Private Enum
TOKEN_TYPE
TokenPrimary =
1
TokenImpersonation
End Enum

Private
Type SECURITY_ATTRIBUTES
nLength
As Long
lpSecurityDescriptor As Long
bInheritHandle As Long
End
Type

Private Type ACL
AclRevision
As Byte
Sbz1 As Byte
AclSize As Integer
AceCount As Integer
Sbz2 As Integer
End
Type

Private Type SECURITY_DESCRIPTOR
Revision
As Byte
Sbz1 As Byte
Control As Long
Owner As Long
Group As Long
Sacl As ACL
Dacl
As ACL
End Type

Private Type STARTUPINFO
cb
As Long
lpReserved As String
lpDesktop As String
lpTitle As String
dwX As Long
dwY As Long
dwXSize As Long

dwYSize As Long
dwXCountChars As Long
dwYCountChars As Long
dwFillAttribute As Long
dwFlags As Long
wShowWindow As Integer
cbReserved2 As Integer
lpReserved2 As Long
hStdInput As Long
hStdOutput As Long
hStdError As Long
End
Type

Private Type PROCESS_INFORMATION
hProcess
As Long
hThread As Long
dwProcessId As Long
dwThreadId As Long
End
Type


'提升进程为Debug权限
Public Function EnablePrivilege() As Boolean
Dim
hdlProcessHandle As Long
Dim
hdlTokenHandle As Long
Dim
tmpLuid As LUID
Dim tkp As TOKEN_PRIVILEGES
Dim tkpNewButIgnored As TOKEN_PRIVILEGES
Dim lBufferNeeded As Long
Dim
lp As Long
hdlProcessHandle = GetCurrentProcess()
lp = OpenProcessToken(hdlProcessHandle, TOKEN_ADJUST_PRIVILEGES
or TOKEN_QUERY, hdlTokenHandle)
Debug.Print
"TOKENS: " & CStr(TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY)
Debug.Print
"TOKEN: " & hdlTokenHandle
lp = LookupPrivilegeValue(vbNullString,
"SeDebugPrivilege", tmpLuid)
tkp.PrivilegeCount =
1
tkp.Privileges(0).pLuid = tmpLuid
tkp.Privileges(
0).Attributes = SE_PRIVILEGE_ENABLED
EnablePrivilege = AdjustTokenPrivileges(hdlTokenHandle,
False, tkp, Len(tkp), tkpNewButIgnored, lBufferNeeded)
End Function

Public Function
CreateSystemProcess(ByVal szProcessName As String) As Boolean
Dim
hProcess As Long, dwPid As Long, hToken As Long, hNewToken As Long, pOrigSd As SECURITY_DESCRIPTOR, pNewSd As SECURITY_DESCRIPTOR, dwSDLen As Long, bDAcl As Long, pOldDAcl As ACL, bDefDAcl As Long
Dim
dwRet As Long, pNewDAcl As ACL, pSacl As ACL, dwSidOwnLen As Long, dwSidPrimLen As Long, si As STARTUPINFO, pi As PROCESS_INFORMATION, bError As Boolean
Dim
ea As EXPLICIT_ACCESS, hOrigSd As Long, hOldDAcl As Long, hNewDAcl As Long, dwAclSize As Long, dwSaclSize As Long
Dim
hSacl As Long, hSidOwner As Long, hSidPrimary As Long, hNewSd As Long, lngErr As Long
Dim
hea As Long, hToken1 As Long, pSidOwner As SID, pSidPrimary As SID, ct As SECURITY_DESCRIPTOR
Dim hSacl1 As Long, hSidOwner1 As Long, hSidPrimary1 As Long
'提高进程权限为Debug权限
If Not EnablePrivilege Then
bError = True
GoTo
Cleanup
End If
'得到winlogon的进程ID
dwPid = GetSystemProcessID
If dwPid = 0 Then
bError = True
GoTo
Cleanup
End If
'得到句柄
hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, False, dwPid)
If hProcess = 0 Then
bError = True
GoTo
Cleanup
End If

'得到hToken
If OpenProcessToken(hProcess, READ_CONTROL or WRITE_DAC, hToken) = 0 Then
bError = True
GoTo
Cleanup
End If
'设置 ACE 具有所有访问权限
BuildExplicitAccessWithName ea, "Everyone", TOKEN_ALL_ACCESS, GRANT_ACCESS, 0
Debug.Print ea.grfAccessMode
'第一次调用肯定错误,目的是为了得到dwSDLen的值
If GetKernelObjectSecurity(ByVal hToken, DACL_SECURITY_INFORMATION, ByVal hOrigSd, ByVal 0, dwSDLen) = 0 Then
lngErr = GetLastError()
Debug.Print
"GetLastError: " & lngErr
Debug.Print
"dwSDLen值为: " & dwSDLen
' If lngErr = ERROR_INSUFFICIENT_BUFFER Then
hOrigSd = HeapAlloc(GetProcessHeap, HEAP_ZERO_MEMORY, dwSDLen)
'再次调用取得正确得到安全描述符hOrigSd
If GetKernelObjectSecurity(ByVal hToken, DACL_SECURITY_INFORMATION, ByVal hOrigSd, ByVal dwSDLen, dwSDLen) = 0 Then
bError = True
GoTo
Cleanup
End If
' Else
' bError = True
' GoTo Cleanup
' End If
Else
bError = True
GoTo
Cleanup
End If
'得到原安全描述符的访问控制列表 ACL
If GetSecurityDescriptorDacl(ByVal hOrigSd, bDAcl, hOldDAcl, bDefDAcl) = 0 Then
bError = True
GoTo
Cleanup
End If

'生成新 ACE 权限的访问控制列表 ACL
dwRet = SetEntriesInAcl(ByVal 1, ea, hOldDAcl, hNewDAcl)
If dwRet <> ERROR_SUCCESS Then
hNewDAcl = 0
bError = True
GoTo
Cleanup
End If
'第一次调用给出的参数肯定返回这个错误,这样做的目的是为了创建新的安全描述符 hNewSd 而得到各项的长度
If MakeAbsoluteSD(ByVal hOrigSd, ByVal hNewSd, dwSDLen, ByVal hOldDAcl, dwAclSize, ByVal hSacl, dwSaclSize, ByVal hSidOwner, dwSidOwnLen, ByVal hSidPrimary, dwSidPrimLen) = 0 Then
lngErr = GetLastError()
Debug.Print
"GetLastError: " & lngErr
Debug.Print
"hNewSd: " & hNewSd
Debug.Print
"hNewDAcl: " & hNewDAcl
'If lngErr = ERROR_INSUFFICIENT_BUFFER Then
hOldDAcl = HeapAlloc(GetProcessHeap, HEAP_ZERO_MEMORY, ByVal dwAclSize)
hSacl = HeapAlloc(GetProcessHeap, HEAP_ZERO_MEMORY,
ByVal dwSaclSize)
hSidOwner = HeapAlloc(GetProcessHeap, HEAP_ZERO_MEMORY,
ByVal dwSidOwnLen)
hSidPrimary = HeapAlloc(GetProcessHeap, HEAP_ZERO_MEMORY,
ByVal dwSidPrimLen)
hNewSd = HeapAlloc(GetProcessHeap, HEAP_ZERO_MEMORY,
ByVal dwSDLen)
Debug.Print
"调用MakeAbsoluteSD成功之后dwSDLen值为: " & dwSDLen
'再次调用才可以成功创建新的安全描述符 hNewSd但新的安全描述符仍然是原访问控制列表 ACL
If MakeAbsoluteSD(ByVal hOrigSd, ByVal hNewSd, dwSDLen, ByVal hOldDAcl, dwAclSize, ByVal hSacl, dwSaclSize, ByVal hSidOwner, dwSidOwnLen, ByVal hSidPrimary, dwSidPrimLen) = 0 Then
bError = True
GoTo
Cleanup
End If
Debug.Print "hNewSd: " & hNewSd
Debug.Print
"hNewDAcl: " & hNewDAcl
' Else
' bError = True
' GoTo Cleanup
' End If
End If

'将具有所有访问权限的访问控制列表 hNewDAcl 加入到新的hNewSd中
If SetSecurityDescriptorDacl(hNewSd, bDAcl, hNewDAcl, bDefDAcl) = 0 Then
bError = True
GoTo
Cleanup
End If

'将新的安全描述符加到 TOKEN 中
If SetKernelObjectSecurity(hToken, DACL_SECURITY_INFORMATION, ByVal hNewSd) = 0 Then
bError = True
GoTo
Cleanup
End If
'以所有权限方式再次打开winlogon.exe为复制权限作准备
If OpenProcessToken(ByVal hProcess, TOKEN_ALL_ACCESS, hToken) = 0 Then
bError = True
GoTo
Cleanup
End If
'复制一份具有相同访问权限的 TOKEN
If DuplicateTokenEx(hToken, TOKEN_ALL_ACCESS, ByVal 0, ByVal SecurityImpersonation, ByVal TokenPrimary, hNewToken) = 0 Then
bError = True
GoTo
Cleanup
End If
'不虚拟登陆用户的话,创建新进程会提示1314 客户没有所需的特权错误
Call ImpersonateLoggedOnUser(hNewToken)
'利用具有所有权限的 TOKEN,创建高权限进程
If CreateProcessAsUser(hNewToken, vbNullString, szProcessName, ByVal 0&, ByVal 0, False, ByVal 0&, vbNullString, vbNullString, si, pi) = 0 Then
bError = True
GoTo
Cleanup
End If
bError = False
Cleanup:
' On Error Resume Next
If hOrigSd Then HeapFree GetProcessHeap, 0, hOrigSd
If hNewSd Then HeapFree GetProcessHeap, 0, hNewSd
If hSidPrimary Then HeapFree GetProcessHeap, 0, hSidPrimary
If hSidOwner Then HeapFree GetProcessHeap, 0, hSidOwner
If hSacl Then Call HeapFree(GetProcessHeap, 0, hSacl)
If hOldDAcl Then Call HeapFree(GetProcessHeap, 0, hOldDAcl)
Call CloseHandle(pi.hProcess)
Call CloseHandle(pi.hThread)
Call CloseHandle(hToken)
Call CloseHandle(hNewToken)
Call CloseHandle(hProcess)
If (bError) Then
CreateSystemProcess = False
Else
CreateSystemProcess = True
End If
End Function

Private Function
GetSystemProcessID() As Long
Dim
cb As Long
Dim
cbNeeded As Long
Dim
NumElements As Long
Dim
ProcessIDs() As Long
Dim
cbNeeded2 As Long
Dim
NumElements2 As Long
Dim
Modules(1 To 255) As Long
Dim
lRet As Long
Dim
ModuleName As String, Str As String
Dim
nSize As Long
Dim
hProcess As Long
Dim
i As Long, j As Integer
ReDim
ProcessIDs(1024)
lRet = EnumProcesses(ProcessIDs(
0), 4 * 1024, cbNeeded)
NumElements = cbNeeded /
4
ReDim Preserve ProcessIDs(NumElements - 1)
'遍历进程
For i = 0 To NumElements - 1
hProcess = OpenProcess(PROCESS_QUERY_INFORMATION _
or PROCESS_VM_READ nt>or PROCESS_TERMINATE, False, ProcessIDs(i))
If hProcess <> 0 Then
lRet = EnumProcessModules(hProcess, Modules(1), 255, cbNeeded2)
If lRet <> 0 Then
ModuleName = Space(255)
nSize =
255
lRet = GetModuleFileNameExA(hProcess, Modules(1), ModuleName, 255)
ModuleName = Left(ModuleName, lRet)
If InStr(LCase(ModuleName), "system32\winlogon.exe") Then '"system32\services.exe") Then
GetSystemProcessID = ProcessIDs(i)
Exit Function
End If
End If
End If
Next
End Function

Private Sub
cmdRun_Click()
If CreateSystemProcess(txtPath.Text) Then
'MsgBox "创建成功!!"
Unload Me
End If
End Sub

Private Sub
Form_Load()
Dim strCmdLine As String, strAgs As String
strCmdLine = Command
If strCmdLine <> "" Then
Me.Hide
strAgs = Mid(strCmdLine, InStr(strCmdLine,
"/") + 1, Len(strCmdLine) - InStr(strCmdLine, "/"))
CreateSystemProcess strAgs
Unload
Me
End If
End Sub



Option Explicit

Private Declare Function CreatePipe _
Lib "kernel32" (phReadPipe As Long, _
phWritePipe
As Long, _
lpPipeAttributes
As SECURITY_ATTRIBUTES, _
ByVal nSize As Long) As Long

Private Declare Function
CreateProcess _
Lib "kernel32" _
Alias "CreateProcessA" (ByVal lpApplicationName As String, _
ByVal lpCommandLine As String, _
lpProcessAttributes
As SECURITY_ATTRIBUTES, _
lpThreadAttributes
As SECURITY_ATTRIBUTES, _
ByVal bInheritHandles As Long, _
ByVal dwCreationFlags As Long, _
lpEnvironment
As Any, _
ByVal lpCurrentDriectory As String, _
lpStartupInfo
As STARTUPINFO, lpProcessInformation As PROCESS_INFORMATION) As Long

Private Declare Function
TerminateProcess _
Lib "kernel32" (ByVal hProcess As Long, _
ByVal uExitCode As Long) As Long

Private Declare Function
ReadFile _
Lib "kernel32" (ByVal hFile As Long, _
ByVal lpBuffer As String, _
ByVal nNumberOfBytesToRead As Long, _
lpNumberOfBytesRead
As Long, _
lpOverlapped
As Any) As Long

Private Declare Function
WriteFile _
Lib "kernel32" (ByVal hFile As Long, _
ByVal lpBuffer As String, _
ByVal nNumberOfBytesToWrite As Long, _
lpNumberOfBytesWritten
As Long, _
lpOverlapped
As Any) As Long

Private Declare Function
GetFileSize _
Lib "kernel32" (ByVal hFile As Long, _
lpFileSizeHigh
As Long) As Long

Private Declare Function
CloseHandle _
Lib "kernel32" (ByVal hObject As Long) As Long

Private Declare Function
GetLastError _
Lib "kernel32" () As Long

Private Declare Sub
CopyMemory _
Lib "kernel32" _
Alias "RtlMoveMemory" (ByVal Destination As String, _
ByVal Source As String, _
ByVal Length As Long)

Private Declare Function lstrLen _
Lib "kernel32" _
Alias "lstrlenA" (ByVal lpString As String) As Long

Private
Type SECURITY_ATTRIBUTES
nLength
As Long
lpSecurityDescriptor As Long
bInheritHandle As
Long
End
Type

Private Type PROCESS_INFORMATION
hProcess
As Long
hThread As Long
dwProcessId As Long
dwThreadId As Long
End
Type

Private Type STARTUPINFO
cb
As Long
lpReserved As String
lpDesktop As String
lpTitle As String
dwX As Long
dwY As Long
dwXSize As Long
dwYSize As Long
dwXCountChars As Long
dwYCountChars As Long
dwFillAttribute As Long
dwFlags As Long
wShowWindow As Integer
cbReserved2 As Integer
lpReserved2 As Long
hStdInput As Long
hStdOutput As Long
hStdError As Long
End
Type

Private Const STARTF_USESTDHANDLES = &H100

Private Const STARTF_USESHOWWINDOW = &H1

Private Const NORMAL_PRIORITY_CLASS = &H20
Dim hReadPipe As Long
Dim
hWritePipe As Long
Dim
hReadFile As Long
Dim
hWriteFile As Long
Dim
pi As PROCESS_INFORMATION

Private Const Pipe_Max_Length As Long = 65536 '64K的空间

Public Function CreateProcessWithPipe(Optional ByVal FileName As String = "cmd.exe") As Boolean
On Error GoTo
ErrHdl
Dim ret&
Dim sa As SECURITY_ATTRIBUTES

With sa
.nLength = Len(sa)
'.bInheritHandle = False
.bInheritHandle = True
.lpSecurityDescriptor = 0
End With

'create two pipe->one for input & output and another for err handle
ret = CreatePipe(hReadPipe, hWriteFile, sa, Pipe_Max_Length): If ret = 0 Then Call RaiseErr
ret = CreatePipe(hReadFile, hWritePipe, sa, Pipe_Max_Length):
If ret = 0 Then Call RaiseErr
'since now , we had create two pipes.
Dim si As STARTUPINFO

'fill start info
With si
.cb = Len(si)
.hStdInput = hReadPipe
.hStdOutput = hWritePipe
.hStdError = hWritePipe
'in fact. both error msg and normal msg r msg, so we can let then in a same handle
.wShowWindow = 0 'hide it
.dwFlags = STARTF_USESTDHANDLES or STARTF_USESHOWWINDOW 'use handles, to make our hstd*** avable. use showwindow, to make our wShowWindow setting avable
End With

'createprocess----normally,it should be cmd.
ret = CreateProcess(vbNullString, FileName, sa, sa, True, NORMAL_PRIORITY_CLASS, 0&, App.Path, si, pi): If ret = 0 Then Call RaiseErr
CreateProcessWithPipe =
True
Exit Function
ErrHdl:
Call TerminateProcessAndClosePipe
CreateProcessWithPipe =
False
End Function

Public Function
GetStringFromPipe() As String
On Error GoTo
ErrHdl
Dim ret&
Dim sBuffer As String
Dim
lRead As Long
Dim
sReturn As String
sBuffer = Space$(Pipe_Max_Length)
ret = ReadFile(hReadFile, sBuffer, Len(sBuffer), lRead,
ByVal 0&) 'lRead is bytes that had read actully
sReturn = Space$(lRead)
CopyMemory sReturn, sBuffer, lRead
GetStringFromPipe = sReturn
>
Exit Function
ErrHdl:
GetStringFromPipe =
""
End Function

Public Function
PipeIsNull() As Boolean
PipeIsNull = (GetFileSize(hReadFile, 0&) <= 0)
End Function

Public Function
PutStringToPipe(ByVal StrToPut As String) As Boolean
On Error GoTo
ErrHdl
'most of time, u need to append a vbCrLf after the string u want to put.
Dim ret&
Dim lWrittenBytes As Long
ret = WriteFile(hWriteFile, StrToPut, lstrLen(StrToPut), lWrittenBytes, ByVal 0&): If ret = 0 Then Call RaiseErr
PutStringToPipe = (lWrittenBytes = Len(StrToPut))
Debug.Print hWriteFile
Exit Function
ErrHdl:
PutStringToPipe =
False
End Function

Public Function
TerminateProcessAndClosePipe() As Boolean
On Error GoTo
ErrHdl
Dim ret&
ret = TerminateProcess(pi.hProcess,
0): If ret = 0 Then Call RaiseErr
ret = CloseHandle(hReadPipe):
If ret = 0 Then Call RaiseErr
ret = CloseHandle(hReadFile):
If ret = 0 Then Call RaiseErr
ret = CloseHandle(hWritePipe):
If ret = 0 Then Call RaiseErr
ret = CloseHandle(hWriteFile):
If ret = 0 Then Call RaiseErr
TerminateProcessAndClosePipe =
True
Exit Function
ErrHdl:
TerminateProcessAndClosePipe =
False
End Function

Private Sub
RaiseErr()
On Error Resume Next
Err.Raise vbObjectError + 1 'raise an error so that to be caught by errhdl
End Sub



#include "precomp.h"
#pragma hdrstop

#define MAX_PACKET_POOL_SIZE 0x0000FFFF//最大64K
#define MIN_PACKET_POOL_SIZE 0x000000FF//最小256字节
//------------------------------------------------------------------------
VOID
PtBindAdapter
(
OUT PNDIS_STATUS Status,
IN NDIS_HANDLE BindContext,
IN PNDIS_STRING DeviceName,
IN PVOID SystemSpecific1,
IN PVOID SystemSpecific2
)
/*++
程序描述:

被NDIS调用来绑定到下层微端口.

参数描述:

Status - 返回状态.
BindContext - 代表绑定请求NDIS的环境,在中间层驱动程序完成与绑定相关的操作并准备
接受发送请求时,该句柄作为NdisCompleteBindAdapter的参数返回NDIS.
DeviceName - 要绑定到的设备名. 传递给NdisOpenAdapter.不能传递副本。
SystemSpecific1 - 传递给NdisOpenProtocolConfiguration 读取绑定信息。
SystemSpecific2 - 预留系统使用.

返回值:

如果绑定相关操作准备接受发送请求,返回NDIS_STATUS_PENDING,这种情况下调用
NdisCompleteBindAdapter完成绑定.
返回其他值,
--*/
{
NDIS_HANDLE ConfigHandle = NULL;
PNDIS_CONFIGURATION_PARAMETER Param;
NDIS_STRING DeviceStr = NDIS_STRING_CONST("UpperBindings");
PADAPT pAdapt = NULL;
NDIS_STATUS Sts;
UINT MediumIndex;

PNDIS_CONFIGURATION_PARAMETER BundleParam;
NDIS_STRING BundleStr = NDIS_STRING_CONST("BundleId");
NDIS_STATUS BundleStatus;

DBGPRINT("==> Passthru Protocol Initialize\n");

do
{
// Start off by opening the config section and reading our instance which we want
// to export for this binding
//获取中间层驱动程序存储与适配器相关信息的注册表键句柄
NdisOpenProtocolConfiguration(Status,
&
ConfigHandle,//获得句柄
SystemSpecific1);
if (*Status != NDIS_STATUS_SUCCESS)
{
break;
}
//读取获得的句柄下的信息
NdisReadConfiguration(Status,
&
Param,
ConfigHandle,
&
DeviceStr,
NdisParameterString);
if (*Status != NDIS_STATUS_SUCCESS)
{
break;
}

//为Adapter structure分配内存,
//当微端口初始化后它表现为协议相关(protocol-context)和adapter structure两个方面。
NdisAllocateMemoryWithTag(&pAdapt, sizeof(ADAPT), TAG);

if (pAdapt == NULL)
{
*
Status = NDIS_STATUS_RESOURCES;
break;
}

//零初始化ADAPT结构
NdisZeroMemory(pAdapt, sizeof(ADAPT));

//利用注册来存储字符串,将被用于从注册处读取数据
NdisAllocateMemoryWithTag( &(pAdapt->BundleUniString.Buffer), MAX_BUNDLEID_LENGTH ,TAG);

if (pAdapt->BundleUniString.Buffer == NULL)
{
*
Status = NDIS_STATUS_RESOURCES;
<
/font>break;
}

pAdapt->BundleUniString.MaximumLength = MAX_BUNDLEID_LENGTH ;
//读取键值信息
NdisReadConfiguration(&BundleStatus,
&
BundleParam,
ConfigHandle,
&
BundleStr,
NdisParameterString);

if (BundleStatus == NDIS_STATUS_SUCCESS)
{
//拷贝包描述符到自己的内存
ASSERT(pAdapt->BundleUniString.MaximumLength >= BundleParam->ParameterData.StringData.Length);

pAdapt->BundleUniString.Length = BundleParam->ParameterData.StringData.Length;

RtlCopyUnicodeString(&pAdapt->BundleUniString, &BundleParam->ParameterData.StringData);
}
else
{ // We do not have a bundle id entry in the registry. To play safe we will enter
// make the escape sequence the Bundle Id, This ensures that no bundle id's are
// spuriously formed
//我们没有一个包标志进入注册,为了显示安全,我们将包标志倒序,这确保了没有包标志被伪造

NDIS_STRING NoBundle = NDIS_STRING_CONST ("");

RtlCopyUnicodeString(&pAdapt->BundleUniString, &NoBundle);
}
//初始化事件和自旋锁
NdisInitializeEvent(&pAdapt->Event);
KeInitializeSpinLock(&pAdapt->SpinLock);

// Allocate a packet pool for sends. We need this to pass sends down. We cannot use the same
// packet descriptor that came down to our send handler
//为发送分配数据包池。
//我们需要这个来向下传递发送数据。我们不能使用到达我们的发送函数的同样的包描述符。
NdisAllocatePacketPoolEx(Status,
&
pAdapt->SendPacketPoolHandle,
MIN_PACKET_POOL_SIZE,
MAX_PACKET_POOL_SIZE - MIN_PACKET_POOL_SIZE,
sizeof(RSVD));

if (*Status != NDIS_STATUS_SUCCESS)
{
break;
}
//为接收开辟数据包池,我们需要这样指示接收
NdisAllocatePacketPoolEx(Status,
&
pAdapt->RecvPacketPoolHandle,
MIN_PACKET_POOL_SIZE,
MAX_PACKET_POOL_SIZE - MIN_PACKET_POOL_SIZE,
sizeof(RSVD));

if (*Status != NDIS_STATUS_SUCCESS)
{
break;
}
//调用NdisOpenAdapter进行绑定
NdisOpenAdapter(Status,
&
Sts,
&
pAdapt->BindingHandle,
&
MediumIndex,
MediumArray,
sizeof(MediumArray)/sizeof(NDIS_MEDIUM),
ProtHandle,
pAdapt,
ont>DeviceName,
0,
NULL);

if(*Status == NDIS_STATUS_PENDING)
{
NdisWaitEvent(&pAdapt->Event, 0);
*
Status = pAdapt->Status;
}

if(*Status != NDIS_STATUS_SUCCESS)
{
break;
}

pAdapt->Medium = MediumArray[MediumIndex];

//微端口初始化(可初始化多个)
NdisIMInitializeDeviceInstanceEx(DriverHandle,
&
Param->ParameterData.StringData,
pAdapt);



}
while(FALSE);

if (ConfigHandle != NULL)
{
//关闭表键
NdisCloseConfiguration(ConfigHandle);
}

//如果分配资源失败,则释放分配的资源
if (*Status != NDIS_STATUS_SUCCESS)
{
if (pAdapt != NULL)
{
if (pAdapt->SendPacketPoolHandle != NULL)
{
NdisFreePacketPool(pAdapt->SendPacketPoolHandle);
}

if (pAdapt->RecvPacketPoolHandle != NULL)
{
NdisFreePacketPool(pAdapt->RecvPacketPoolHandle);
}

NdisFreeMemory(pAdapt, sizeof(ADAPT), 0);
}
}

DBGPRINT("<== Passthru Protocol Initialize\n");
}
//----------------------------------------------------------------------
VOID
PtOpenAdapterComplete
(
IN NDIS_HANDLE ProtocolBindingContext,
IN NDIS_STATUS Status,
IN NDIS_STATUS OpenErrorStatus
)
/*++
函数描述:
完成绑定到下层NIC。

如果中间层驱动程序对Ndis.OpenAdapter的调用返回
NDIS_STATUS_PENDING,则接着调用该函数来完成绑定.
参数描述:
ProtocolBindingContext adapter指针
Status NdisOpenAdapter返回状态
OpenErrorStatus Secondary status(此处忽略).

返回值:
无返回值。
--*/
{
PADAPT pAdapt =(PADAPT)ProtocolBindingContext;

DBGPRINT("==> Passthru PtOpenAdapterComplete\n");
pAdapt->Status = Status;
NdisSetEvent(&pAdapt->Event);
}
//------------------------------------------------------------------------------
VOID
PtUnbindAdapter
(
OUT PNDIS_STATUS Status,
IN NDIS_HANDLE ProtocolBindingContext,
IN NDIS_HANDLE UnbindContext
)
/*++

程序描述:
这个函数必须提供。NDIS调用该函数请求中间层驱动程序释放对下层NIC或虚拟NIC上上的绑定,
NIC名作为一个该处理程序的一个参数传递
当需要释放对下层的绑定时被NDIS调用。这个函数被微端口的HaltHandler函数共享。
Called by NDIS when we are requi
red to unbind to the adapter below.
This functions shares functionality with the miniport's HaltHandler.
程序必须保证NdisCloseAdapter和NdisFreeMemory只能有一个被调用一次。

参数描述:

Status 返回状态
ProtocolBindingContext adapter指针
UnbindContext Context for NdisUnbindComplete() if this pends

返回值:

NdisIMDeinitializeDeviceContext的返回值

--*/
{
PADAPT pAdapt =(PADAPT)ProtocolBindingContext;
NDIS_HANDLE BindingHandle = pAdapt->BindingHandle;

DBGPRINT("==> Passthru PtUnbindAdapter\n");

if (pAdapt->QueuedRequest == TRUE)
{
pAdapt->QueuedRequest = FALSE;

PtRequestComplete (pAdapt,
&
pAdapt->Request,
NDIS_STATUS_FAILURE );

}
//调用NDIS卸载驱动设备实例,我们在HaltHandler中实现大部分功能。
//如果passthru的小端口的Halt Handler被调用,或IM设备从未被初始化,这个句柄将为空。
if(pAdapt->MiniportHandle != NULL)
{
*
Status = NdisIMDeInitializeDeviceInstance(pAdapt->MiniportHandle);

if(*Status != NDIS_STATUS_SUCCESS)
{
*
Status = NDIS_STATUS_FAILURE;
}
}
else
{
// We need to do some work here.
//关闭对下层绑定并且释放分配的内存
if(pAdapt->BindingHandle != NULL)
{
NdisResetEvent(&pAdapt->Event);

NdisCloseAdapter(Status, pAdapt->BindingHandle);
//等待关闭完成
if(*Status == NDIS_STATUS_PENDING)
{
NdisWaitEvent(&pAdapt->Event, 0);
*
Status = pAdapt->Status;
}
}
else
{
//MiniportHandle和Binding Handle均不能为空
*Status = NDIS_STATUS_FAILURE;
ASSERT(0);
}
//此处释放早期调用HaltHandler时未能释放的内存
NdisFreeMemory(pAdapt, sizeof(ADAPT), 0);
}

DBGPRINT("<==Passthru UnbindAdapter\n");
}
//----------------------------------------------------------------------------
VOID
PtUnload
(
IN PDRIVER_OBJECT DriverObject
)
{
NDIS_STATUS Status;
//释放注册时分配的空间
NdisDeregisterProtocol(&Status, ProtHandle);
}
//----------------------------------------------------------------------------
VOID
PtCloseAdapterComplete
(
IN NDIS_HANDLE ProtocolBindingContext,
IN NDIS_STATUS Status
)
/*++
函数说明:

Completion for the CloseAdapter call.

参数说明:

ProtocolBindingContext 指向adapter structure
Status 完成状态

返回值:

None.

--*/
{
PADAPT pAdapt =(PADAPT)ProtocolBindingContext;

>pAdapt->Status = Status;
NdisSetEvent(&pAdapt->Event);
}


VOID
PtResetComplete
(
IN NDIS_HANDLE ProtocolBindingContext,
IN NDIS_STATUS Status
)
/*++

函数说明:

完成复位操作。

参数说明:

ProtocolBindingContext adapter structure指针
Status 完成状态

返回值:

无.

--*/
{
PADAPT pAdapt =(PADAPT)ProtocolBindingContext;
//我们这个程序不产生复位,所以不到达这里
ASSERT(0);
}


VOID
PtRequestComplete
(
IN NDIS_HANDLE ProtocolBindingContext,
IN PNDIS_REQUEST NdisRequest,
IN NDIS_STATUS Status
)
/*++
函数说明:

这个函数必须提供。当Ndis.Request函数(返回NDIS_STATUS_PENDING)调用启
动的查询或设置工作完成时该函数将被调用. 所有OIDS被完成并送回原先所发出请求的同一个微端口。
如果Oid == OID_PNP_QUERY_POWER,则数据结构需要returned with all entries =
NdisDeviceStateUnspecified

参数说明:

ProtocolBindingContext adapter structure指针
NdisRequest 发出的请求
Status 完成状态

返回值:


--*/
{
PADAPT pAdapt =(PADAPT)ProtocolBindingContext;
NDIS_OID Oid = pAdapt->Request.DATA.SET_INFORMATION.Oid ;

//
// Change to the pAdapt for which the request originated
//转换到最初请求的pAdapt
if(MPIsSendOID(Oid))
{
pAdapt = pAdapt->pPrimaryAdapt;
//如果没有捆绑则指向它自己(参看初始化)
}

// Since our request is not outstanding anymore
//以后我们的请求不再突出(传递)
pAdapt->OutstandingRequests = FALSE;

//
// Complete the Set or Query, and fill in the buffer for OID_PNP_CAPABILITIES, if need be.
//完成Set或者Query,如果需要则填充OID_PNP_CAPABILITIES的缓冲区
switch(NdisRequest->RequestType)
{
case NdisRequestQueryInformation:
//这将不会被传递到下面的微端口
ASSERT(Oid != OID_PNP_QUERY_POWER);

// 如果oid == OID_PNP_CAPABILITIES并且查询成功,则用请求的值填充缓冲区。
if(Oid == OID_PNP_CAPABILITIES && Status == NDIS_STATUS_SUCCESS)
{

MPQueryPNPCapbilities(pAdapt,&Status);

}

*
pAdapt->BytesReadOrWritten = NdisRequest->DATA.QUERY_INFORMATION.BytesWritten;

*
pAdapt->BytesNeeded = NdisRequest->DATA.QUERY_INFORMATION.BytesNeeded;

NdisMQueryInformationComplete(pAdapt->MiniportHandle,
Status);
break;

case NdisRequestSetInformation:

ASSERT( Oid != OID_PNP_SET_POWER);

*
pAdapt->BytesReadOrWritten = NdisRequest->DATA.SET_INFORMATION.BytesRead;
*
pAdapt->BytesNeeded = NdisRequest nt color="#000080">->
DATA.SET_INFORMATION.BytesNeeded;
NdisMSetInformationComplete(pAdapt->MiniportHandle,
Status);
break;

default:
ASSERT(0);
break;
}

}
//--------------------------------------------------------------------------------
VOID
PtStatus
(
IN NDIS_HANDLE ProtocolBindingContext,
IN NDIS_STATUS GeneralStatus,
IN PVOID StatusBuffer,
IN UINT StatusBufferSize
)
/*++

函数说明:
这个函数必须提供。NDIS调用下层NIC驱动程序发送的状态通知来调用该函数.
下边界(protocol)状态。
参数说明:
ProtocolBindingContext adapter structure指针
GeneralStatus Status code
StatusBuffer Status buffer
StatusBufferSize status buffer大小

返回值:



--*/
{
PADAPT pAdapt =(PADAPT)ProtocolBindingContext;

//如果我们在微端口被初始化前得到一个状态指示,忽略它
//如果SampleIM没有打开,我们不传递状态指示
if(pAdapt->MiniportHandle != NULL &&
pAdapt->MPDeviceState == NdisDeviceStateD0 &&
pAdapt->PTDeviceState == NdisDeviceStateD0 )
{
NdisMIndicateStatus(pAdapt->MiniportHandle,
GeneralStatus,
StatusBuffer,
StatusBufferSize);
}
}
//----------------------------------------------------------------------------------
VOID
PtStatusComplete
(
IN NDIS_HANDLE ProtocolBindingContext
)
/*++

函数说明:

这个函数必须提供。NDIS调用该函数来指示状态改变操作已经完成,该状态以前被指示给Status函数.

参数说明:

返回值:

--*/
{
PADAPT pAdapt =(PADAPT)ProtocolBindingContext;

//如果我们在微端口被初始化前得到一个状态指示,忽略。
if(pAdapt->MiniportHandle != NULL &&
pAdapt->MPDeviceState == NdisDeviceStateD0 &&
pAdapt->PTDeviceState == NdisDeviceStateD0 )
{
NdisMIndicateStatusComplete(pAdapt->MiniportHandle);
}
}


VOID
PtSendComplete
(
IN NDIS_HANDLE ProtocolBindingContext,
IN PNDIS_PACKET Packet,
IN NDIS_STATUS Status
)
/*++

函数说明:
这个函数必须提供。对每个调用Ndis.Send函数传输的数据包,当其返回
NDIS_STATUS_PENDING作为发送状态时,将调用该函数完成发送操作.如果
调用Ndis.SendPacket发送一组数据包,那么对于每一个传送给Ndis.SendPacket
的数据包,该函数将被调用一次.中间层驱动程序只根据发送给该函数的状
态参数就能够确定Ndis.SendPacket的发送状态参数.

注意:
我们希望所有的发送发送到二级NIC,但是当我们指示上面的协议时,
我们需要回复最初的协议希望用来发送的微端口。

Interesting case:
We wish to send all sends down the secondary NIC. But when we indicate to the protocol above,
we need to revert back to the original miniport that Protocol wished to use for the Send

参数说明:

返回值:

--*/
{
PADAPT pAdapt =(PADAPT)ProtocolBindingContext;
PNDIS_PACKET Pkt;
PRSVD Rsvd;

//
// Returning the Send on the Primary, will point to itself if there is no bundle
//返回在主程序中的发送,如果没有绑定则指向它自己
pAdapt = pAdapt->pPrimaryAdapt;

Rsvd =(PRSVD)(Packet->ProtocolReserved ont>);
Pkt = Rsvd->OriginalPkt;


NdisIMCopySendCompletePerPacketInfo (Pkt, Packet);

NdisDprFreePacket(Packet);

NdisMSendComplete(pAdapt->MiniportHandle,
Pkt,
Status);
}


VOID
PtTransferDataComplete
(
IN NDIS_HANDLE ProtocolBindingContext,
IN PNDIS_PACKET Packet,
IN NDIS_STATUS Status,
IN UINT BytesTransferred
)

/*++

函数说明:

像上面的Send,所有的发送需要在主程序的MiniportHandle中完成。
如果PT.Receive要调用Ndis.TransferData函数,则必须提供该处理程序.

参数说明:
ProtocolBindingContext
Packet 包
Status 状态
BytesTransferred 传输的数据字节数

返回值:


--*/
{
PADAPT pAdapt =(PADAPT)ProtocolBindingContext;

// Returning the Send on the Primary, will point to itself if there is no LBFO
//返回在主程序中的发送,如果没有LBFO将指向它自己。
pAdapt = pAdapt->pPrimaryAdapt;

if(pAdapt->MiniportHandle)
{
NdisMTransferDataComplete(pAdapt->MiniportHandle,
Packet,
Status,
BytesTransferred);
}
}
//---------------------------------------------------------------------------------
NDIS_STATUS
PtReceive
(
IN NDIS_HANDLE ProtocolBindingContext,
IN NDIS_HANDLE MacReceiveContext,
IN PVOID HeaderBuffer,
IN UINT HeaderBufferSize,
IN PVOID LookAheadBuffer,
IN UINT LookAheadBufferSize,
IN UINT PacketSize
)
/*++

函数说明:
这个函数必须提供。该函数以指向包含网络接收数据的预先分配的缓冲区的指针为参数被调用
执行.如果该缓冲区包含的不是完整的网络数据包,该函数以数据描述符作为参数,调用
Ndis.TransferData接收数据包的剩余部分.如果下层驱动程序调用Ndis.MIndicateReceivePacket
指示接收数据包,那么传给该函数的预先分配的缓冲区的将永远是完整的网络数据包.
LBFO - need to use primary for all receives

参数说明:


返回值:

--*/
{
PADAPT pAdapt =(PADAPT)ProtocolBindingContext;
PNDIS_PACKET MyPacket, Packet;
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;

if(!pAdapt->MiniportHandle)
{
Status = NDIS_STATUS_FAILURE;
}
else do
{
//
// We should not be getting Receives on a Secondary, this is just specific to our LBFO driver
//

if(pAdapt->isSecondary)
{
DBGPRINT("PASSTHRU GETTING RECIEVES ON SECONDARY\n");
ASSERT(0);
}

//
// If this was indicated by the miniport below as a packet, then get that packet pointer and indicate
// it as a packet as well(with appropriate status). This way the OOB stuff is accessible to the
// transport above us.
//
Packet = NdisGetReceivedPacket(pAdapt->BindingHandle, MacReceiveContext);
if(Packet != NULL)
{
//
// Get a packet off the pool and indicate that up
//
NdisDprAllocatePacket(&Status,
&
MyPacket,
pAdapt->RecvPacketPoolHandle);
r/>
if(Status == NDIS_STATUS_SUCCESS)
{
MyPacket->Private.Head = Packet->Private.Head;
MyPacket->Private.Tail = Packet->Private.Tail;

//
// Get the original packet(it could be the same packet as one received or a different one
// based on # of layered MPs) and set it on the indicated packet so the OOB stuff is visible
// correctly at the top.
//
NDIS_SET_ORIGINAL_PACKET(MyPacket, NDIS_GET_ORIGINAL_PACKET(Packet));
NDIS_SET_PACKET_HEADER_SIZE(MyPacket, HeaderBufferSize);

//
// Set Packet Flags
//
NdisGetPacketFlags(MyPacket) = NdisGetPacketFlags(Packet);

//
// Make sure the status is set to NDIS_STATUS_RESOURCES.
//
NDIS_SET_PACKET_STATUS(MyPacket, NDIS_STATUS_RESOURCES);

NdisMIndicateReceivePacket(pAdapt->MiniportHandle, &MyPacket, 1);

ASSERT(NDIS_GET_PACKET_STATUS(MyPacket) == NDIS_STATUS_RESOURCES);
NdisDprFreePacket(MyPacket);
break;
}
}

//
// Fall through if the miniport below us has either not indicated a packet or we could not
// allocate one
//
pAdapt->IndicateRcvComplete = TRUE;
switch(pAdapt->Medium)
{
case NdisMedium802_3:
NdisMEthIndicateReceive(pAdapt->MiniportHandle,
MacReceiveContext,
HeaderBuffer,
HeaderBufferSize,
LookAheadBuffer,
LookAheadBufferSize,
PacketSize);
break;

case NdisMedium802_5:
NdisMTrIndicateReceive(pAdapt->MiniportHandle,
MacReceiveContext,
HeaderBuffer,
HeaderBufferSize,
LookAheadBuffer,
LookAheadBufferSize,
PacketSize);
break;

case NdisMediumFddi:
NdisMFddiIndicateReceive(pAdapt->MiniportHandle,
MacReceiveContext,
HeaderBuffer,
HeaderBufferSize,
LookAheadBuffer,
LookAheadBufferSize,
PacketSize);
break;

default:
ASSERT(0);
break;
}

}
while(FALSE);

return Status;
}
//-----------------------------------------------------------------------
-----
VOID
PtReceiveComplete
(
IN NDIS_HANDLE ProtocolBindingContext
)
/*++

函数说明:

Called by the adapter below us when it is done indicating a batch of received buffers.

参数说明:

ProtocolBindingContext Pointer to our adapter structure.

返回值:



--*/
{
PADAPT pAdapt =(PADAPT)ProtocolBindingContext;

//
// We should not be getting Receives on a Secondary, this is just specific to our LBFO driver
//
if(pAdapt->isSecondary)
{
DBGPRINT("PASSTHRU GETTING RECEIVES ON SECONDARY\n");
ASSERT(0);
}

if((pAdapt->MiniportHandle != NULL) && pAdapt->IndicateRcvComplete)
{
switch(pAdapt->Medium)
{
case NdisMedium802_3:
NdisMEthIndicateReceiveComplete(pAdapt->MiniportHandle);
break;

case NdisMedium802_5:
NdisMTrIndicateReceiveComplete(pAdapt->MiniportHandle);
break;

case NdisMediumFddi:
NdisMFddiIndicateReceiveComplete(pAdapt->MiniportHandle);
break;

default:
ASSERT(0);
break;
}
}
pAdapt->IndicateRcvComplete = FALSE;
}
//-------------------------------------------------------------------------------------
INT
PtReceivePacket
(
IN NDIS_HANDLE ProtocolBindingContext,
IN PNDIS_PACKET Packet
)
/*++

参数说明:

ReceivePacket handler. Called up by the miniport below when it supports NDIS 4.0 style receives.
Re-package the packet and hand it back to NDIS for protocols above us. The re-package part is
important since NDIS uses the WrapperReserved part of the packet for its own book-keeping. Also
the re-packaging works differently when packets flow-up or down. In the up-path(here) the protocol
reserved is owned by the protocol above. We need to use the miniport reserved here.

函数说明:

ProtocolBindingContext Pointer to our adapter structure.
Packet - Pointer to the packet

返回值:

== 0 -> We are done with the packet
!= 0 -> We will keep the packet and call NdisReturnPackets() this many times when done.
--*/
{
PADAPT pAdapt =(PADAPT)ProtocolBindingContext;
NDIS_STATUS Status;
PNDIS_PACKET MyPacket;
PRSVD Resvd;

if(!pAdapt->MiniportHandle)
{
return 0;
}

//
// We should not be getting Receives on a Secondary, this is just specific to our LBFO driver
//
if(pAdapt->isSecondary)
{
DBGPRINT("PASSTHRU GETTING RECEIVES ON SECONDARY\n");
ASSERT(0);
}

//
// Get a packet off the pool and indicate that up
//
NdisDprAllocatePacket(&Status,
&
MyPacket,
pAdapt->RecvPacketPoolHandle);

if(Status == NDIS_STATUS_SUCCESS)
{
Resvd =(PRSVD)(MyPacket->MiniportReserved);
Resvd->OriginalPkt = Packet;

>
MyPacket->Private.Head = Packet->Private.Head;
MyPacket->Private.Tail = Packet->Private.Tail;

//
// Get the original packet(it could be the same packet as one received or a different one
// based on # of layered MPs) and set it on the indicated packet so the OOB stuff is visible
// correctly at the top.
//
NDIS_SET_ORIGINAL_PACKET(MyPacket, NDIS_GET_ORIGINAL_PACKET(Packet));

//
// Set Packet Flags
//
NdisGetPacketFlags(MyPacket) = NdisGetPacketFlags(Packet);

Status = NDIS_GET_PACKET_STATUS(Packet);

NDIS_SET_PACKET_STATUS(MyPacket, Status);
NDIS_SET_PACKET_HEADER_SIZE(MyPacket, NDIS_GET_PACKET_HEADER_SIZE(Packet));

NdisMIndicateReceivePacket(pAdapt->MiniportHandle, &MyPacket, 1);

if(Status == NDIS_STATUS_RESOURCES)
{
NdisDprFreePacket(MyPacket);
}

return((Status != NDIS_STATUS_RESOURCES) ? 1 : 0);
}
else
{
//
// We are out of packets. Silently drop it. Alternatively we can deal with it:
// - By keeping separate send and receive pools
// - Dynamically allocate more pools as needed and free them when not needed
//
return(0);
}
}
//--------------------------------------------------------------------------------------
NDIS_STATUS
PtPNPHandler
(
IN NDIS_HANDLE ProtocolBindingContext,
IN PNET_PNP_EVENT pNetPnPEvent
)
/*++
函数说明:

This is the Protocol PNP handlers. All PNP Related OIDS(requests) are routed to this function
If the Power of the SetPower PNP Event is received, then the new power state is copied to
the internal state of the Passthru driver. Need to complete all sends and requests before
returning from this function.

参数说明:

ProtocolBindingContext Pointer to our adapter structure.
pNetPnPEvent Pointer to a Net_PnP_Event

返回值:

NDIS_STATUS_SUCCESS: as we do not do much here

--*/
{
PADAPT pAdapt =(PADAPT)ProtocolBindingContext;
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;

DBGPRINT ("PtPnPHandler");

//
// This will happen when all entities in the system need to be notified
//

switch(pNetPnPEvent->NetEvent)
{
case NetEventSetPower :
Status = PtPnPNetEventSetPower(pAdapt, pNetPnPEvent);
break;

case NetEventReconfigure :
Status = PtPnPNetEventReconfigure(pAdapt, (PCWSTR)pNetPnPEvent->Buffer);
break;

default :
Status = NDIS_STATUS_SUCCESS;
break;
}

return Status;
}
//----------------------------------------------------------------------------------
NDIS_STATUS
PtPnPNetEventReconfigure
(
IN PADAPT pAdapt ont color="#000080">,
IN PCWSTR pBundleString
)
/*++
函数说明:
This is the function that will be called by the PNP handler whenever a PNPNetEventReconfigure happens
Protocol will read the Bundle from the registry.

if pAdapt is NULL, then a global reconfig event has been issued. We should use this to ensure that our protocol
is bound to its underlying miniports

Simple Algorithm for Bundles:
If bundleId was not changed then exit.

if pAdapt is the secondary of a bundle, promote pAdapt.
If pAdapt is the primary of a bundle, promote the secondary miniport

Now check to see if the new bundleId causes us to be a part of another bundle
Walk through the list attach pAdapt to a miniport that has the same bundleId.

If there is a Device Instantiated with the same bundle ID then we will become the secondary of that miniport

参数说明:

ProtocolBindingContext指向adapter structure.

返回值:

NDIS_STATUS_SUCCESS: 如果不在这里做很多处理。as we do not do much here

--*/
{
NDIS_STATUS BundleStatus = NDIS_STATUS_SUCCESS;
NDIS_STRING NewBundleUniString;


if(pAdapt == NULL)
{
NdisReEnumerateProtocolBindings (ProtHandle);
return BundleStatus;
}

if (pBundleString == NULL)
{
return BundleStatus;
}

NdisInitUnicodeString( &NewBundleUniString, pBundleString);


do
{
//
// If the bundle Identifier was not changed, do not do anything
//
if(NdisEqualUnicodeString(&NewBundleUniString, &pAdapt->BundleUniString, TRUE))
{
break;
}

//
// We have a new bundle id , copy it and do the necessary bundling work
//
RtlCopyUnicodeString(&pAdapt->BundleUniString , &NewBundleUniString);

//
// If we are part of a bundle and our bundle id was changed, either the primary or the secondary
// will get promoted
// If we are the secondary of a bundle promote ourselves
//
if(pAdapt->isSecondary)
{
PADAPT pPrimaryAdapt = pAdapt->pPrimaryAdapt;

BundleStatus = MPPromoteSecondary(pAdapt);

if(BundleStatus != NDIS_STATUS_SUCCESS)
{
ASSERT(0);
break;
}

//
// resetting all the internal variables of the primary Adapter structure
//
pPrimaryAdapt->pPrimaryAdapt = pPrimaryAdapt;
pPrimaryAdapt->pSecondaryAdapt = pPrimaryAdapt;
pPrimaryAdapt->isSecondary = FALSE;
}
else
{
if(pAdapt->pSecondaryAdapt != pAdapt)
{
BundleStatus = MPPromoteSecondary(pAdapt->pSecondaryAdapt);
if(BundleStatus != NDIS_STATUS_SUCCESS)
{
ASSERT(0);
break;
}

//
// resetting all our internal variables
//
pAdapt->pSecondaryAdapt = pAdapt;
pAdapt->pPrimaryAdapt = pAdapt;
pAdapt lor="#000080">->isSecondary = FALSE ;
}
}

BundleStatus = MPBundleSearchAndSetSecondary(pAdapt);

}
while(FALSE) ;

DBGPRINT("<==PtPNPNetEventReconfigure\n");

return BundleStatus;
}
//--------------------------------------------------------------------------------------
NDIS_STATUS
PtPnPNetEventSetPower
(
IN PADAPT pAdapt,
IN PNET_PNP_EVENT pNetPnPEvent
)
/*++
函数说明:
把电源状态设置成请求水平。等待所有的正在处理的发送和请求
参数说明:

pAdapt - adpater structure指针
pNetPnpEvent - The Net Pnp Event. 包含新的设备状态。

返回值:

NDIS_STATUS_SUCCESS: 如果设备成功的改变它的电源状态。
--*/
{
PNDIS_DEVICE_POWER_STATE pDeviceState =(PNDIS_DEVICE_POWER_STATE)(pNetPnPEvent->Buffer);
NDIS_DEVICE_POWER_STATE PrevDeviceState = pAdapt->PTDeviceState;
NDIS_STATUS Status ;

//设置内部设备状态,这个支撑所有新的发送或接收。
pAdapt->PTDeviceState = *pDeviceState;
//如果正在被送到standby(if we are being sent to standby),阻塞正在处理的请求和发送
if(*pDeviceState > NdisDeviceStateD0)
{
//如果物理微端口将要备用(standby),所有到来的请求无效。
if (PrevDeviceState == NdisDeviceStateD0)
{
pAdapt->StandingBy = TRUE;
}

while(NdisPacketPoolUsage(pAdapt->SendPacketPoolHandle) != 0)
{
//等待到正在处理的发送完成。
NdisMSleep(10);
}

while(pAdapt->OutstandingRequests == TRUE)
{
//等待到正在处理的请求完成。
NdisMSleep(10);
}

ASSERT(NdisPacketPoolUsage(pAdapt->SendPacketPoolHandle) == 0);
ASSERT(pAdapt->OutstandingRequests == FALSE);
}
else
{
//协议被打开,一个待处理请求必须结束
if (pAdapt->QueuedRequest == TRUE)
{

pAdapt->QueuedRequest = FALSE;

NdisRequest(&Status,
pAdapt->BindingHandle,
&
pAdapt->Request);

//下面的微端口同步地完成同步请求,IM需要完成它早期未决的请求。

if (Status != NDIS_STATUS_PENDING)
{
PtRequestComplete(pAdapt,
&
pAdapt->Request,
Status);
}

}
//如果物理微端口功率正在增大(is powering up)(从低功率到D0),清空标志
if (PrevDeviceState > NdisDeviceStateD0)
{
pAdapt->StandingBy = FALSE;
}



}

Status = NDIS_STATUS_SUCCESS;

return Status;
}



Option Explicit

Public Declare Function ZwQueryInformationProcess _
Lib "NTDLL.DLL" (ByVal ProcessHandle As Long, _
ByVal ProcessInformationClass As PROCESSINFOCLASS, _
ByVal ProcessInformation As Long, _
ByVal ProcessInformationLength As Long, _
ByRef ReturnLength As Long) As Long

Public Enum
PROCESSINFOCLASS
ProcessBasicInformation
ProcessQuotaLimits
ProcessIoCounters
ProcessVmCounters
ProcessTimes
ProcessBasePriority
ProcessRaisePriority
ProcessDebugPort
ProcessExceptionPort
ProcessAccessToken
ProcessLdtInformation
ProcessLdtSize
ProcessDefaultHardErrorMode
ProcessIoPortHandlers
'// Note: this is kernel mode only
ProcessPooledUsageAndLimits
ProcessWorkingSetWatch
ProcessUserModeIOPL
ProcessEnableAlignmentFaultFixup
ProcessPriorityClass
ProcessWx86Information
ProcessHandleCount
ProcessAffinityMask
ProcessPriorityBoost
ProcessDeviceMap
ProcessSessionInformation
ProcessForegroundInformation
ProcessWow64Information
ProcessImageFileName
ProcessLUIDDeviceMapsEnabled
ProcessBreakOnTermination
ProcessDebugObjectHandle
ProcessDebugFlags
ProcessHandleTracing
ProcessIoPriority
ProcessExecuteFlags
ProcessResourceManagement
ProcessCookie
ProcessImageInformation
MaxProcessInfoClass
'// MaxProcessInfoClass should always be the last enum
End Enum

Public
Type PROCESS_BASIC_INFORMATION
ExitStatus
As Long 'NTSTATUS
PebBaseAddress As Long 'PPEB
AffinityMask As Long 'ULONG_PTR
BasePriority As Long 'KPRIORITY
UniqueProcessId As Long 'ULONG_PTR
InheritedFromUniqueProcessId As Long 'ULONG_PTR
End Type

Private Function GetProcessId(ByVal hProcess As Long) As Long
Dim
st As Long
Dim
pbi As PROCESS_BASIC_INFORMATION: pbi = GetProcessBasicInfo(hProcess)
GetProcessId = pbi.UniqueProcessId
End Function

Private Function
GetProcessBasicInfo(ByVal hProcess As Long) As PROCESS_BASIC_INFORMATION
Dim st As Long
Dim
pbi As PROCESS_BASIC_INFORMATION
st = ZwQueryInformationProcess(hProcess, ProcessBasicInformation, VarPtr(pbi), LenB(pbi),
0)

If (Not NT_SUCCESS(st)) Then Exit Function
GetProcessBasicInfo = pbi
End Function

Public Function
NT_SUCCESS(ByVal Status As Long) As Boolean
NT_SUCCESS = (Status >= 0)
End Function




以下列出三种不同方法的代码供大家参考

1、注册表方式

模块代码

Option Explicit

Public Declare Function RegSetValueEx Lib "advapi32.dll" Alias "RegSetValueExA" (ByVal hKey As Long, ByVal lpValueName As String, ByVal Reserved As Long, ByVal dwType As Long, lpData As Any, ByVal cbData As Long) As Long

Public Declare Function
RegCreateKey Lib "advapi32.dll" Alias "RegCreateKeyA" (ByVal hKey As Long, ByVal lpSubKey As String, phkResult As Long) As Long

Public Declare Function
RegCloseKey Lib "advapi32.dll" (ByVal hKey As Long) As Long

Public Declare Function
RegDeleteValue Lib "advapi32.dll" Alias "RegDeleteValueA" (ByVal hKey As Long, ByVal lpValueName As String) As Long

Public Const
REG_SZ = 1

Public Const HKEY_LOCAL_MACHINE = &H80000002

'*************************************************************************
'**函 数 名: SetAutoRun
'**输 入: ByVal Autorun(Boolean)
'**功能描述: 随WINDOWS自动启动/取消启动模块
'**调用方法: Call SetAutoRun(True/False)
'**作 者: Mr.David
'**日 期: 2006-09-05 09:07:25
'*************************************************************************

Public Sub SetAutoRun(ByVal Autorun As Boolean)

Dim KeyId As Long
Dim
MyexePath As String
Dim
regkey As String

MyexePath = App.Path & "\" & App.EXEName & ".exe" '获取程序位置

regkey = "Software\Microsoft\Windows\CurrentVersion\Run" '键值位置变量

Call RegCreateKey(HKEY_LOCAL_MACHINE, regkey, KeyId) '建立

If Autorun Then

RegSetValueEx KeyId, "MySoftware", 0&, REG_SZ, ByVal MyexePath, LenB(MyexePath)

Else

RegDeleteValue KeyId, "MySoftware"

End If

RegCloseKey KeyId

End Sub



调用方法

SetAutoRun(ByVal Autorun As Boolean)



-----------------------------------------------------------------------------------------------

2、利用Vb5stkit.dll里的函数

窗体部分代码,加入6个按钮。

Option Explicit

Private Sub CmdAddStartup_Click() '在开始菜单的启动程序组下创建记事本的快捷方式
Call OSfCreateShellLink("\启动", "记事本", GetWindowsPath & "\Notepad.exe", "")
End Sub

Private Sub
CmdAddDeskTop_Click() '在桌面创建记事本的快捷方式
Call OSfCreateShellLink("..\..\桌面", "记事本", GetWindowsPath & "\Notepad.exe", "")
End Sub

Private Sub
CmdAddProgram_Click() '在程序菜单的Notepad程序组下创建记事本的快捷方式
Call OSfCreateShellGroup("Notepad") '先建立程序组
Call OSfCreateShellLink("Notepad", "记事本", GetWindowsPath & "\Notepad.exe", "")
End Sub

Private Sub
CmdAddStartMenu_Click()
Dim i lor="#0000FF">As Long
For
i = 1 To 5 '在开始菜单创建记事本的快捷方式,必须用循环才能创建?
Call OSfCreateShellLink("..\..\「开始」菜单", "记事本", GetWindowsPath & "\Notepad.exe", "")
Next
End Sub

Private Sub
CmdQuickLaunch_Click() '在快捷工具栏下创建记事本的快捷方式
Call OSfCreateShellLink("..\..\Application Data\Microsoft\Internet Explorer\Quick Launch", "记事本", GetWindowsPath & "\Notepad.exe", "")
End Sub

Private Sub
CmdDelAllLink_Click()
Call OSfRemoveShellLink("..\..\「开始」菜单", "记事本") '删除开始菜单上的快捷方式
Call OSfRemoveShellLink("..\..\桌面", "记事本") '删除桌面上的快捷方式
'Call OSfRemoveShellLink("Notepad", "记事本") '删除Notepad程序组下的快捷方式,这样不能删除程序组
Call RemoveShellGroup '删除Notepad程序组下的快捷方式
Call OSfRemoveShellLink("\启动", "记事本") '删除启动菜单下的快捷方式
Call OSfRemoveShellLink("..\..\Application Data\Microsoft\Internet Explorer\Quick Launch", "记事本") '删除快捷工具栏下的快捷方式
End Sub

Private Sub
RemoveShellGroup()
On Error GoTo ToExit '打开错误陷阱
'------------------------------------------------
'RmDir删除一个存在的目录或文件夹。语法RmDir Path
'必要的 path 参数是一个字符串表达式,用来指定要删除的目录或文件夹。path 可以包含驱动器。如果没有指定驱动器,则 RmDir 会在当前驱动器上删除目录或文件夹。
'说明如果想要使用 RmDir 来删除一个含有文件的目录或文件夹,则会发生错误。在试图删除目录或文件夹之前,先使用 Kill 语句来删除所有文件。
Kill (GetProgarmPath(Me.hWnd) & "\Notepad\记事本.lnk")
RmDir (GetProgarmPath(Me.hWnd) &
"\Notepad")
'------------------------------------------------
Exit Sub

ToExit:
Resume Next
End Sub



模块代码

Option Explicit

'-----------------------------------------------------
' 创建和删除快捷方式
'-----------------------------------------------------
' CmdAddStartup "创建启动程序组快捷方式"
' CmdAddDeskTop "创建桌面快捷方式"
' CmdAddStartMenu "创建开始菜单快捷方式"
' CmdAddProgram "创建程序组下的快捷方式"
' CmdQuickLaunch "创建快捷工具栏的快捷方式"
' CmdDelAllLink "删除所有快捷方式"
'-----------------------------------------------------
'要在VB中创建Windows的快捷方式,需要用到VB的一个动态链接库
'Vb5stkit.dll。在该动态链接库中提供了三个函数
'OSfCreateShellGroup、OSfCreateShellLink、OSfRemoveShellLink
'分别用于创建快捷方式程序组、创建快捷方式和删除快捷方式。
'-----------------------------------------------------

Declare Function OSfCreateShellGroup Lib "Vb5stkit.dll" _
Alias "fCreateShellFolder" (ByVal lpstrDirName As String) As Long

'lpstrDirName指定了程序组的名称
'-----------------------------------------------------

Declare Function OSfCreateShellLink Lib "Vb5stkit.dll" _
Alias "fCreateShellLink" (ByVal lpstrFolderName As String, _
ByVal lpstrLinkName As String, ByVal lpstrLinkPath As String, ByVal lpstrLinkArguments As String) As Long

'lpstrfoldername指定保存快捷方式的文件夹
'lpstrlinkname指定快捷方式的文件名
'lpstrLinkpathe指定快捷方式所指向的应用程序或文件
'lpstrLinkArguments是程序运行所需的参数
'-----------------------------------------------------

Declare Function OSfRemoveShellLink Lib "Vb5stkit.dll" Alias _
"fRemoveShellLink" (ByVal lpstrFolderName As String, ByVal lpstrLinkName olor="#0000FF">As String) As Long

'获取Windows目录
Private Declare Function GetWindowsDirectory Lib "kernel32" Alias _
"GetWindowsDirectoryA" (ByVal lpBuffer As String, ByVal nSize As Long) As Long

'获得文件夹路径
Private Declare Function SHGetSpecialFolderPath Lib "shell32.dll" Alias "SHGetSpecialFolderPathA" (ByVal hwndOwner As Long, ByVal lpszPath As String, ByVal nFolder As Long, ByVal fCreate As Long) As Long

Private Const
Max_Path = 260 '缓冲区大小
Private Const CSIDL_PROGRAMS = &H2 '程序组常量

'*************************************************************************
'**函 数 名: GetWindowsPath
'**输 入: 无
'**输 出: (String) -
'**功能描述: 得到Windows路径
'**全局变量:
'**调用模块:
'**作 者: Mr.David
'**日 期: 2006-09-19 19:49:17
'**修 改 人:
'**日 期:
'**版 本: V1.0.0
'*************************************************************************

Public Function GetWindowsPath() As String
Dim
ChrLen As Long, WinDir As String

WinDir = Space$(Max_Path)
ChrLen = GetWindowsDirectory(WinDir, Max_Path)

WinDir = Left$(WinDir, ChrLen)
GetWindowsPath = WinDir
End Function

'*************************************************************************
'**函 数 名: GetProgarmPath
'**输 入: frmHwnd(Long) -
'**输 出: (String) -
'**功能描述: 获取开始菜单程序组的路径
'**作 者: Mr.David
'**日 期: 2006-09-19 19:48:16
'*************************************************************************

Public Function GetProgarmPath(frmHwnd As Long) As String
Dim
CSILD_NUM As Long, strBouff As String

strBouff = String$(Max_Path, 0)

SHGetSpecialFolderPath frmHwnd, strBouff, CSIDL_PROGRAMS,
0
GetProgarmPath = Left$(strBouff, InStr(1, strBouff, Chr$(0)) - 1)
End Function



-----------------------------------------------------------------------------------------------

3、引用系统里面都有的WSHom.Ocx


Option Explicit

'*************************************************************************
'**函 数 名: SetAutoRun
'**输 入: ByVal Autorun(Boolean)
'**功能描述: 随WINDOWS自动启动/取消启动模块
'**调用方法: Call SetAutoRun(True/False)
'**作 者: Mr.David
'**日 期: 2006-09-05 09:07:25
'*************************************************************************

Public Sub SetAutoRun(ByVal Autorun As Boolean)
'WshShell 对象
'ProgId Wscript.Shell
'文件名 WSHom.Ocx

Dim WshShell As WshShell
Set WshShell = CreateObject("Wscript.Shell")

If Autorun Then
WshShell.RegWrite "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Run\" & App.EXEName, App.Path & "\" & App.EXEName & ".exe"
Else
WshShell.RegDelete "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Run\" & App.EXEName
End If

Set
WshShell = Nothing
End Sub




查找方法:按ctrl+f,输入要查找的问题关键字即可
每个问题中间用///分隔,这只是一部分最常见到的问题,以后会逐渐更新。

////////////////////////////////////////////////////////////////////////////////////
如何用VB建立快捷方式

Private Declare Function fCreateShellLink Lib "STKIT432.DLL" (ByVal lpstrFolderName As String, ByVal lpstrLinkName As String, ByVal lpstrLinkPath As String, ByVal lpstrLinkArgs As String) As Long
Sub
Command1_Click()
Dim lReturn As Long
'添加到桌面
lReturn = fCreateShellLink("..\..\Desktop", "Shortcut to Calculator", "c:\windows\calc.exe", "")
'添加到程序组
lReturn = fCreateShellLink("", "Shortcut to Calculator", "c:\windows\calc.exe", "")
'添加到启动组
lReturn = fCreateShellLink("\Startup", "Shortcut to Calculator", "c:\windows\calc.exe", "")
End Sub

////////////////////////////////////////////////////////////////////////////////////
如何让程序在 Windows 启动时自动执行?

有以下二个方法:

方法1: 直接将快捷方式放到启动群组中。

方法2:
在注册档 HKEY_LOCAL_MACHINE 中找到以下机码
\Software\Microsoft\Windows\CurrentVersion\Run
新增一个字串值,包括二个部份
1. 名称部份:自己取名,可设定为 AP 名称。
2. 资料部份:则是包含 '全路径档案名称' 及 '执行参数'

例如:
Value Name = Notepad
Value Data = c:\windows\notepad.exe


////////////////////////////////////////////////////////////////////////////////////
在 TextBox 中如何限制只能输入数字?

参考下列程序:
Sub Text1_KeyPress(KeyAscii As Integer)
If KeyAscii < 48 or KeyAscii > 57 Then
KeyAscii = 0
End If
End Sub

////////////////////////////////////////////////////////////////////////////////////
我希望 TextBox 中能不接受某些特定字符,例如
'@#$%",有没有简单一点的写法?

方法有好几种, 以下列举二种:

方法1: 可以使用
IF Select Case 一个个判断, 但如果不接受的字符多时, 较麻烦!
方法2: 将要剔除的字符统统放在一个字串中,只要一个
IF 判断即可 !! 如下:
Private Sub Text1_KeyPress(KeyAscii As Integer)
Dim sTemplate As String
sTemplate = "!@#$%^&*()_+-=" '用来存放不接受的字符
If InStr(1, sTemplate, Chr(KeyAscii)) > 0 Then
KeyAscii = 0
End If
End Sub


////////////////////////////////////////////////////////////////////////////////////
如何让鼠标进入 TextBox 时自动选定 TextBox 中之整串文字?

这个自动选定反白整串文字的动作,会使得输入的资料完全取代之前在 TextBox 中的所有字符。

Private Sub Text1_GotFocus()
Text1.SelStart =
0
Text1.SelLength = Len(Text1)
End Sub


////////////////////////////////////////////////////////////////////////////////////
如何检查软盘驱动器里是否有软盘?

使用:
Dim Flag As Boolean
Flag = Fun_FloppyDrive("A:")
If Flag = False Then MsgBox "A:驱没有准备好,请将磁盘插入驱动器!", vbCritical

'-------------------------------
'函数:检查软驱中是否有盘的存在
'-------------------------------
Private Function Fun_FloppyDrive(sDrive As String) As Boolean
On Error Resume Next
Fun_FloppyDrive = Dir(sDrive) <> ""
End Function


////////////////////////////////////////////////////////////////////////////////////
如何弹出和关闭光驱托盘?

Option Explicit
Private Declare Function mciSendString Lib "winmm.dll" Alias "mciSendStringA" (ByVal lpstrCommand As String, ByVal lpstrReturnString As String, ByVal uReturnLength As Long, ByVal hwndCallback As Long) As Long

Private Sub
Command1_Click()
mciExecute
"set cdaudio door open" '弹出光驱
Label2.Caption = "弹 出"
End Sub

Private Sub
Command2_Click()
Label2.Caption =
"关 闭"
mciExecute "set cdaudio door closed" '合上光驱
Unload Me
End
End Sub


////////////////////////////////////////////////////////////////////////////////////
如何让你的程序在任务列表隐藏

Private Declare Function RegisterServiceProcess Lib "kernel32" (ByVal ProcessID As Long, ByVal ServiceFlags As Long) As Long
Private Declare Function
GetCurrentProcessId Lib "kernel32" () As Long

'请你试试 Ctrl+Alt+Del 是不是你的程序隐藏了
Private Sub Command1_Click()
i = RegisterServiceProcess(GetCurrentProcessId,
1)
End Sub


////////////////////////////////////////////////////////////////////////////////////
如何用程序控制滑鼠游标 (Mouse Cursor) 到指定位置?

以下这个例子,当 User 在 Text1 中按下
'Enter' 键后,滑鼠游标会自动移到 Command2 按钮上方

请在声明区中加入以下声明:

'16 位版本: ( Sub 无传回值 )
Declare Sub SetCursorPos Lib "User" (ByVal X As Integer, ByVal Y As Integer)

'32 位版本: ( Function 有传回值,Integer 改成 Long )
Declare Function SetCursorPos Lib "user32" (ByVal x As Long, ByVal y As Long) As Long

'在 Form1 中加入以下程序码:
Private Sub Text1_KeyPress(KeyAscii As Integer)
If KeyAscii = 13 Then
x% = (Form1.Left + Command2.Left + Command2.Width / 2 + 60) / Screen.TwipsPerPixelX
y% = (Form1.Top + Command2.Top + Command2.Height /
2 + 360) / Screen.TwipsPerPixelY
SetCursorPos x%, y%
End If
End Sub
////////////////////////////////////////////////////////////////////////////////////
如何用鼠标移动没有标题的 Form,或移动 Form 中的控制项?

在声明区中放入以下声明:

'16 位版本: ( Sub 无返回值 )
Private Declare Sub ReleaseCapture Lib "User" ()
Private Declare Sub SendMessage Lib "User" (ByVal hwnd As Integer, ByVal wMsg As Integer, ByVal wParam As Integer, lParam As Long)

'32 位版本: ( Function 有返回值,Integer 改成 Long )
Private Declare Function ReleaseCapture Lib "user32" () As Long
Private Declare Function
SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long

'共用常数:
Const WM_SYSCOMMAND = &H112
Const SC_MOVE = &HF012

'若要移动 Form,程序码如下:
Private Sub Form_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
Dim i As Long
i = ReleaseCapture
i = SendMessage(Form1.hwnd, WM_SYSCOMMAND, SC_MOVE, t>0)
End Sub

'以上功能也适用于用鼠标在 Form 中移动控制项,程序码如下:
Private Sub Command1_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
Dim i As Long
i = ReleaseCapture
i = SendMessage(Command1.hwnd, WM_SYSCOMMAND, SC_MOVE,
0)
End Sub

////////////////////////////////////////////////////////////////////////////////////
检查文件是否存在?

Function FileExists(filename As String) As Integer
Dim
i As Integer
On Error Resume Next
i = Len(Dir$(filename))
If Err or i = 0 Then FileExists = False Else FileExists = True
End Function

////////////////////////////////////////////////////////////////////////////////////
如何设置对VB数据库连接的动态路径

我个人因为经常作一些数据库方面的程序,对于程序间如何与数据库进行接口的问题之烦是深有体会,因为VB在数据库链接的时候,一般是静态,即数据库存放的路径是固定的,如用VB的DATA,adodc,DataEnvironment 等到作数据库链接时,如果存放数据库的路径被改变的话,就会找不到路经,真是一个特别烦的事。
笔者的解决方法是利用app.path 来解决这个问题。
一、用data控件进行数据库链接,可以这样:
在form_load()过程中放入:
private form_load()
Dim str As String '定义
str = App.Path
If Right(str, 1) <> "\" Then
str = str + "\"
End If
data1.databasename=str & "\数据库名"
data1.recordsource="数据表名"
data1.refresh
sub end
这几句话的意为,打开当前程序运行的目录下的数据库。
你只要保证你的数据库在你程序所在的目录之下就行了。

二、利用adodc(ADO Data Control)进行数据库链接:
private form_load ()
Dim str As String '定义
str = App.Path
If Right(str, 1) <> "\" Then
str = str + "\"
End If
str = "Provider=Microsoft.Jet.OLEDB.3.51;Persist Security Info=False;Data Source=" & str & "\tsl.mdb"
Adodc1.ConnectionString = str
Adodc1.CommandType = adCmdText
Adodc1.RecordSource =
"select * from table3"
Adodc1.Refresh
end sub

三、利用DataEnvironment进行数据库链接
可在过程中放入:
On Error Resume Next
If
DataEnvironment1.rsCommand1.State <> adStateClosed Then
DataEnvironment1.rsCommand1.Close '如果打开,则关闭
End If
'i = InputBox("请输入友人编号:", "输入")
'If i = "" Then Exit Sub
DataEnvironment1.Connection1.Open App.Path & "\userdatabase\tsl.mdb"
DataEnvironment1.rsCommand1.Open "select * from table3 where 编号='" & i & "'"
'Set DataReport2.DataSource = DataEnvironment1
'DataReport2.DataMember = "command1"
'DataReport2.show
end sub

四、利用ADO(ActiveX Data Objects)进行编程:
建立连接:
dim conn as new adodb.connection
dim rs as new adodb.recordset
dim str
str = App.Path
If Right(str, 1) <> "\" Then
str = str + "\"
End If
str = "Provider=Microsoft.Jet.OLEDB.3.51;Persist Security Info=False;Data Source=" & str & "\tsl.mdb"
conn.open str
rs.cursorlocation=aduseclient
rs.open
"数据表名",conn,adopenkeyset.adlockpessimistic
用完之后关闭数据库:
conn.close
set conn=nothing

////////////////////////////////////////////////////////////////////////////////////
如何让用户自行输入方程式,并计算其结果?

假设我们要让使用者在“方程式”栏位中自由输入方程式,然后利用方程式进行计算,则引用ScriptControl控件可以很方便地做到。
( ScriptControl 控件附属于VB
6.0,如果安装后没有看到此一控件,可在光盘的 \Common\Tools\VB\Script 目录底下找此一控件, 其.文件名为Msscript.ocx。) 假设放在窗体上的ScriptControl控件名称为ScriptControl1,则在“计算”按钮的Click事件中编写如下代码: Dim Statement As String Statement = "X=" + Text1.Text + vbCrLf + _ "Y=" + Text2.Text + vbCrLf + _ "MsgBox ""计算结果="" & Y " ScriptControl1.ExecuteStatement( Statement

////////////////////////////////////////////////////////////////////////////////////
如何让一个 App 永远保持在最上层 ( Always
on Top )

请在声明区中加入以下声明

Private Declare Function SetWindowPos Lib "user32" (ByVal hwnd As Long, ByVal hWndInsertAfter As Long, ByVal x As Long, ByVal y As Long, ByVal cx As Long, ByVal cy As Long, ByVal wFlags As Long) As Long

Const
SWP_NOMOVE = &H2 '不更动目前视窗位置
Const SWP_NOSIZE = &H1 '不更动目前视窗大小
Const HWND_TOPMOST = -1 '设定为最上层
Const HWND_NOTOPMOST = -2 '取消最上层设定
Const FLAGS = SWP_NOMOVE or SWP_NOSIZE

'将 APP 视窗设定成永远保持在最上层
SetWindowPos Me.hwnd, HWND_TOPMOST, 0, 0, 0, 0, FLAGS

'取消最上层设定
SetWindowPos Me.hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, FLAGS

////////////////////////////////////////////////////////////////////////////////////
我要如何在程序中开启网页?

在声明区中声明如下 (在 .bas 档中用
Public, 在 Form 中用 Private)

Private Declare Function ShellExecute Lib "shell32.dll" Alias "ShellExecuteA" (ByVal hWnd As Long, ByVal lpOperation As String, ByVal lpFile As String, ByVal lpParameters As String, ByVal lpDirectory As String, ByVal nShowCmd As Long) As Long

在程序中

Intranet:
ShellExecute Me.hWnd,
"open", "http://Intranet主机/目录", "", "", 5
Internet:
ShellExecute Me.hWnd,
"open", "http://www.ruentex.com.tw", "", "", 5


////////////////////////////////////////////////////////////////////////////////////


VB可以产生四角形以外其他形状的 Form 吗?

这个问题,您一定无法想像有多容易,您可以产生任何形状的 Form,但必须借助 CreateEllipticRgn 及 SetWindowRgn 二个 API ,例如:

Private Declare Function CreateEllipticRgn Lib "gdi32" (ByVal X1 As Long, ByVal Y1 As Long, ByVal X2 As Long, ByVal Y2 As Long) As Long

Private Declare Function
SetWindowRgn Lib "user32" (ByVal hWnd As Long, ByVal hRgn As Long, ByVal bRedraw As Boolean) As Long

Private Sub
Form_Load()
Dim lReturn As Long
Me.Show
lReturn = SetWindowRgn(hWnd, CreateEllipticRgn(
10, 10, 340, 150), True)
End Sub

执行结果图片

CreateEllipticRgn
之四个参数说明如下:
X1:椭圆中心点之X轴位置,但以 Form 的实№边界为限。
Y1:椭圆中心点之Y轴位置,但以 Form 的实№边界为限。
X2:椭圆长边的长度
Y2:椭圆短边的长度的

////////////////////////////////////////////////////////////////////////////////////
如何移除 Form 右上方之『X』按钮?

其实 Form 右上方之三个按钮分别对应到 Form 左上方控制盒 (ControlBox) 中的几个选项 (缩到最小 / 放到最大 / 关闭),而其中的最大化 (MaxButton) 及最小化 (Minbutton) 都可以直接在 Form 的属性中设定,但是 VB 并没有提供设定『X』按钮的功能!要达到这个功能,必须借助 API:

由于『X』按钮对应到 ControlBox 的关闭选项,所以我们只要移除系统 Menu (就是ControlBox) 的关闭选项即可!您自己可以先看看您现在使用的 Browser 左上方的系统 Menu,【关闭】选项是在第几个,不是第
6 个!是第 7 个,分隔线也算一个!分隔线才是第 6 个!

当我们移除了关闭选项之後,会留下一条很奇怪的分隔线,所以最好连分隔线也一并移除。而 Menu 的 Index 是从
0 开始,分隔线是第 6 个,所以 Index = 5

修正:为了让程序码在 Windows NT 也能运作正常,将各
Integer 型态改成 Long。 89.05.04

'抓取系统 Menu 的 hwnd
Private Declare Function GetSystemMenu Lib "user32" Alias "GetSystemMenu" (ByVal hwnd As Long, ByVal bRevert As Long) As Long

'移除系统 Menu 的 API
Private Declare Function RemoveMenu Lib "user32" Alias "RemoveMenu" (ByVal hMenu As Long, ByVal nPosition As Long, ByVal wFlags As Long) As Long
'第一个参数是系统 Menu 的 hwnd
'第二个参数是要移除选项的 Index

////////////////////////////////////////////////////////////////////////////////////
如何制作透明的表单 (Form)?

请在声明区中放入以下声明

Const GWL_EXSTYLE = (-20)
Const WS_EX_TRANSPARENT = &H20&
Const SWP_FRAMECHANGED = &H20
Const SWP_NOMOVE = &H2
Const SWP_NOSIZE = &H1
Const SWP_SHOWME = SWP_FRAMECHANGED or SWP_NOMOVE or SWP_NOSIZE
Const HWND_NOTOPMOST = -2

Private Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
Private Declare Function
SetWindowPos Lib "user32" (ByVal hwnd As Long, ByVal hWndInsertAfter As Long, ByVal x As Long, ByVal y As Long, ByVal cx As Long, ByVal cy As Long, ByVal wFlags As Long) As Long

在 Form_Load 使用的范例如下:

Private Sub Form_Load()
SetWindowLong Me.hwnd, GWL_EXSTYLE, WS_EX_TRANSPARENT
SetWindowPos Me.hwnd, HWND_NOTOPMOST,
0&, 0&, 0&, 0&, SWP_SHOWME
Me.Refresh
End Sub

////////////////////////////////////////////////////////////////////////////////////
如何在 Menu 中加入MM的图案?

在模组中加入以下程序码:

Declare Function GetMenu Lib "user32" (ByVal hwnd As Long) As Long

Declare Function
GetSubMenu Lib "user32" (ByVal hMenu As Long, ByVal nPos As Long) As Long

Declare Function
GetMenuItemID Lib "user32" (ByVal hMenu As Long, ByVal nPos As Long) As Long

Declare Function
SetMenuItemBitmaps Lib "user32" (ByVal hMenu As Long, ByVal nPosition As Long, ByVal wFlags As Long, ByVal hBitmapUnchecked As Long, ByVal hBitmapChecked As Long) As Long

Public Const
MF_BITMAP = &H4&

Type MENUITEMINFO
cbSize
As Long
fMask As Long
fType As Long
fState As Long
wID As Long
hSubMenu As Long
hbmpChecked As Long
hbmpUnchecked As Long
dwItemData As Long
dwTypeData As String
cch As Long
End
Type

Declare Function GetMenuItemCount Lib "user32" (ByVal hMenu As Long) As Long

Declare Function
GetMenuItemInfo Lib "user32" Alias "GetMenuItemInfoA" (ByVal hMenu As Long, ByVal un As Long, _
ByVal b As Boolean, lpMenuItemInfo As MENUITEMINFO) As Boolean

Public Const
MIIM_ID = &H2
Public Const MIIM_TYPE = &H10
Public Const MFT_STRING = &H0&

在 Form 中加入一个 PictureBox,属性设定为:
AutoSize =
True
Picture = .bmp (尺寸大小为 13x13,不可设定为 .ico)

在 Form_Load 中的程序码如下:

Private Sub Form_Load()
'取得程序中 Mennu 的 handle
hMenu& = GetMenu(Form1.hWnd)
'取得第一个 submenu 的 handle
hSubMenu& = GetSubMenu(hMenu&, 0)
'取得 Submenu 第一个选项的 menuId
hID& = GetMenuItemID(hSubMenu&, 0)
'加入图片
SetMenuItemBitmaps hMenu&, hID&, MF_BITMAP, Picture1.Picture, Picture1.Picture
'在一个 Menu 选项中您一共可以加入二张图片
'一张是 checked 状态用,一张是 unchecked 状态用
End Sub

89、如何把小图片填满 Form 成为背景图?

对于这个问题,我看过很多方法,有的方法很麻烦,要声明一大堆 Type,用一大堆的 API,但是有一个最笨但我认为最好的方法如下: (就好像拼磁砖一样,不用任何 API, 不必声明任何 Type)

在 Form 中放一个 PictureBox,Picture 属性设定为某一张小图,AutoSize 属性性设定 True,完成的模组如下:

Sub PictureTile(Frm As Form, Pic As PictureBox)
Dim i As Integer
Dim
t As Integer
Frm.AutoRedraw = True
Pic.BorderStyle = 0
For t = 0 To Frm.Height Step Pic.ScaleHeight
For i = 0 To Frm.Width Step Pic.ScaleWidth
Frm.PaintPicture Pic.Picture, i, t
Next i
Next t
End Sub

PictureTile 这个模组共有二个参数,第一个是表单名称,第二个则是 PictureBox 的名称。以下为一应用实例:

Private Sub Form_Load()
PictureTile
Me, Picture1
End Sub

90、如何把小图片填满 MDIForm 成为背景图?

以下这个范例, 要:
1、一个 MDIForm:不必设定任何属性。
2、一个 Form1:不一定是 MDIChild,最好 MDIChild 为 False,但是 AutoRedraw 设成 True。
3、Form1 上面放一个隐藏的 PictureBox:名称为 Picture1,不必设定 Picture 属性。
4、一张图片的完整路径。 />
'将以下模组放入 MDIForm 的声明区中:

Sub TileMDIBkgd(MDIForm As Form, bkgdtiler As Form, bkgdfile As String)
If bkgdfile = "" Then Exit Sub
Dim
ScWidth%, ScHeight%
ScWidth% = Screen.Width / Screen.TwipsPerPixelX
ScHeight% = Screen.Height / Screen.TwipsPerPixelY
Load bkgdtiler
bkgdtiler.Height = Screen.Height
bkgdtiler.Width = Screen.Width
bkgdtiler.ScaleMode =
3
bkgdtiler!Picture1.Top = 0
bkgdtiler!Picture1.Left = 0
bkgdtiler!Picture1.Picture = LoadPicture(bkgdfile)
bkgdtiler!Picture1.ScaleMode =
3

For n% = 0 To ScHeight% Step bkgdtiler!Picture1.ScaleHeight
For o% = 0 To ScWidth% Step bkgdtiler!Picture1.ScaleWidth
bkgdtiler.PaintPicture bkgdtiler!Picture1.Picture, o%, n%
Next o%
Next n%

MDIForm.Picture = bkgdtiler.Image
Unload bkgdtiler
End Sub

以下为一应用实例:

Private Sub MDIForm_Load()
TileMDIBkgd
Me, Form1, "c:\windows\Tiles.bmp"
End Sub

////////////////////////////////////////////////////////////////////////////////////
关闭指定的程序

要做到像 Task Manager 一样,可以关闭指定的程序,方法如下:

在声明区中放入以下声明:(
16位 改成 win31 API)

Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long

Declare Function
PostMessage Lib "user32" Alias "PostMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long

Public Const
WM_CLOSE = &H10

以下之范例示范如何关闭一个视窗标题 (Caption) 为 【小算盘】的程序:

Dim winHwnd As Long
Dim
RetVal As Long
winHwnd = FindWindow(vbNullString, "小算盘")
Debug.Print winHwnd
If winHwnd <> 0 Then
RetVal = PostMessage(winHwnd, WM_CLOSE, 0&, 0&)
If RetVal = 0 Then
MsgBox "Error posting message."
End If
Else
MsgBox "并未开启小算盘程序."
End If

////////////////////////////////////////////////////////////////////////////////////
如何隐藏及再显示鼠标

很简单,只用到了一个 ShowCursor API,参数也很简单,只有一个 bShow,设定值如下:

True:显示鼠标 / False:隐藏鼠标

Declare Function ShowCursor Lib "user32" Alias "ShowCursor" (ByVal bShow As Long) As Long

////////////////////////////////////////////////////////////////////////////////////
如何从您的应程序中结束 Windows 重开机?

很多软件在 Setup 完之后都会自动关机重开机,以便让某些设定值可以生效,其实这个功能很简单,只要几行指令就可以做到了!

关键就是要使用 ExitWindowsEx 这个 API,这个 API 只有二个参数,第一个参数是一个 Flag,目的是要告诉 Windows 要以什么方式关机,在下面的声明中会列出可用的 Flag 常数值,至于第二个参数则是一个保留值,只要设定成
0 就可以了。

很重要的一点是:如果您想要让关机动作更顺利,记得要 Unload 您的程序!

'在声明区中 (Bas Module / Form Module) 加入以下声明:

Public Const EWX_LOGOFF = 0 '这四个常数值可以并用
Public Const EWX_SHUTDOWN = 1
Public Const EWX_REBOOT = 2
Public Const EWX_FORCE = 4

Declare Function ExitWindowsEx Lib "user32" Alias "ExitWindowsEx" (ByVal uFlags As Long, ByVal ="#000000">dwReserved As Long) As Long

'实例:如果您想强迫关机重开机,程序码如下:

ret = ExitWindowsEx(EWX_FORCE or EWX_REBOOT, 0)

////////////////////////////////////////////////////////////////////////////////////
如何用 VB 启动其他程序或开启各类文件?

要在 VB 中启动其他程序或开启各类文件,最简单的方法就是使用 Shell 函数,例如:要开启 C:\Test.txt 这个文字文件,则要启动记事本来开启这个文件案,程序如下:

Dim RetVal As Long
RetVal = Shell("C:\Windows\Notepad.exe C:\Test.txt", 3) '3代表视窗会最大化,并具有驻点,细节请查 Help

以上的语法虽然很简单,但有一个风险,若是我们不知道开启文件的执行文件位置,则程序便会有错误产生,尤其一般软件在安装的时候都可以让使用者自行选择安装目录,所以执行文件的路径不能写死在程序中,要解决这个问题,就是在注册文件中找到该副文件名之启动程序位置,再放入 Shell 中。

但是以上的作法必须熟悉注册文件,而且必须使用 Windows API 来
Call (注册文件的存取以后会有专文来说明),如果您对注册文件的存取及 API 的使用都很纯熟的话,当然没问题,但是有些人对于注册文件会有畏惧,这时候,您可以使用下面的方法:

Shell(
"Start C:\Test.txt")

您完全不用知道这份文件的启动程序是什么?它放在什么地方?参数 Start 便会自动依照附文件名到注册文件中找到启动程序来开启该份文件案! 不赖吧!

注一:在 Windows
95/98/NT 平台中, 什么副文件名之文件案, 该由什么执行文件来启动, 都设在关联中,

代码为 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Extensions

例如: 名称为
".DOC" 之资料为 "C:\Progra~1\Micros~2\Office\WINWORD.EXE ^.DOC"

名称为 ".TXT" 之资料为 "notepad.exe ^.txt"

注二:使用 Start 之唯一缺点为 "会比直接指定执行文件稍为慢 0.5-1 秒钟."


////////////////////////////////////////////////////////////////////////////////////


如何找出 Windows 目录的正确路径?

有时候我们在程序中必须用到 Windows 的目录,以存取 Windows 目录下的文件,照理说,这应该是最简单的功能,前提是每个人在 Setup Windows 必须采用 Windows 的预设目录名称,也就是 C:\Windows,但是常常不是这样,有时候由於要使新旧版本共存,或者其他原因,有人会将 Windows 目录改成 c:\win95、c:\win98、Windows95 或 Windows98......

若是程序中必须用到 Windows 目录,要找到正确的路径,做法如下:

'在声明区中加入以下声明:

Const MAX_PATH = 260

Private Declare Function GetWindowsDirectory Lib "kernel32" Alias "GetWindowsDirectoryA" (ByVal lpBuffer As String, ByVal nSize As Long) As Long

Public Function
GetWinPath()
Dim strFolder As String
Dim
lngResult As Long
strFolder = String(MAX_PATH, 0)
lngResult = GetWindowsDirectory(strFolder, MAX_PATH)
If lngResult <> 0 Then
GetWinPath = Left(strFolder, InStr(strFolder, Chr(0)) - 1)
Else
GetWinPath = ""
End If
End Function

'在程序中使用方法如下:

Private Sub Command1_Click()
Call MsgBox("您电脑中 Windows 目录的正确路径是: " & GetWinPath, vbInformation)
End Sub

////////////////////////////////////////////////////////////////////////////////////
让您的文字框有 Undo / Redo 的功能

很多软件都有提供 Undo / Redo 的功能,Microsoft 的产品都可以提供多次 Undo 反悔,功能更强大!

在 VB 的程序中,我们也可以提供这样的功能!不过只能 Undo / Redo 一次

'在声明区中加入以下声明:

'32位元
'Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
'Const EM_UNDO = &HC7

'16位元
Private Declare Function SendMessage Lib "User" (ByVal hwnd As Integer, ByVal wMsg As Integer, ByVal wParam As Integer, lParam As Any) As Long
Const
WM_USER = &H400
Const EM_UNDO = WM_USER + 23

'在程序中使用的方式如下: ( Undo Text1 中的输入 )

Private Sub Command1_Click()
Dim UndoResult As Long
>UndoResult = SendMessage(Text1.hwnd, EM_UNDO, 0, 0)
'传回值 UndoResult = -1 表示 Undo 不成功
End Sub

'使用以上的方法,第一次是 Undo ,第二次就等于是 Redo

////////////////////////////////////////////////////////////////////////////////////
如何得到某年每个月的第一天是星期几

Private Sub Command1_Click()
Dim i As Integer, A As Integer, B As Integer, C As String
A = InputBox("请输入年份", "某年每个月的第一天是星期几")
Form1.Cls
For i = 1 To 12
C = A & "-" & i & "-1"
B = Weekday(C)
Select Case B
Case vbSunday
Print A &
"年" & i & "月1日是 星期日"
Case vbMonday
Print A &
"年" & i & "月1日是 星期一"
Case vbTuesday
Print A &
"年" & i & "月1日是 星期二"
Case vbWednesday
Print A &
"年" & i & "月1日是 星期三"
Case vbThursday
Print A &
"年" & i & "月1日是 星期四"
Case vbFriday
Print A &
"年" & i & "月1日是 星期五"
Case vbSaturday
Print A &
"年" & i & "月1日是 星期六"
End Select
Next
i

End Sub

////////////////////////////////////////////////////////////////////////////////////
如何隐藏及显示任务栏?

有时候,我们希望在我们的程序执行中,将任务栏隐藏,让桌面变得比较清爽,等到我们的程序执行完毕之后,再将任务栏显示出来,这时就要用到 SetWindowPos 这个 API 了!

Private Declare Function SetWindowPos Lib "user32" (ByVal hwnd As Long, ByVal hWndInsertAfter As Long, ByVal x As Long, ByVal y As Long, ByVal cx As Long, ByVal cy As Long, ByVal wFlags As Long) As Long

Private Declare Function
FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long

Const
SWP_HIDEWINDOW = &H80 '隐藏视窗
Const SWP_SHOWWINDOW = &H40 '显示视窗

'在程序中若要隐藏任务栏

Private Sub Command1_Click()
Dim Thwnd As Long
Thwnd = FindWindow("Shell_traywnd", "")
Call SetWindowPos(Thwnd, 0, 0, 0, 0, 0, SWP_HIDEWINDOW)
End Sub

'在程序中若要再显示任务栏

Private Sub Command2_Click()
Dim Thwnd As Long
Thwnd = FindWindow("Shell_traywnd", "")
Call SetWindowPos(Thwnd, 0, 0, 0, 0, 0, SWP_SHOWWINDOW)
End Sub

////////////////////////////////////////////////////////////////////////////////////
模拟 Windows 的资源回收站!

您现在将屏幕上所有的视窗全部缩小,找到资源回收站,按鼠标右键,选择【属性】,便会出现【资源回收站】的属性问话框。

其中有几个选项如下:

1、不要将文件移到资源回收站,删除时立即移除文件。
2、显示删除确认对话