2025/07/01

Excel / 使用VBA執行ffmpeg合併圖檔與音檔成為影音檔 4

「Excel / 使用VBA執行ffmpeg合併圖檔與音檔成為影音檔」的第4篇

說明如何調用Windows API ,讓VBA內建的shell也可以等待程式碼執行

程式碼如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77


Private Const SYNCHRONIZE = &H100000
Private Const INFINITE = &HFFFFFFFF

#If Win64 Then
Private Declare PtrSafe Function OpenProcess Lib "kernel32" _
(ByVal dwDesiredAccess As LongPtr, ByVal bInheritHandle As LongPtr, ByVal dwProcessId As LongPtr) As LongPtr
Private Declare PtrSafe Function CloseHandle Lib "kernel32" (ByVal hObject As LongPtr) As LongPtr
Private Declare PtrSafe Function WaitForSingleObject Lib "kernel32" _
(ByVal hHandle As LongPtr, ByVal dwMilliseconds As LongPtr) As LongPtr
#Else
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 WaitForSingleObject Lib "kernel32" _
(ByVal hHandle As Long, ByVal dwMilliseconds As Long) As Long
#End If

' 修改
Public Sub creatVideo2()

r = Sheets(1).Range("B1").End(xlDown).Row
If r = 1048576 Then
Exit Sub
End If

For i = 2 To r
If Sheets(1).Range("A" & i).Value <> "◎" Then
If Sheets(1).Range("B" & i).Value <> "" And Sheets(1).Range("C" & i).Value <> "" Then

On Error GoTo CleanUp

Application.DisplayAlerts = False
Application.ScreenUpdating = False

Dim windowStyle As Integer: windowStyle = 3
Dim wavName As String, mp4Name As String, imgPath As String
Dim n As Long, s As String
Dim pId As LongPtr, pHnd As LongPtr

wavName = Sheets(1).Range("C" & i).Value

n = InStr(1, wavName, ".", vbTextCompare)
mp4Name = Mid(wavName, 1, n - 1) & ".mp4"

imgPath = Sheets(1).Range("B" & i).Value

Debug.Print mp4Name


' 如果用環境參數在WScript.Shell會無法執行
' ffmpegFile = "C:\Users\trico\Desktop\ffmpeg\bin\ffmpeg.exe"
ffmpegFile = "C:\Users\edu\Desktop\yt-dlp\ffmpeg\bin\ffmpeg.exe"


' 建立 ffmpeg 指令
s = ffmpegFile & " -framerate 1 -i " & imgPath & " -i " & Chr(34) & wavName & Chr(34) & " -f mp4 -c:v libx264 -pix_fmt yuv420p " & Chr(34) & mp4Name & Chr(34)
Debug.Print s

' 執行並等待 ffmpeg 完成
pId = Shell(s, windowStyle)
pHnd = OpenProcess(SYNCHRONIZE, 0, pId)

If pHnd <> 0 Then
WaitForSingleObject pHnd, INFINITE
CloseHandle pHnd
Debug.Print "輸出:" & mp4Name
Sheets(1).Range("A" & i).Value = "◎"
Sheets(1).Range("D" & i).Value = mp4Name
End If
End If
End If
Next

CleanUp:
Application.DisplayAlerts = True
Application.ScreenUpdating = True
End Sub





 

#1-2

定義16位元的常數SYNCHRONIZE用於OpenProcess()、INFINITE用於WaitForSingleObject()

#4-16

調用kernel32的3個函式(Function) OpenProcess、CloseHandle、WaitForSingleObje

#59-69

利用shell的回傳值,如果執行成功會有工作識別碼(Process Id)

再利用windows API來偵測這個工作識別碼所代表的程式的執行狀態

呼叫 OpenProcess API 取得 Process Handle(pHnd), 然後再利用 Process Handle 呼叫 WaitForSingleObject, 即可等待被 Shell 執行的程式執行完畢(第2個參數設定為INFINITE), 才繼續向下執行(關閉當前程序)

詳細說明可以參考這篇文章「Shell & Wait 的程式怎麼寫?

函式的參數值可以參考這篇文章「【VB6|第27期】如何在VB6中使用Shell函数实现同步执行

0 comments:

張貼留言