📄 edittlb.bas
字号:
Attribute VB_Name = "modEditTLB"
Option Explicit
'Localized resource identifiers
Public Const cidAddinShortDesc As Integer = 100
Public Const cidAddinLongDesc As Integer = 101
Public Const cidAddInMenu As Integer = 102
Public Const cidAppTitle As Integer = 103
Public Const cidReferenceInvalid As Integer = 104
Public Const cidReadOnlyFile As Integer = 105
Public Const cidGuidConflict As Integer = 106
Public Const cidNameInUse As Integer = 107
Public Const cidLibNameAndGuidChange As Integer = 108
Public Const cidLibNameNoGuidChange As Integer = 109
Public Const cidLibGuidNoNameChange As Integer = 110
Public Const cidSaveAsTitle As Integer = 111
Public Const cidSaveAsFilter As Integer = 112
Public Const cidSaveAsNotATypeLib As Integer = 113
Public Const cidTryReload As Integer = 114
Public Const cidReadOnlyProjectFile As Integer = 115
Public Const cidFileLocked As Integer = 116
Public Const cidTipProjects As Integer = 117
Public Const cidTipLibraries As Integer = 118
Public Const cidTipNewLibrary As Integer = 119
Public Const cidTipSaveChanges As Integer = 120
Public Const cidTipDiscardChanges As Integer = 121
Public Const cidWindowCaption As Integer = 122
Public Const cidWindowCaptionNewLibrary As Integer = 123
Public Const cidWindowCaptionNoLibrary As Integer = 124
Public Const cidWindowCaptionNoProject As Integer = 125
Public Const cidWindowCaptionDirtyFlag As Integer = 126
Public Const cidNewLibName As Integer = 127
'Nonlocalized strings
Public Const ADDIN_PROGID As String = "PowerVBTLBEditor.Connect"
Public Const ADDIN_DOC_PROGID As String = "PowerVBTLBEditor.MainWindow"
Public Const UNIQUE_APP_ID As String = "PowerVBTLBEditor_1_0"
Public Const REG_CATEGORY As String = "PowerVB AddIns"
Public Const REG_APPSECTION As String = "Edit TLB"
Public Const REG_SHOWONCONNECT As String = "ShowOnConnect"
'Temp file APIs. Need to use ANSI because this add-in can run on Win9x
Private Declare Function GetTempFileName Lib "kernel32" Alias "GetTempFileNameA" (ByVal lpszPath As Long, ByVal lpPrefixString As String, ByVal wUnique As Long, ByVal lpTempFileName As Long) As Long
Private Declare Function GetTempPath Lib "kernel32" Alias "GetTempPathA" (ByVal nBufferLength As Long, ByVal lpBuffer As Long) As Long
Private Const MAX_PATH As Integer = 260
'APIs for setting the caption of the document window's parent
Public Declare Function GetParent Lib "user32" (ByVal hWnd As Long) As Long
Public Const WM_SETTEXT As Long = &HC
Public Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
'Declares and APIs to prompt for a file name. Note that ComDlg32.ocx is reference
'solely to provide constant values.
Private Type OPENFILENAME
lStructSize As Long
hwndOwner As Long
hInstance As Long
lpstrFilter As String
lpstrCustomFilter As String
nMaxCustFilter As Long
nFilterIndex As Long
lpstrFile As String
nMaxFile As Long
lpstrFileTitle As String
nMaxFileTitle As Long
lpstrInitialDir As String
lpstrTitle As String
Flags As Long
nFileOffset As Integer
nFileExtension As Integer
lpstrDefExt As String
lCustData As Long
lpfnHook As Long
lpTemplateName As String
End Type
Private Declare Function GetSaveFileName Lib "comdlg32.dll" Alias "GetSaveFileNameA" (pOpenfilename As OPENFILENAME) As Long
Private Type NMHDR
hwndFrom As Long
idFrom As Long
Code As Long
End Type
Private Type OFNOTIFY
hdr As NMHDR
lpOFN As Long
pszFile As Long
End Type
Private Const WM_NOTIFY As Long = &H4E
Private Const CDN_FIRST As Long = -601
Private Const CDN_FILEOK As Long = CDN_FIRST - 5
Private Const DWL_MSGRESULT As Long = 0&
Private Const OFN_ENABLEHOOK As Long = &H20
Private Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
Private Type OFNForDeref
lStructSize As Long
hwndOwner As Long
hInstance As Long
lpstrFilter As Long
lpstrCustomFilter As Long
nMaxCustFilter As Long
nFilterIndex As Long
lpstrFile As Long 'This is as far as we need
End Type
Private Type DerefOFN
Owner As ArrayOwner
pSA() As OFNForDeref
End Type
Private m_DerefOFN As DerefOFN
'A structure to hold all the locals needed for SaveActiveRef. These
'are passed around to its helper functions. It is in this module
'because one of the helper functions is an AddressOf callback, which
'can't be in the DOB.
Public Type SaveActiveRefLocals
RefName As String 'Info to restore m_ActiveRef
ProjectName As String 'Info to restore m_ActiveProject
Files() As String 'Array of file names, includes active ref and all after it
iActiveRef As Long '1-base index of active reference, LBound of Files
cRefs As Long 'Count of references, UBound of Files
TargetFile As String 'The file that we're updating
NewFile As String 'The temporary file with the newly generated typelib
NewLibName As String 'The name of the new library
NewLibGuid As VBGUID 'The GUID of the new library
NewLibMajor As Integer 'The MajorVersion of the new library
NewLibMinor As Integer 'The MinorVersion of the new library
NewLibLCID As Long 'The LCID of the new library
NewLibDesc As String 'The description of the new library. Used while regenerating the project file
StartLibGuid As VBGUID 'The GUID of the original target library
StartLibMajor As Integer 'The MajorVersion of the original library
StartLibMinor As Integer 'The MinorVersion of the original library
StartLibLCID As Long 'The LCID of the original library
ProjectFile As String 'The project file to edit.
ReferenceLineStart As String 'The formatted reference line to search for in the ProjectFile
fRestorableRefs As Boolean 'The references collection can be repopulated without a library reload
fRefInfoChange As Boolean 'The libraries GUID/Major/Minor/Name values have change
fGuidChange As Boolean 'The libraries GUID has changed-prompt for a SaveAs
fNameChange As Boolean 'The libraries name has changed-prompt for a SaveAs
End Type
Public Function BuildString(StartString As String, ParamArray Inserts() As Variant) As String
Dim i As Integer
Dim iPos As Integer
'BuildString = LoadResString(idStart)
BuildString = StartString
For i = 0 To UBound(Inserts)
iPos = InStr(1, BuildString, "|" & CStr(i + 1))
BuildString = Left$(BuildString, iPos - 1) & Inserts(i) & Mid$(BuildString, iPos + 2)
Next i
End Function
Public Function TempFile(strBaseName As String) As String
TempFile = String$(MAX_PATH, 0) 'More space than we need, but it can't hurt with DBCS issues
GetTempPath MAX_PATH, StrPtr(TempFile)
GetTempFileName StrPtr(TempFile), strBaseName, 0, StrPtr(TempFile)
TempFile = StrConv(TempFile, vbUnicode)
TempFile = Left$(TempFile, InStr(TempFile, vbNullChar) - 1)
End Function
Public Function PromptForFileName(ByVal hWnd As Long) As String
Dim ofn As OPENFILENAME
'Make sure we're ready to dereference an OPENFILENAME in the callback
With m_DerefOFN
If .Owner.SA.cDims = 0 Then InitArrayOwner .Owner, LenB(.pSA(0)), 0
End With
With ofn
.lStructSize = Len(ofn)
.lpstrDefExt = "tlb"
.lpstrFilter = Replace(LoadResString(cidSaveAsFilter), "|", vbNullChar)
.hwndOwner = hWnd
'Dim Pos As Long
' .lpstrFilter = LoadResString(cidSaveAsFilter)
' Do
' Pos = InStr(Pos + 1, .lpstrFilter, "|")
' If Pos = 0 Then Exit Do
' Mid$(.lpstrFilter, Pos, 1) = vbNullChar
' Loop
.Flags = OFN_ENABLEHOOK Or cdlOFNOverwritePrompt Or cdlOFNNoReadOnlyReturn Or cdlOFNPathMustExist Or cdlOFNExplorer Or cdlOFNHideReadOnly
.lpstrFile = String$(512, 0)
.nMaxFile = 512
.lpfnHook = FuncAddr(AddressOf SaveAsHookProc)
.lpstrTitle = LoadResString(cidSaveAsTitle)
If 0 = GetSaveFileName(ofn) Then Exit Function
PromptForFileName = Left$(.lpstrFile, InStr(.lpstrFile, vbNullChar) - 1)
End With
End Function
Private Function SaveAsHookProc(ByVal hWnd As Long, ByVal uMsg As Long, ByVal wParam As Long, lParam As OFNOTIFY) As Long
Dim strFile As String
Dim lpstrFile As Long
If uMsg = WM_NOTIFY Then
If lParam.hdr.Code = CDN_FILEOK Then
With m_DerefOFN
m_DerefOFN.Owner.SA.pvData = lParam.lpOFN
lpstrFile = .pSA(0).lpstrFile
End With
strFile = StrConv(SysAllocStringByteLen(lpstrFile, lstrlen(lpstrFile)), vbUnicode)
If Not IsTypeLibEditable(strFile) Then
Select Case MsgBox(LoadResString(cidSaveAsNotATypeLib), vbInformation Or vbYesNo Or vbDefaultButton2)
Case vbYes
'Nothing to do, just return zero
Case vbNo
'Return to the dialog
SaveAsHookProc = 1
SetWindowLong hWnd, DWL_MSGRESULT, 1
End Select
End If
End If
End If
End Function
'Returns True if a library is editable or if the specified file does not exist.
Public Function IsTypeLibEditable(FilePath As String) As Boolean
Dim fNum As Integer
Dim fCloseFile As Boolean
Dim iMagic As Long
On Error GoTo Error
fNum = FreeFile
Open FilePath For Binary Access Read As fNum
fCloseFile = True
If LOF(fNum) = 0 Then
IsTypeLibEditable = True
Else
Get #fNum, 1, iMagic
'Make sure this is a (new format) typelib, not a resource in a dll or exe.
IsTypeLibEditable = iMagic = &H5446534D
End If
fCloseFile = False
Close #fNum
Exit Function
Error:
If fCloseFile Then
Close #fNum
Else
IsTypeLibEditable = True 'File doesn't exist
End If
End Function
Private Function FuncAddr(ByVal pfn As Long) As Long
FuncAddr = pfn
End Function
'Redirection function for PushParamThunk address
Public Sub SaveActiveRefMakeReloadModifications(Locals As SaveActiveRefLocals)
Dim fCantKill As Boolean
On Error Resume Next
SaveActiveRefUnregisterTarget Locals
Kill Locals.TargetFile
fCantKill = Err
On Error GoTo 0
If fCantKill Then
SaveActiveRefRegisterTarget Locals
Exit Sub
End If
'Move the file
Name Locals.NewFile As Locals.TargetFile
'Reregister the file
SaveActiveRefRegisterTarget Locals
'Update the project file. The NewFile name is now available to write to.
RewriteProjectFile Locals
'This signals that everything worked
Locals.NewFile = vbNullString
End Sub
Private Sub RewriteProjectFile(Locals As SaveActiveRefLocals)
Dim GuidString As String * 38
Dim strLine As String
Dim fNumDst As Integer
Dim fNumSrc As Integer
Dim fCloseDstFile As Boolean
Dim fCloseSrcFile As Boolean
Dim iPos1 As Long
Dim iPos2 As Long
Dim fFoundLine As Boolean
On Error GoTo Error
fNumDst = FreeFile
Open Locals.NewFile For Output As fNumDst
fCloseDstFile = True
fNumSrc = FreeFile
Open Locals.ProjectFile For Input As fNumSrc
fCloseSrcFile = True
Do Until EOF(fNumSrc)
Line Input #fNumSrc, strLine
If InStr(1, strLine, Locals.ReferenceLineStart, vbBinaryCompare) = 1 Then
fFoundLine = True
'Need to rewrite the file line. We have all of the information in locals
'except for the local path to the target file, which can be gleaned from
'the current setting in the project file.
'Skip the LCID number
iPos1 = InStr(Len(Locals.ReferenceLineStart) + 1, strLine, "#", vbBinaryCompare) + 1
iPos2 = InStr(iPos1, strLine, "#", vbBinaryCompare)
With Locals
StringFromGUID2 .NewLibGuid, GuidString
Print #fNumDst, "Reference=*\G"; GuidString; "#"; _
Hex$(.NewLibMajor); "."; Hex$(.NewLibMinor); "#"; Hex$(.NewLibLCID); "#"; _
Mid$(strLine, iPos1, iPos2 - iPos1); "#";
If Len(.NewLibDesc) = 0 Then
Print #fNumDst, .NewLibName
Else
Print #fNumDst, .NewLibDesc
End If
End With
'Finish up here to avoid the check
Do Until EOF(fNumSrc)
Line Input #fNumSrc, strLine
Print #fNumDst, strLine
Loop
Else
Print #fNumDst, strLine
End If
Loop
fCloseDstFile = False
Close #fNumDst
fCloseSrcFile = False
Close #fNumSrc
If fFoundLine Then
Kill Locals.ProjectFile
Name Locals.NewFile As Locals.ProjectFile
Else
SaveActiveRefKillNewFile Locals
End If
Exit Sub
Error:
'Not really anything to do here. This is a very unlikely failure
If fCloseDstFile Then Close #fNumDst
If fCloseSrcFile Then Close #fNumSrc
SaveActiveRefKillNewFile Locals
End Sub
Public Sub SaveActiveRefKillNewFile(Locals As SaveActiveRefLocals)
Debug.Assert Len(Locals.NewFile)
On Error Resume Next
Kill Locals.NewFile
Locals.NewFile = vbNullString
On Error GoTo 0
End Sub
Public Sub SaveActiveRefUnregisterTarget(Locals As SaveActiveRefLocals)
On Error Resume Next 'Just in case it isn't registered
With Locals
UnRegisterTypeLib .StartLibGuid, .StartLibMajor, .StartLibMinor, .StartLibLCID, SYS_WIN32
End With
On Error GoTo 0
End Sub
Public Sub SaveActiveRefRegisterTarget(Locals As SaveActiveRefLocals)
On Error Resume Next
'We must use RegisterTypeLib here because LoadTypeLibEx doesn't register it
'reliably if it already considers this a loaded typelib.
RegisterTypeLib LoadTypeLibEx(Locals.TargetFile), Locals.TargetFile, vbNullString
On Error GoTo 0
End Sub
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -