PowerShell发送WM_COPYDATA至MPC-HC遇指针转换错误求助
Fixing WM_COPYDATA Communication with MPC-HC in PowerShell
Let's break down the issues in your code and fix them step by step:
Key Problems in Your Original Code
- Incorrect P/Invoke Declaration: Your
SendMessagemethod declareslParamasref IntPtr, but forWM_COPYDATA, this parameter needs to be a reference to aCOPYDATASTRUCTinstance to match the Windows API requirement. - String to IntPtr Conversion: You can't directly assign a .NET string or its first character to
lpData—you need to marshal the string to unmanaged memory to get a valid pointer that MPC-HC can read. - Invalid
SendMessageCall: Passing[ref]$cds[0]is incorrect; you need to pass theCOPYDATASTRUCTinstance directly via[ref]$cds. - Race Condition:
Start-Processmight return before MPC-HC's window is fully initialized, leading to an invalidMainWindowHandle.
Corrected Working Code
Add-Type @" using System; using System.Runtime.InteropServices; public class MpcMessages { [DllImport("user32.dll", CharSet = CharSet.Auto)] public static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, ref COPYDATASTRUCT lParam); [StructLayout(LayoutKind.Sequential)] public struct COPYDATASTRUCT { public IntPtr dwData; public int cbData; public IntPtr lpData; } } "@ # Constants for MPC-HC commands and WM_COPYDATA message $WM_COPYDATA = 0x004A $CMD_OSDSHOWMESSAGE = 0xA0005000 # Start MPC-HC and wait for its window to be ready $mpcProcess = Start-Process -PassThru -FilePath "C:\Program Files (x86)\K-Lite Codec Pack\MPC-HC64\mpc-hc64.exe" -ArgumentList "/new" # Wait until MainWindowHandle is valid (non-zero) while ($mpcProcess.MainWindowHandle -eq [IntPtr]::Zero) { Start-Sleep -Milliseconds 100 } # Prepare the message to send $message = "Hello from PowerShell!" # Marshal the string to unmanaged Unicode memory (MPC-HC uses Unicode encoding) $messagePtr = [System.Runtime.InteropServices.Marshal]::StringToHGlobalUni($message) try { # Initialize the COPYDATASTRUCT with correct values $cds = New-Object MpcMessages+COPYDATASTRUCT $cds.dwData = [IntPtr]$CMD_OSDSHOWMESSAGE # cbData = total bytes of the string (Unicode = 2 bytes per char) + 2 bytes for null terminator $cds.cbData = ($message.Length + 1) * 2 $cds.lpData = $messagePtr # Send the WM_COPYDATA message to MPC-HC $result = [MpcMessages]::SendMessage( $mpcProcess.MainWindowHandle, $WM_COPYDATA, [System.Diagnostics.Process]::GetCurrentProcess().MainWindowHandle, [ref]$cds ) if ($result -eq [IntPtr]::Zero) { Write-Warning "Message might not have been received by MPC-HC" } else { Write-Host "Message sent successfully! You should see it in MPC-HC's OSD." } } finally { # Free the unmanaged memory to avoid leaks [System.Runtime.InteropServices.Marshal]::FreeHGlobal($messagePtr) }
Explanation of Critical Changes
- Fixed P/Invoke Signature: The
SendMessagemethod now correctly accepts aref COPYDATASTRUCTforlParam, aligning with howWM_COPYDATAworks in the Windows API. - Proper String Marshaling:
Marshal.StringToHGlobalUniconverts the .NET string to an unmanaged Unicode pointer that MPC-HC can interpret. We free this memory in afinallyblock to prevent memory leaks. - Valid
cbDataCalculation: For Unicode strings, each character uses 2 bytes, so we multiply the string length by 2 and add an extra 2 bytes for the required null terminator. - Window Readiness Check: The loop ensures we don't send the message until MPC-HC's window handle is fully initialized, avoiding invalid handle errors.
- Correct
SendMessageCall: We pass theCOPYDATASTRUCTdirectly via[ref]$cdsand use the current PowerShell process's window handle forwParam(as required byWM_COPYDATA).
内容的提问来源于stack exchange,提问作者Keith
相关产品推荐
相关产品推荐

