AlphaBlend 在一个软件的一台机器上失败
AlphaBlend fails on one machine in one software
我正在使用与如下声明相同的 AlphaBlend 函数:
Public Declare Function AlphaBlend Lib "MSIMG32.dll" (ByVal hDCDest As Long, ByVal nXOriginDest As Long, ByVal nYOriginDest As Long, ByVal nWidthDest As Long, ByVal nHeightDest As Long, ByVal hDCSrc As Long, ByVal nXOriginSrc As Long, ByVal nYOriginSrc As Long, ByVal nWidthSrc As Long, ByVal nHeightSrc As Long, ByVal lBlendFunction As Long) As Long
在某些机器上,我的代码工作得非常好,并且完全按照它应该做的去做。
在一台机器上,相同的代码在应用程序 A 中运行良好,但相同的代码在应用程序 B 中使 AlphaBlend 失败。
想象一下:
你有 2 个同卵双胞胎,他们都在吃一个苹果。两个苹果完全一样
一个双胞胎成功吞下了它,另一个双胞胎在尝试这样做时死了。
GetLastError returns 0.
我该如何调查问题所在?
一些机器,一切正常。
然而,在有问题的一台机器上,我在两个应用程序中编译了完全相同的代码 运行:应用程序 A 和应用程序 B。
在应用程序A中,AlphaBlend失败,在应用程序B中,AlphaBlend成功。
它总是在应用程序 A 中失败。
我什至怀疑 VB6 的理智并检查“Len”是否确实 returns 正确的长度。
我使用 VB6 已有 20 年了,但我从未经历过如此疯狂的事情。
有人知道为什么相同的代码可能会在那个应用程序中失败吗?
Option Explicit
Private Declare Function GetLastError Lib "kernel32" () As Long
Private Declare Function AlphaBlend Lib "MSIMG32.dll" (ByVal hDCDest As Long, ByVal nXOriginDest As Long, ByVal nYOriginDest As Long, ByVal nWidthDest As Long, ByVal nHeightDest As Long, ByVal hDCSrc As Long, ByVal nXOriginSrc As Long, ByVal nYOriginSrc As Long, ByVal nWidthSrc As Long, ByVal nHeightSrc As Long, ByVal lBlendFunction As Long) As Long
Private Declare Function FindWindow Lib "USER32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare Sub MoveMemory Lib "Kernel32.dll" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
Private Declare Function GetClientRect Lib "USER32" (ByVal hWnd As Long, lpRect As RECT) As Long
Private Declare Function GetDC Lib "USER32" (ByVal hWnd As Long) As Long
Private Declare Function ReleaseDC Lib "User32.dll" (ByVal hWnd As Long, ByVal hdc As Long) As Long
Private Type BLENDFUNCTION
BlendOp As Byte
BlendFlags As Byte
SourceConstantAlpha As Byte
AlphaFormat As Byte
End Type
Private Type RECT
Left As Long
Top As Long
Right As Long
Bottom As Long
End Type
Private Const AC_SRC_OVER = &H0
Private Sub Timer1_Timer()
Dim lHwnd&
lHwnd = FindWindow(vbNullString, "twsseetechcamwin")
If lHwnd = 0 Then
Me.Caption = "is null!"
Exit Sub
End If
Me.Caption = "ok"
Dim LBF As Long
Dim bf As BLENDFUNCTION
With bf
.BlendOp = AC_SRC_OVER
.SourceConstantAlpha = 255
End With
Dim lLen&
lLen = Len(bf) 'just check for sanity... I wanted to make sure that it's 4, and it indeed is
Call MoveMemory(LBF, bf, Len(bf)) 'Copy struct into a Long var
Dim rOtherWin As RECT
GetClientRect lHwnd, rOtherWin
Dim lOtherDC&
lOtherDC = GetDC(lHwnd)
Dim r As RECT
GetClientRect Me.hWnd, r
Dim lret&
lret = AlphaBlend(Me.hdc, 0, 0, (r.Right - r.Left), (r.Bottom - r.Top), lOtherDC, 0, 0, (rOtherWin.Right - rOtherWin.Left), (rOtherWin.Bottom - rOtherWin.Top), LBF)
Dim lWinErr&
lWinErr = GetLastError()
Me.Caption = Time & " ret: " & lret & ", err: " & lWinErr&
ReleaseDC lHwnd, lOtherDC
End Sub
由于这是特定于机器的(假设它是准确的),因此两个程序 A 和 B 可能没有加载相同的副本 MSIMG32.dll。
我会检查:PC 上是否有该 DLL 的多个副本?特别是如果程序文件夹中有 A 或 B 的副本?
您还可以 运行 进程监视器并观察 运行ning 程序以准确查看正在加载的 DLL。这至少可以确认它们都 运行 正在使用相同的 DLL 并将其作为潜在原因消除。
除此之外,我个人会加入一些调试日志记录并真正验证失败函数的输入是否相同。
当 OS 设置为高 DPI 设置(例如以 150% 显示所有内容)并且如果应用程序具有声明 dpiaware=true
.
的清单时,就会出现问题
有 2 种可能的解决方案:
- 从清单中删除
dpiaware
- 也向其他进程添加一个清单,并在该清单中也声明
dpiaware=true
。这样两个过程之间就没有差异了。这当然只适用于您的产品/流程,并且您可以使用清单对其进行编译。
我正在使用与如下声明相同的 AlphaBlend 函数:
Public Declare Function AlphaBlend Lib "MSIMG32.dll" (ByVal hDCDest As Long, ByVal nXOriginDest As Long, ByVal nYOriginDest As Long, ByVal nWidthDest As Long, ByVal nHeightDest As Long, ByVal hDCSrc As Long, ByVal nXOriginSrc As Long, ByVal nYOriginSrc As Long, ByVal nWidthSrc As Long, ByVal nHeightSrc As Long, ByVal lBlendFunction As Long) As Long
在某些机器上,我的代码工作得非常好,并且完全按照它应该做的去做。
在一台机器上,相同的代码在应用程序 A 中运行良好,但相同的代码在应用程序 B 中使 AlphaBlend 失败。
想象一下: 你有 2 个同卵双胞胎,他们都在吃一个苹果。两个苹果完全一样
一个双胞胎成功吞下了它,另一个双胞胎在尝试这样做时死了。
GetLastError returns 0.
我该如何调查问题所在?
一些机器,一切正常。
然而,在有问题的一台机器上,我在两个应用程序中编译了完全相同的代码 运行:应用程序 A 和应用程序 B。
在应用程序A中,AlphaBlend失败,在应用程序B中,AlphaBlend成功。 它总是在应用程序 A 中失败。
我什至怀疑 VB6 的理智并检查“Len”是否确实 returns 正确的长度。
我使用 VB6 已有 20 年了,但我从未经历过如此疯狂的事情。
有人知道为什么相同的代码可能会在那个应用程序中失败吗?
Option Explicit
Private Declare Function GetLastError Lib "kernel32" () As Long
Private Declare Function AlphaBlend Lib "MSIMG32.dll" (ByVal hDCDest As Long, ByVal nXOriginDest As Long, ByVal nYOriginDest As Long, ByVal nWidthDest As Long, ByVal nHeightDest As Long, ByVal hDCSrc As Long, ByVal nXOriginSrc As Long, ByVal nYOriginSrc As Long, ByVal nWidthSrc As Long, ByVal nHeightSrc As Long, ByVal lBlendFunction As Long) As Long
Private Declare Function FindWindow Lib "USER32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare Sub MoveMemory Lib "Kernel32.dll" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
Private Declare Function GetClientRect Lib "USER32" (ByVal hWnd As Long, lpRect As RECT) As Long
Private Declare Function GetDC Lib "USER32" (ByVal hWnd As Long) As Long
Private Declare Function ReleaseDC Lib "User32.dll" (ByVal hWnd As Long, ByVal hdc As Long) As Long
Private Type BLENDFUNCTION
BlendOp As Byte
BlendFlags As Byte
SourceConstantAlpha As Byte
AlphaFormat As Byte
End Type
Private Type RECT
Left As Long
Top As Long
Right As Long
Bottom As Long
End Type
Private Const AC_SRC_OVER = &H0
Private Sub Timer1_Timer()
Dim lHwnd&
lHwnd = FindWindow(vbNullString, "twsseetechcamwin")
If lHwnd = 0 Then
Me.Caption = "is null!"
Exit Sub
End If
Me.Caption = "ok"
Dim LBF As Long
Dim bf As BLENDFUNCTION
With bf
.BlendOp = AC_SRC_OVER
.SourceConstantAlpha = 255
End With
Dim lLen&
lLen = Len(bf) 'just check for sanity... I wanted to make sure that it's 4, and it indeed is
Call MoveMemory(LBF, bf, Len(bf)) 'Copy struct into a Long var
Dim rOtherWin As RECT
GetClientRect lHwnd, rOtherWin
Dim lOtherDC&
lOtherDC = GetDC(lHwnd)
Dim r As RECT
GetClientRect Me.hWnd, r
Dim lret&
lret = AlphaBlend(Me.hdc, 0, 0, (r.Right - r.Left), (r.Bottom - r.Top), lOtherDC, 0, 0, (rOtherWin.Right - rOtherWin.Left), (rOtherWin.Bottom - rOtherWin.Top), LBF)
Dim lWinErr&
lWinErr = GetLastError()
Me.Caption = Time & " ret: " & lret & ", err: " & lWinErr&
ReleaseDC lHwnd, lOtherDC
End Sub
由于这是特定于机器的(假设它是准确的),因此两个程序 A 和 B 可能没有加载相同的副本 MSIMG32.dll。
我会检查:PC 上是否有该 DLL 的多个副本?特别是如果程序文件夹中有 A 或 B 的副本?
您还可以 运行 进程监视器并观察 运行ning 程序以准确查看正在加载的 DLL。这至少可以确认它们都 运行 正在使用相同的 DLL 并将其作为潜在原因消除。
除此之外,我个人会加入一些调试日志记录并真正验证失败函数的输入是否相同。
当 OS 设置为高 DPI 设置(例如以 150% 显示所有内容)并且如果应用程序具有声明 dpiaware=true
.
有 2 种可能的解决方案:
- 从清单中删除
dpiaware
- 也向其他进程添加一个清单,并在该清单中也声明
dpiaware=true
。这样两个过程之间就没有差异了。这当然只适用于您的产品/流程,并且您可以使用清单对其进行编译。