См. Модуль VBA и Класс VBA , ниже которого я недавно построил, разрешая прямые вызовы веб-службы Amazon Polly из MS Office, сохраняя полученный MP3 в файл.Пара замечаний:
- Я только подтвердил успешные звонки в Amazon Polly с версиями MS Word и MS Excel для Office 365 для Windows 10, но, учитывая мой прошлый опыт работы с VBA, у меня нет никаких причинполагать, что код не будет работать с другими вариантами.
- Точка входа: callAwsPolly .
- Вам необходимо соответствующим образом настроить параметры AWS (т. е. aws.host , aws.region , aws.service , & aws.uri ).
- Полномочия ( aws.accessKey & aws.secretKey ) являются стандартными учетными данными примера AWS, и их, очевидно, необходимо будет заменить на свои собственные учетные данные AWS.
- Обратите внимание, что это очень плохо практика встраивания учетных данных в код.Я не уверен в вашем конкретном приложении, но в моем случае я создал свое собственное хранилище ключей, используя при желании парольную фразу или MAC-адрес в качестве ключа расшифровки для хранилища ключей.Концепция управления учетными данными - это еще одна тема, которую я здесь не рассматриваю ...
Чтобы включить эту функциональность в продукт MS Office, добавьте следующее в качестве модуля VBA ...
Option Explicit
Sub callAwsPolly()
Dim aws As amazonWebService
Set aws = New amazonWebService
aws.host = "polly.us-east-2.amazonaws.com"
aws.region = Split(aws.host, ".")(1)
aws.service = "polly"
aws.uri = "/v1/speech"
' !!! NOTE: The following is very bad practice to embed credentials in code!!!
aws.accessKey = "AKIAIOSFODNN7EXAMPLE"
aws.secretKey = "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
Dim requestParameters As String
requestParameters = "{#OutputFormat#: #mp3#, #Text#: #Polly want a cracker?#, #TextType#: #ssml#, #VoiceId#: #Emma#}"
requestParameters = Replace(requestParameters, "#", """")
Dim httpResponse As Object
Set httpResponse = aws.callWebService("application/json", requestParameters)
If httpResponse Is Nothing Then
MsgBox "Call to AWS Polly failed."
ElseIf httpResponse.Status = 200 Then
MsgBox "Call to AWS Polly succeeded! MP3 file being saved."
Dim iFile As Long: iFile = FreeFile
Open ActiveWorkbook.FullName & ".mp3" For Binary Access Write As #iFile
Put iFile, , httpResponse.Responsebody
Close #iFile
Else
MsgBox "Call to AWS Polly failed:" + CStr(httpResponse.Status) + " " + httpResponse.StatusText + " " + httpResponse.ResponseText
End If
End Sub
' Adapted from https://stackoverflow.com/questions/36384741/cant-use-getbytes-and-computehash-methods-on-vba
Public Function hmacSha256(key As Variant, stringToHash As Variant) As Byte()
Dim ssc As Object
Set ssc = CreateObject("System.Security.Cryptography.HMACSHA256")
ssc.key = str2byte(key)
hmacSha256 = ssc.ComputeHash_2(str2byte(stringToHash))
Set ssc = Nothing
End Function
Public Function sha256(stringToHash As Variant) As Byte()
Dim ssc As Object
Set ssc = CreateObject("System.Security.Cryptography.SHA256Managed")
sha256 = ssc.ComputeHash_2(str2byte(stringToHash))
Set ssc = Nothing
End Function
Public Function str2byte(s As Variant) As Byte()
If VarType(s) = vbArray + vbByte Then
str2byte = s
ElseIf VarType(s) = vbString Then
str2byte = StrConv(s, vbFromUnicode)
Else
Exit Function
End If
End Function
Public Function byte2hex(byteArray() As Byte) As String
Dim i As Long
For i = 0 To UBound(byteArray)
byte2hex = byte2hex & Right(Hex(256 Or byteArray(i)), 2)
Next
byte2hex = LCase(byte2hex)
End Function
... и добавьте следующий код в качестве модуля класса VBA, назвав его "
amazonWebService " ...
'
' Class Module: amazonWebService
'
Private className As String
Public host As String
Public region As String
Public service As String
Public uri As String
Public accessKey As String
Public secretKey As String
Private Sub Class_Initialize()
className = "amazonWebService"
host = ""
region = ""
uri = ""
service = ""
accessKey = ""
secretKey = ""
End Sub
Public Function callWebService(contentType As String, requestParameters As String) As Object
If host = "" Or region = "" Or uri = "" Or service = "" Or accessKey = "" Or secretKey = "" Then
Err.Raise _
1000, _
className, _
className + ": Please set properties before calling the amazon web service: host, region, uri, service, accessKey, and secretKey."
callWebService = Null
Exit Function
End If
Dim amzDate As String, dateStamp As String
amzDate = date2iso8601(GMT())
dateStamp = Left(amzDate, 8)
' ************* TASK 1: CREATE A CANONICAL REQUEST *************
' http://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html
'Step 1 is to define the verb (GET, POST, etc.)
Dim method As String
method = "POST"
' Step 2: Create canonical URI (set by the calling program)
Dim canonicalUri As String
canonicalUri = uri
' Step 3: Create the canonical query string. In this example (POST), request
' parameters are passed in the body of the request and the query string
' is blank.
Dim canonicalQueryString As String
canonicalQueryString = ""
' Step 4: Create the canonical headers. Header names must be trimmed
' and lowercase, and sorted in code point order from low to high.
' Note that there is a trailing \n.
Dim canonicalHeaders As String
canonicalHeaders = _
"host:" + host + vbLf + _
"x-amz-date:" + amzDate + vbLf
' Step 5: Create the list of signed headers. This lists the headers
' in the canonical_headers list, delimited with ";" and in alpha order.
' Note: The request can include any headers; canonical_headers and
' signed_headers include those that you want to be included in the
' hash of the request. "Host" and "x-amz-date" are always required.
Dim signedHeaders As String
signedHeaders = "host;x-amz-date"
' Step 6: Create payload hash. In this example, the payload (body of
' the request) contains the request parameters.
Dim payloadHash As String
payloadHash = byte2hex(sha256(requestParameters))
' Step 7: Combine elements to create canonical request
Dim canonicalRequest As String
canonicalRequest = method + vbLf + _
canonicalUri + vbLf + _
canonicalQueryString + vbLf + _
canonicalHeaders + vbLf + _
signedHeaders + vbLf + _
payloadHash
' ************* TASK 2: CREATE THE STRING TO SIGN*************
' Match the algorithm to the hashing algorithm you use, either SHA-1 or
' SHA-256 (recommended)
Dim algorithm As String, credentialScope As String, stringToSign As String
algorithm = "AWS4-HMAC-SHA256"
credentialScope = dateStamp + "/" + region + "/" + service + "/aws4_request"
stringToSign = _
algorithm + vbLf + _
amzDate + vbLf + _
credentialScope + vbLf + _
byte2hex(sha256(canonicalRequest))
' ************* TASK 3: CALCULATE THE SIGNATURE *************
' Create the signing key using the function defined above.
Dim signingKey() As Byte, signature As String
signingKey = getSignatureKey(secretKey, dateStamp, region, service)
' Sign the string_to_sign using the signing_key
signature = byte2hex(hmacSha256(signingKey, stringToSign))
' ************* TASK 4: ADD SIGNING INFORMATION TO THE REQUEST *************
' Put the signature information in a header named Authorization.
Dim authorizationHeader As String
authorizationHeader = _
algorithm + " " + _
"Credential=" + accessKey + "/" + credentialScope + ", " + _
"SignedHeaders=" + signedHeaders + ", " + _
"Signature=" + signature
' ************* SEND THE REQUEST TO AWS! *************
Dim http As Object
Set http = CreateObject("WinHttp.WinHttpRequest.5.1")
http.Open "POST", "https://" + host + uri, False
http.setrequestheader "content-type", contentType
http.setrequestheader "host", host
http.setrequestheader "x-amz-date", amzDate
http.setrequestheader "authorization", authorizationHeader
http.Send requestParameters
' If the result is 403 Forbidden, then clear the current selected credentials.
If http.Status = 403 Then
accessKey = ""
secretKey = ""
End If
' Return the HTTP response back to the calling program.
Set callWebService = http
End Function
Private Function GMT() As Date
Dim dt As Object
Set dt = CreateObject("WbemScripting.SWbemDateTime")
dt.SetVarDate Now
GMT = dt.GetVarDate(False)
Set dt = Nothing
End Function
Private Function date2iso8601(dateTime As Date) As String
date2iso8601 = Format(dateTime, "yyyymmdd\Thhnnss\Z")
End Function
Private Function getSignatureKey(key As String, dateStamp As String, regionName As String, serviceName As String) As Byte()
Dim kDate() As Byte, kRegion() As Byte, kService() As Byte, kSigning() As Byte
kDate = hmacSha256("AWS4" + key, dateStamp)
kRegion = hmacSha256(kDate, regionName)
kService = hmacSha256(kRegion, serviceName)
kSigning = hmacSha256(kService, "aws4_request")
getSignatureKey = kSigning
End Function