Twitando com o VBA - É Possível?
Autor: Brazil SFE | Publicado: 2017-02-06T12:30:00-08:00


Twittando com o VBA




Estive recentemente trabalhando num projeto baseado em VBA que incorpora a possibilidade de postar atualizações de status para Twitter.

Antes de colocá-lo juntos consultei vários exemplos de códigos, especificações, documentação API, mensagens em blog, fórum, etc ... Estou compartilhando meus esforços aqui na esperança de salvar qualquer outra pessoa trabalhando em um projeto semelhante um pouco de tempo e / ou frustração .&nbsp;Eu também acrescentou um par de características que eu não tinha visto em outros lugares (por exemplo, usando v1.1. Da API do Twitter, incluindo imagens com tweets, integrando ligação encurtamento, etc ...), então (espero!) Eu sou acrescentando algo de novo para o corpo Tweet-via-VBA da literatura.



Alguns aspectos preliminares:

Claro, todos têm sua própria maneira de nomear variáveis ​​/ funções / subs, tabs, comentários, etc ... Se algo que estiver implementado aqui não combinar com o seu modo, faça as alterações que achar necessário.
Desejei evitar Dlls de terceiros ou add-ins.&nbsp;Assim, estamos usando scripts de controle Microsoft (msscript.ocx), e um par de bibliotecas .Net (o que significa que precisará ter o .NET Framework 1.1 ou posterior instalado).&nbsp;Uma desvantagem para isso é que o Microsoft Script&nbsp;só pode ser usado em versões do MS Office de 32 bits (2007, 2010 e 2013 devem ser todos OK).&nbsp;Nas versões&nbsp;32 bits ou 64 bits do Windows o código com está sendo executado no Office 64 bits.&nbsp;Se precisar modificar este código para rodar em 64 bits no Office, precisará implementar algumas alterações.
Certifique-se de ter adicionado as referências ao Microsoft WinHTTP Services, XML Microsoft e Microsoft Script&nbsp;ao seu projeto (Ferramentas -&gt; Adicione referências no editor VBA)
Você encontrará alguns casos óbvios de repetição de código (por exemplo, as funções&nbsp;get_basestring&nbsp;,&nbsp;&nbsp;get_status_basestring&nbsp;e&nbsp;&nbsp;get_media_basestring&nbsp;&nbsp;são bastante idênticos).&nbsp;Como estava originalmente trabalhando desta maneira, foi mais fácil concentrar a tarefa dessa forma (ou seja, Tweets de texto, Tweets com mídia, obtendo o serviço do Twitter e a informação do estado).&nbsp;Pode-se facilmente refazer as funções anteriores em uma única função, existem oportunidades adicionais para tornar o código mais eficiente / elegante e consistente.
Este desenvolvimento foi criado por&nbsp;Greg Williams&nbsp;e está licenciado sob atribuição&nbsp;Creative Commons.
O código é fornecido como está.&nbsp;Todo o uso é por sua conta e risco.







Funções da API do Windows e declarações de tipo

Primeiro, vamos definir um par de funções da API do Windows usando o&nbsp;Declare&nbsp;&nbsp;palavra-chave.&nbsp;Também vamos criar alguns tipos de dados definidos pelo usuário usando o&nbsp;&nbsp;Tipo&nbsp;&nbsp;comunicado.




#If VBA7 Then

&nbsp;&nbsp;&nbsp;&nbsp;Public Declare PtrSafe Sub GetSystemTime Lib "Kernel32" (lpSystemTime As SYSTEMTIME)

&nbsp;&nbsp;&nbsp;&nbsp;Public Declare PtrSafe Function SystemTimeToFileTime Lib "Kernel32" (lpSystemTime As SYSTEMTIME, lpFileTime As FILETIME) As LongPtr

&nbsp;&nbsp;&nbsp;&nbsp;Public Declare PtrSafe Function LocalFileTimeToFileTime Lib "Kernel32" (lpLocalFileTime As FILETIME, lpFileTime As FILETIME) As LongPtr

&nbsp;&nbsp;&nbsp;&nbsp;Public Declare PtrSafe Function FileTimeToSystemTime Lib "Kernel32" (lpFileTime As FILETIME, lpSystemTime As SYSTEMTIME) As LongPtr

#Else

&nbsp;&nbsp;&nbsp;&nbsp;Public Declare Sub GetSystemTime Lib "Kernel32" (lpSystemTime As SYSTEMTIME)

&nbsp;&nbsp;&nbsp;&nbsp;Public Declare Function SystemTimeToFileTime Lib "Kernel32" (lpSystemTime As SYSTEMTIME, lpFileTime As FILETIME) As Long

&nbsp;&nbsp;&nbsp;&nbsp;Public Declare Function LocalFileTimeToFileTime Lib "Kernel32" (lpLocalFileTime As FILETIME, lpFileTime As FILETIME) As Long

&nbsp;&nbsp;&nbsp;&nbsp;Public Declare Function FileTimeToSystemTime Lib "Kernel32" (lpFileTime As FILETIME, lpSystemTime As SYSTEMTIME) As Long

#End If

&nbsp;

Public Type FILETIME

&nbsp;&nbsp;&nbsp;&nbsp;dwLowDateTime As Long

&nbsp;&nbsp;&nbsp;&nbsp;dwHighDateTime As Long

End Type

&nbsp;

Public Type SYSTEMTIME

&nbsp;&nbsp;&nbsp;&nbsp;wYear As Integer

&nbsp;&nbsp;&nbsp;&nbsp;wMonth As Integer

&nbsp;&nbsp;&nbsp;&nbsp;wDayOfWeek As Integer

&nbsp;&nbsp;&nbsp;&nbsp;wDay As Integer

&nbsp;&nbsp;&nbsp;&nbsp;wHour As Integer

&nbsp;&nbsp;&nbsp;&nbsp;wMinute As Integer

&nbsp;&nbsp;&nbsp;&nbsp;wSecond As Integer

&nbsp;&nbsp;&nbsp;&nbsp;wMilliseconds As Integer

End Type




A sintaxe &nbsp;#If VBA7 Então ... # Else ... # End If,&nbsp;&nbsp;PtrSafe&nbsp;&nbsp;palavra-chave, e&nbsp;&nbsp;LongPtr&nbsp;&nbsp;tipo de dados são usados para permitir que o código seja executado na versão 64 bits do Office (ver&nbsp;&nbsp;este artigo MSDN&nbsp;&nbsp;para mais informações).

Novamente, conforme mencionado acima, o código como está (usando o Microsoft Script Control), não será executado no Office 64 bits.&nbsp;Mas, se decidir escrever alternativas / uso que não precisam Microsoft Script Control (ou no caso aparentemente improvável que a Microsoft lança uma versão de 64 bits do msscript.ocx), vai ser útil para ter suas declarações de função API 64-bit de pronto.



CONSTANTES

A seguir, vamos definir algumas constantes. Para obtermos as chaves de API do Twitter necessárias e os tokens, precisaremos nos inscrever no Twitter como um desenvolvedor, em seguida, registrar o aplicativo.



Neste exemplo, também usaremos encurtador de links do Google &nbsp;para encurtar os links incluídos nos tweets. Se quiser fazer o mesmo, precisará se inscrever como um desenvolvedor do Google e obter uma chave de API.

Const cnsAPIMethodP As String = "POST"

Const cnsAPIMethodG As String = "GET"

Const cnsOauthConsumerKey As String = "yourtwitterconsumerkey"

Const cnsOauthConsumerSecret As String = "yourtwitterconsumersecret"

Const cnsOauthToken As String = "yourtwitteraccesstoken"

Const cnsOauthTokenSecret As String = "yourtwitteraccesstokensecret"

Const cnsURLPost As String = "https://api.twitter.com/1.1/statuses/update.json"

Const cnsURLMedia As String = "https://api.twitter.com/1.1/statuses/update_with_media.json"

Const cnsURLStatus As String = "https://api.twitter.com/1.1/help/configuration.json"

Const cnsMethod As String = "HMAC-SHA1"

Const cnsOauthVersion As String = "1.0"

'Following only necessary if using Google's goo.gl link shortener API

Const cnsGoogleShortenerURL As String = "https://www.googleapis.com/urlshortener/v1/url"

Const cnsGoogleShortenerKey As String = "yourgoogleshortenerkeyhere"



Funções auxiliares

Em seguida, olharemos para algumas funções auxiliares para criar / enviar nossos tweets.

O&nbsp;&nbsp;LocalTimeToUTC&nbsp;&nbsp;função converte um valor de data em formato UTC.&nbsp;Graças ao&nbsp;código do&nbsp;Allen Wyatt.


Public Function LocalTimeToUTC(dteTime As Date) As Date

&nbsp;&nbsp;&nbsp;&nbsp;Dim dteLocalFileTime As FILETIME

&nbsp;&nbsp;&nbsp;&nbsp;Dim dteFileTime As FILETIME

&nbsp;&nbsp;&nbsp;&nbsp;Dim dteLocalSystemTime As SYSTEMTIME

&nbsp;&nbsp;&nbsp;&nbsp;Dim dteSystemTime As SYSTEMTIME

&nbsp;

&nbsp;&nbsp;&nbsp;&nbsp;dteLocalSystemTime.wYear = CInt(Year(dteTime))

&nbsp;&nbsp;&nbsp;&nbsp;dteLocalSystemTime.wMonth = CInt(Month(dteTime))

&nbsp;&nbsp;&nbsp;&nbsp;dteLocalSystemTime.wDay = CInt(Day(dteTime))

&nbsp;&nbsp;&nbsp;&nbsp;dteLocalSystemTime.wHour = CInt(Hour(dteTime))

&nbsp;&nbsp;&nbsp;&nbsp;dteLocalSystemTime.wMinute = CInt(Minute(dteTime))

&nbsp;&nbsp;&nbsp;&nbsp;dteLocalSystemTime.wSecond = CInt(Second(dteTime))

&nbsp;

&nbsp;&nbsp;&nbsp;&nbsp;Call SystemTimeToFileTime(dteLocalSystemTime, _

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dteLocalFileTime)

&nbsp;&nbsp;&nbsp;&nbsp;Call LocalFileTimeToFileTime(dteLocalFileTime, _

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dteFileTime)

&nbsp;&nbsp;&nbsp;&nbsp;Call FileTimeToSystemTime(dteFileTime, dteSystemTime)

&nbsp;

&nbsp;&nbsp;&nbsp;&nbsp;LocalTimeToUTC = CDate(dteSystemTime.wMonth &amp; "/" &amp; _

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dteSystemTime.wDay &amp; "/" &amp; _

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dteSystemTime.wYear &amp; " " &amp; _

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dteSystemTime.wHour &amp; ":" &amp; _

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dteSystemTime.wMinute &amp; ":" &amp; _

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dteSystemTime.wSecond)

End Function


O&nbsp;Twitter usa o&nbsp;OAuth Autorization&nbsp;para validar todas as solicitações.&nbsp;Um dos parâmetros&nbsp;necessários do&nbsp;OAuth&nbsp;é um timestamp&nbsp;(ou seja, o número de segundos decorridos desde 1 de janeiro de 1970 00:00:00 GMT).&nbsp;A&nbsp;função&nbsp;get_timestamp&nbsp; fornece uma seqüência timestamp no formato exigido.




Public Function get_timestamp() As String

&nbsp;&nbsp;&nbsp;&nbsp;get_timestamp = DateDiff("s", #1/1/1970#, LocalTimeToUTC(Now))

End Function




A&nbsp;função&nbsp;EncodeBase64&nbsp;recebe um array de bytes e converte para uma string codificada em base64.&nbsp;É usado para converter dados binários em uma cadeia de caracteres ASCII.&nbsp;Pensava que esta era uma técnica escorregadia;&nbsp;criar um documento XML (usando o objeto MSXML2.DOMDocument), crie um nó e e atribuia os dados binários para ele.&nbsp;Em seguida, basta ler a propriedade de texto do mesmo nó (MSMXL2.DOMDocument irá lidar com a conversão automaticamente).&nbsp;Graças a&nbsp;Tim Hastings&nbsp;&nbsp;para o código.


Public Function EncodeBase64(ByRef arrData() As Byte) As String

&nbsp;

&nbsp;&nbsp;&nbsp;&nbsp;Dim objXML As MSXML2.DOMDocument

&nbsp;&nbsp;&nbsp;&nbsp;Dim objNode As MSXML2.IXMLDOMElement

&nbsp;

&nbsp;&nbsp;&nbsp;&nbsp;Set objXML = New MSXML2.DOMDocument

&nbsp;

&nbsp;&nbsp;&nbsp;&nbsp;' byte array to base64

&nbsp;&nbsp;&nbsp;&nbsp;Set objNode = objXML.createElement("b64")

&nbsp;&nbsp;&nbsp;&nbsp;objNode.DataType = "bin.base64"

&nbsp;&nbsp;&nbsp;&nbsp;objNode.nodeTypedValue = arrData

&nbsp;&nbsp;&nbsp;&nbsp;EncodeBase64 = objNode.Text

&nbsp;

&nbsp;&nbsp;&nbsp;&nbsp;Set objNode = Nothing

&nbsp;&nbsp;&nbsp;&nbsp;Set objXML = Nothing

&nbsp;

End Function


O&nbsp;Base64_HMACSHA1&nbsp;é uma função que utiliza um par de classes do namespace .Net Sistema de hash uma string em um SHA-1 digere e calcula um código de autenticação HMAC usando uma chave secreta.&nbsp;(você pode usar o método VBA CreateObject para utilizar quaisquer classes .Net que são 'explicitamente expostas como componentes COM') Graças ao código da&nbsp;HK1.


Public Function Base64_HMACSHA1(ByVal sTextToHash As String, ByVal sSharedSecretKey As String) As String

&nbsp;

&nbsp;&nbsp;&nbsp;&nbsp;Dim asc As Object 

&nbsp;&nbsp;&nbsp;&nbsp;Dim enc As Object

&nbsp;&nbsp;&nbsp;&nbsp;Dim TextToHash() As Byte

&nbsp;&nbsp;&nbsp;&nbsp;Dim SharedSecretKey() As Byte

&nbsp;

&nbsp;&nbsp;&nbsp;&nbsp;Set asc = CreateObject("System.Text.UTF8Encoding")

&nbsp;&nbsp;&nbsp;&nbsp;Set enc = CreateObject("System.Security.Cryptography.HMACSHA1")

&nbsp;

&nbsp;&nbsp;&nbsp;&nbsp;TextToHash = asc.Getbytes_4(sTextToHash)

&nbsp;&nbsp;&nbsp;&nbsp;SharedSecretKey = asc.Getbytes_4(sSharedSecretKey)

&nbsp;&nbsp;&nbsp;&nbsp;enc.key = SharedSecretKey

&nbsp;

&nbsp;&nbsp;&nbsp;&nbsp;Dim bytes() As Byte

&nbsp;&nbsp;&nbsp;&nbsp;bytes = enc.ComputeHash_2((TextToHash))

&nbsp;&nbsp;&nbsp;&nbsp;Base64_HMACSHA1 = EncodeBase64(bytes)

&nbsp;&nbsp;&nbsp;&nbsp;Set asc = Nothing

&nbsp;&nbsp;&nbsp;&nbsp;Set enc = Nothing

&nbsp;

End Function


A&nbsp;função&nbsp;binary_file_to_string&nbsp;&nbsp;recebe um arquivo binário (como um arquivo de imagem) e a converte para uma string.&nbsp;Vamos eventualmente usar esta função quando quisermos incluir imagens em nossos tweets.&nbsp;Nada muito complicado aqui; apenas&nbsp;ler um arquivo binário em um array de bytes, em seguida, usaremos a&nbsp;função&nbsp;VBA built-in&nbsp; StrConv para converter a matriz de bytes para uma cadeia Unicode.



Public Function binary_file_to_string(strFileName) As String

&nbsp;

&nbsp;&nbsp;&nbsp;&nbsp;Dim bytArr() As Byte

&nbsp;

&nbsp;&nbsp;&nbsp;&nbsp;Dim strConvData As String

&nbsp;

&nbsp;&nbsp;&nbsp;&nbsp;Dim intFile As Integer

&nbsp;&nbsp;&nbsp;&nbsp;intFile = FreeFile

&nbsp;

&nbsp;&nbsp;&nbsp;&nbsp;Open strFileName For Binary Access Read As intFile

&nbsp;

&nbsp;&nbsp;&nbsp;&nbsp;If LOF(intFile) &gt; 0 Then

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ReDim bytArr(0 To LOF(intFile) - 1) As Byte

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Get intFile, , bytArr

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;strConvData = StrConv(bytArr, vbUnicode)

&nbsp;&nbsp;&nbsp;&nbsp;End If

&nbsp;

&nbsp;&nbsp;&nbsp;&nbsp;Close intFile

&nbsp;

&nbsp;&nbsp;&nbsp;&nbsp;binary_file_to_string = strConvData

&nbsp;

End Function


Mais tarde, em nosso código, precisaremos gerar valores&nbsp;únicos. A&nbsp;função&nbsp;get_GUID fornece uma maneira fácil de gerar tal string (retira caracteres não-alfanumérico, daí a remoção dos hífens do GUID e das chaves exteriores.) Graças ao código do&nbsp;Oorang via vbaexpress.com.





Public Function get_GUID() As String

&nbsp;&nbsp;&nbsp;&nbsp;get_GUID = Replace(Mid$(CreateObject("Scriptlet.TypeLib").Guid, 2, 36), "-", "")

End Function

A função&nbsp;strToByteArray&nbsp;recebe uma string e a converte para um array de bytes utilizando a função StrConv do VBA. Ao incluir uma imagem no tweet, vamos usar esta função para preparar o corpo da solicitação HTTP.





Private Function strToByteArray(sText As String) As Byte()

&nbsp;&nbsp;&nbsp;&nbsp;strToByteArray = StrConv(sText, vbFromUnicode)

End Function



A &nbsp;função&nbsp;UrlEncode&nbsp;converte caracteres não-ASCII em um formato codificado por percentual. Essa função cria um MSScriptControl.ScriptControl objeto e define o idioma para JScript (a implementação MS de JavaScript). Podemos, então, executar funções de JavaScript, especificamente, o built-in&nbsp;da função encodeURIComponent, que irá adequadamente texto UrlEncode passado para ele.





Public Function UrlEncode(str As String)

&nbsp;

&nbsp;&nbsp;&nbsp;&nbsp;Dim objEnc As MSScriptControl.ScriptControl

&nbsp;&nbsp;&nbsp;&nbsp;Set objEnc = New MSScriptControl.ScriptControl

&nbsp;&nbsp;&nbsp;&nbsp;objEnc.Language = "JScript"

&nbsp;

&nbsp;&nbsp;&nbsp;&nbsp;objEnc.AddCode "function encode(str) {return encodeURIComponent(str);}"

&nbsp;&nbsp;&nbsp;&nbsp;Dim encoded As String

&nbsp;

&nbsp;&nbsp;&nbsp;&nbsp;encoded = objEnc.Run("encode", str)

&nbsp;&nbsp;&nbsp;&nbsp;UrlEncode = encoded

&nbsp;

End Function


Funções do Twitter

Com o nosso exército de funções auxiliares prontos para lançar dentro, é hora de twittar!

A fim de postar uma atualização de status (ou seja, tweet), vamos (amplamente) precisa:

Calcular uma assinatura de autenticação especial
Enviar um pedido http adequadamente construído


Parece bastante simples, mas o cálculo da assinatura envolve algumas etapas distintas.&nbsp;Vamos expandir nossa lista de tarefas:

Calcular uma assinatura de autenticação especial
Criar uma cadeia de texto aleatório que é susceptível de ser exclusivo
Calcular um timestamp época
Criar uma cadeia de base com a qual para calcular a nossa assinatura de autenticação
Criar uma chave especial com o qual calcular a nossa assinatura de autenticação
Criar assinatura de autenticação


Enviar um pedido http construída adequadamente


Nós tomaremos cada seção em ordem.



Aguarde os próximos artigos...




Deixe seus comentários, compartilhe este artigo!



brazilsalesforceeffectiveness@gmail.com

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;