Powershell 在threadjob中使用SetImage
我有一个将图片插入PPT的功能,包括以下代码:Powershell 在threadjob中使用SetImage,powershell,Powershell,我有一个将图片插入PPT的功能,包括以下代码: $file = get-item($pic); $img = [System.Drawing.Image]::Fromfile($file); [System.Windows.Forms.Clipboard]::SetImage($img); $slide = $pp1.Slides.Item($targetslide) Start-Sleep -Seconds 5 $shape = $Slide.Shapes.PasteSpecia
$file = get-item($pic);
$img = [System.Drawing.Image]::Fromfile($file);
[System.Windows.Forms.Clipboard]::SetImage($img);
$slide = $pp1.Slides.Item($targetslide)
Start-Sleep -Seconds 5
$shape = $Slide.Shapes.PasteSpecial($ppPasteJPG,$false,$null,$null,$null,$null)
但是,我创建了一个使用此函数的函数,并将其放入threadjob的操作脚本中。现在,当它被激活时,会产生错误:
Exception calling "SetImage" with "1" argument(s): "Current thread must be set to single thread apartment (STA) mode before OLE calls can be made. Ensure that your Main function has STAThreadAttribute marked on it."
At C:\...\PicInsertPPT.ps1:17 char:1
+ [System.Windows.Forms.Clipboard]::SetImage($img);
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : ThreadStateException
我可以用什么替换该行,它将作为threadjob中的一个任务与多个并行任务一起工作
我正在考虑申请:
CommandBars.ExecuteMso("PictureInsertFromFile")
但我不完全确定如何控制以这种方式插入的图片
编辑:我的threadjob代码是:
Function ThreadMaster{
param ($folder)
$global:folder = $folder
# Use the system's temp folder in this example.
$global:dir = $folder
# Define the tasks as an array of custom objects that specify the dir.
# and file name pattern to monitor as well as the action script block to
# handle the events.
$tasks = # array of custom objects to describe the
[pscustomobject] @{
DirToMonitor = $dir
FileNamePattern = '*.csv'
Action = {
$path = $EventArgs.FullPath
$name = $EventArgs.Name
$changeType = $EventArgs.ChangeType
$timeStamp = $EventArgs.TimeGenerated
Write-Host -NoNewLine "`nINFO: Event 1 raised:`n$($EventArgs | Format-List | Out-String)"
Import-Module C:\...Report1V1.ps1
$Actionpath = Split-Path $Path
write-host $Actionpath " Ready for Report1"
Report1 $Actionpath
write-host $Actionpath "Report1 Generated"
"`nEvent 1 output: " + $EventArgs.Fullpath
}
}
},
[pscustomobject] @{
DirToMonitor = $dir
FileNamePattern = '*4.4_10X*'
Action = {
$path = $Event.SourceEventArgs.FullPath
$name = $Event.SourceEventArgs.Name
$changeType = $Event.SourceEventArgs.ChangeType
$timeStamp = $Event.TimeGenerated
Write-Host -NoNewLine "`nINFO: Event 2 raised:`n$($EventArgs | Format-List | Out-String)"
Import-Module C:\...\Report2V1.ps1
$Actionpath = Split-Path $Path
$Actionpath = Split-Path $Actionpath
write-host $Actionpath " Ready for Report2"
Report2 $Actionpath
write-host "Report2 Generated"
"`nEvent 2 output: " + $EventArgs.Fullpath
}
}
}
# Start a separate thread job for each action task.
$threadJobs = $tasks | ForEach-Object {
Start-ThreadJob -ArgumentList $_ {
param([pscustomobject] $task)
# Create and initialize a thread-specific watcher.
# Note: To keep system load low, it's generally better to use a *shared*
# watcher, if feasible. You can define it in the caller's scope
# and access here via $using:watcher
$watcher = [System.IO.FileSystemWatcher] [ordered] @{
Path = $task.DirToMonitor
Filter = $task.FileNamePattern
IncludeSubdirectories = $true
EnableRaisingEvents = $true # start watching.
InternalBufferSize = 65536
}
# Subscribe to the watcher's Created events, which returns an event job.
# This indefinitely running job receives the output from the -Action script
# block whenever the latter is called after an event fires.
$eventJob = Register-ObjectEvent -ea stop $watcher Created -Action $task.Action
Write-Host "`nINFO: Watching $($task.DirToMonitor) for creation of $($task.FileNamePattern) files..."
# Indefinitely wait for output from the action blocks and relay it.
try {
while ($true) {
Receive-Job $eventJob
Start-Sleep -Milliseconds 500 # sleep a little
}
}
finally {
# !! This doesn't print, presumably because this is killed by the
# !! *caller* being killed, which then doesn't relay the output anymore.
Write-Host "Cleaning up thread for task $($task.FileNamePattern)..."
# Dispose of the watcher.
$watcher.Dispose()
# Remove the event job (and with it the event subscription).
$eventJob | Remove-Job -Force
}
}
}
Write-Host "Starting tasks...`nUse Ctrl-C to stop."
# Indefinitely wait for and display output from the thread jobs.
# Use Ctrl+C to stop.
$dtStart = [datetime]::UtcNow
while ($true) {
# Receive thread job output, if any.
$threadJobs | Receive-Job
# Sleep a little.
Write-Host . -NoNewline
Start-Sleep -Milliseconds 500
}
}
不确定在使用线程作业时是否可以控制单元状态。您可能需要直接使用运行空间重写。你有包含线程作业的函数代码吗?我不太确定你想要代码的哪一部分。我有一个Threadjob,它有两个操作块,一个用于Report1Generator,另一个用于Report2Generator。在Report2Generator中,它调用函数PicInsertPPT。PicInsertPPT的代码显然与多线程不兼容。请放入包含线程作业的代码并抛出此错误,以便人们可以复制、粘贴和复制。无论如何,您需要做的是用自定义运行空间替换线程作业,并将其单元状态设置为STA。在那里,我添加了它
powershell.exe-STA