{"id":1391,"date":"2011-10-25T18:40:13","date_gmt":"2011-10-26T01:40:13","guid":{"rendered":"http:\/\/www.andreanolanusse.com\/pt\/?p=1391"},"modified":"2013-05-21T20:49:27","modified_gmt":"2013-05-22T03:49:27","slug":"cloudapi-envio-de-arquivos-para-amazon-s3-e-windows-azure-parte-1","status":"publish","type":"post","link":"http:\/\/www.andreanolanusse.com\/pt\/cloudapi-envio-de-arquivos-para-amazon-s3-e-windows-azure-parte-1\/","title":{"rendered":"CloudAPI &#8211; Envio de arquivos para Amazon S3 e Windows Azure &#8211; Parte 1"},"content":{"rendered":"<p>No meu recente artigo <a title=\"Shell Extension para Windows 32-bit e 64-bit com Delphi XE2\" href=\"http:\/\/www.andreanolanusse.com\/pt\/shell-extension-para-windows-32-bit-e-64-bit-com-delphi-xe2\/\">Shell Extension para Windows 32-bit e Windows 64-bit com Delphi XE<\/a>\u00a0expliquei passo a passo como criar extens\u00f5es para o Windows Explorer, possibilitando o envio de arquivo para Amazon S3 e Windows Azure, neste artigo vamos ver como utilizar o Cloud API para enviar os arquivos para Amazon S3 e Windows Azure Cloud com Delphi XE2, caso voc\u00ea n\u00e3o tenha lido o artigo <a title=\"Shell Extension para Windows 32-bit e 64-bit com Delphi XE2\" href=\"http:\/\/www.andreanolanusse.com\/pt\/shell-extension-para-windows-32-bit-e-64-bit-com-delphi-xe2\/\">anterior<\/a>, recomendo ler para melhor compreens\u00e3o deste artigo.<\/p>\n<p>O Cloud API \u00e9 um conjunto de API&#8217;s que permite a intera\u00e7\u00e3o com os servi\u00e7os de tabela, armazenamento e mensagens do Amazon S3 e Windows Azure, est\u00e1 dispon\u00edvel para <a href=\"http:\/\/www.embarcadero.com\/products\/delphi\" target=\"_blank\">Delphi<\/a> e <a href=\"http:\/\/www.embarcadero.com\/products\/cbuilder\" target=\"_blank\">C++Builder<\/a>.<\/p>\n<p>Utilizando o exemplo do artigo anterior como ponto inicial, foi implementado no mesmo um DataModule (CloudDM.pas) que cont\u00e9m a configura\u00e7\u00e3o para acesso as nuvens atrav\u00e9s dos componentes AmazonConnection e AzureConnection, al\u00e9m disso os m\u00e9todos respons\u00e1veis pelo envio de arquivos para as nuvens, assim sendo voc\u00ea precisa ter uma conta no Amazon e no Azure para utilizar este exemplo, a baixo um resumo breve para obter sua conta a qual n\u00e3o \u00e9 gratuita, o custo \u00e9 bem baixo e baseado no quanto voc\u00ea utiliza.<\/p>\n<h3>Criando uma conta Windows Azure Storage<\/h3>\n<p>Atrav\u00e9s do link <a href=\"http:\/\/windows.azure.com\" target=\"_blank\">http:\/\/windows.azure.com<\/a>\u00a0voc\u00ea pode criar sua conta Azure Storage seguindo os passos fornecidos na p\u00e1gina, abaixo um screenshot da minha conta e onde est\u00e3o localizados os dois par\u00e2metros (AccountName e AccountKey) requeridos pelo componente AzureConnection.<\/p>\n<p style=\"text-align: center;\"><a href=\"http:\/\/www.andreanolanusse.com\/pt\/wp-content\/uploads\/2011\/10\/AzureAccount.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-1392\" title=\"Windows Azure Account\" alt=\"\" src=\"http:\/\/www.andreanolanusse.com\/pt\/wp-content\/uploads\/2011\/10\/AzureAccount.png\" width=\"664\" height=\"316\" srcset=\"http:\/\/www.andreanolanusse.com\/pt\/wp-content\/uploads\/2011\/10\/AzureAccount.png 769w, http:\/\/www.andreanolanusse.com\/pt\/wp-content\/uploads\/2011\/10\/AzureAccount-320x151.png 320w\" sizes=\"(max-width: 664px) 100vw, 664px\" \/><\/a><\/p>\n<p>&nbsp;<\/p>\n<h3>Criando uma conta Amazon \u00a0(AWS)<\/h3>\n<p>Criar uma conta no Amazon tamb\u00e9m \u00e9 bem simples, acesse o site <a href=\"https:\/\/console.aws.amazon.com\/s3\/home \" target=\"_blank\">https:\/\/console.aws.amazon.com\/s3\/home <\/a>e siga os passos, para obter o AccountKey e AccountName a ser utilizado no componente AmazonConnection, acesse <a href=\"https:\/\/aws-portal.amazon.com\/gp\/aws\/developer\/account\/index.html?action=access-key\" target=\"_blank\">https:\/\/aws-portal.amazon.com\/gp\/aws\/developer\/account\/index.html?action=access-key<\/a>,\u00a0abaixo um screenshot.<\/p>\n<p style=\"text-align: center;\"><a href=\"http:\/\/www.andreanolanusse.com\/pt\/wp-content\/uploads\/2011\/10\/AmazonAccount.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-1393\" title=\"Amazon Account\" alt=\"\" src=\"http:\/\/www.andreanolanusse.com\/pt\/wp-content\/uploads\/2011\/10\/AmazonAccount.png\" width=\"683\" height=\"413\" srcset=\"http:\/\/www.andreanolanusse.com\/pt\/wp-content\/uploads\/2011\/10\/AmazonAccount.png 975w, http:\/\/www.andreanolanusse.com\/pt\/wp-content\/uploads\/2011\/10\/AmazonAccount-289x175.png 289w, http:\/\/www.andreanolanusse.com\/pt\/wp-content\/uploads\/2011\/10\/AmazonAccount-705x426.png 705w, http:\/\/www.andreanolanusse.com\/pt\/wp-content\/uploads\/2011\/10\/AmazonAccount-450x272.png 450w, http:\/\/www.andreanolanusse.com\/pt\/wp-content\/uploads\/2011\/10\/AmazonAccount-900x544.png 900w\" sizes=\"(max-width: 683px) 100vw, 683px\" \/><\/a><\/p>\n<p>&nbsp;<\/p>\n<h3>Arquivo INI para configura\u00e7\u00e3o da DLL<\/h3>\n<p>As configura\u00e7\u00f5es de acesso as respectivas nuvens est\u00e3o sendo armazenadas no arquivo ini CloudUpload-Extension.ini localizado no diret\u00f3rio Home de cada usu\u00e1rio, eu n\u00e3o vou detalhar como utilizar arquivos ini aqui, voc\u00ea pode estudar esta parte ap\u00f3s baixar os c\u00f3digo fonte do exemplo aqui utilizado.<\/p>\n<p>&nbsp;<\/p>\n<h3>Bucket vs Container e Object vs Blob<\/h3>\n<p>Todo arquivo enviado para as nuvens ser\u00e1 armazenado em uma pasta, Amazon chama pasta de Bucket e Windows Azure de Container, no final das contas Bucket e Container s\u00e3o pastas, cada nuvem tem suas regras e limita\u00e7\u00f5es de como nomear as pastas, por exemplo o nome de uma pastas no Amazon deve ser \u00fanico em toda a nuvem, isso mesmo n\u00e3o \u00fanico na sua conta, ou seja, criar um diret\u00f3rio imagens esquece, algu\u00e9m certamente j\u00e1 criou um.<\/p>\n<p>A diferen\u00e7a de nomenclatura tamb\u00e9m ocorre para arquivos, que na Amazon \u00e9 chamado do Object e no Windows Azure chama-se Blog.<\/p>\n<p>Cloud API respeita essas diferen\u00e7as, assim para criar um Bucket no Amazon usamos o m\u00e9todo CreateBucket, para criar um Container no Windows Azure utilizamos o m\u00e9todo CreateContainer.<\/p>\n<p>&nbsp;<\/p>\n<h3>Envio de arquivos para Windows Azure<\/h3>\n<p>A implementa\u00e7\u00e3o do Shell Extension utiliza o m\u00e9todo UploadtoAzure (CloudDM.pas) para o envio de arquivos para o Windows Azure, antes de enviar o arquivo temos definir em qual pasta (Container) ser\u00e1 armazenado este arquivo.<\/p>\n<p>Como o container pode n\u00e3o existir, ou o usu\u00e1rio pode querer criar um novo, implementei um formul\u00e1rio que permite o usu\u00e1rio selecionar um container j\u00e1 existente ou criar uma nova.<\/p>\n<p>Abaixo parte do c\u00f3digo respons\u00e1vel pelo envio do arquivo, as linhas em destaque refletem o c\u00f3digo que ir\u00e1 listar e criar ou selecionar o container.<\/p>\n<p>Ao fazer uma solicita\u00e7\u00e3o ao Windows Azure atrav\u00e9s do CloudAPI a maioria dos m\u00e9todos retorna um objeto do tipo TCloudResponseInfo, este objeto cont\u00e9m o status do retorno referente a sua solicita\u00e7\u00e3o, todas estas solicita\u00e7\u00f5es s\u00e3o chamadas REST.<\/p>\n<p>Para obter a lista de containers utilizando o m\u00e9todo ListContainers que \u00e9 parte do objeto BlobService instanciando anteriormente, todos os servi\u00e7os relacionados a Blob fazem parte desta classe, assim como a cria\u00e7\u00e3o do container atrav\u00e9s do m\u00e9todo Create Container.<\/p>\n<p>No caso da cria\u00e7\u00e3o do container, podemos passar informa\u00e7\u00f5es adicionais a qual chamamos de metadata, no exemplo abaixo passamos o nome do computador utilizado para solicitar a cria\u00e7\u00e3o deste container, esta informa\u00e7\u00e3o estar\u00e1 dispon\u00edvel como parte do metadata deste container, voc\u00ea pode definir v\u00e1rias outras informa\u00e7\u00f5es e adiciona-las como parte do seu metadata que \u00e9 do tipo TStringList;<\/p>\n<pre class=\"brush: delphi\">function TCloud.UploadtoAzure(FileName: String): TCloudResponseInfo;\r\nvar\r\n  BlobService: TAzureBlobService;\r\n  SList, Metadata: TStrings;\r\n  ContainerList: TList;\r\n  ContainerObj: TAzureContainer;\r\n  Content: TBytes;\r\n  BlobName, ContainerName: String;\r\n  ResponseList: TCloudResponseInfo;\r\n  FrmList: TFrmContainerList;\r\n  Act: TContainerAction;\r\nbegin\r\n\r\n  Result := TCloudResponseInfo.Create;\r\n\r\n  if (FileName = EmptyStr) then\r\n    Exit;\r\n\r\n  BlobService := TAzureBlobService.Create(AzureConnection);\r\n  try\r\n    ResponseList := TCloudResponseInfo.Create;\r\n    ContainerList := BlobService.ListContainers(nil, ResponseList);\r\n    Metadata := TStringList.Create;\r\n\r\n    if ResponseList.StatusCode = 200 then\r\n    begin\r\n\r\n      SList := TStringList.Create;\r\n      for ContainerObj in ContainerList do\r\n        SList.Add(ContainerObj.Name);\r\n      ContainerList.Free;\r\n\r\n      FrmList := TFrmContainerList.Create(nil, SList, TClouds[AzureIndex]);\r\n      try\r\n        FrmList.ShowModal;\r\n        Act := FrmList.Action;\r\n\r\n        case Act of\r\n          caCreate:\r\n            begin\r\n              Metadata.Values[SMDCreateby] := GetComputerandUserName;\r\n\r\n              if BlobService.CreateContainer(FrmList.Container, Metadata,\r\n                bpaBlob, Result) then\r\n                ContainerName := FrmList.Container;\r\n            end;\r\n          caUpload:\r\n            begin\r\n              ContainerName := FrmList.Container;\r\n            end;\r\n        end;\r\n      finally\r\n        SList.Free;\r\n        FrmList.Free;\r\n      end;\r\n\r\n      if Act = TContainerAction.caNone then\r\n        Exit;\r\n\r\n    end;<\/pre>\n<p>&nbsp;<\/p>\n<p>Com a defini\u00e7\u00e3o do container podemos seguir para o pr\u00f3ximo passo que \u00e9 o envio do arquivo.<\/p>\n<p>Para o envio do arquivo utilizamos o m\u00e9todo BlobService.PutBlockBlob que cont\u00e9m diversos par\u00e2metros como: nome e o conte\u00fado do arquivo em TBytes, metadata e alguns outros que n\u00e3o s\u00e3o necess\u00e1rios para este exemplo.<\/p>\n<p>Assim como para containers podemos adicionar metadata ao arquivo, neste exemplo adiciono o nome do computador\\usu\u00e1rio e a localiza\u00e7\u00e3o original do arquivo a ser enviado.<\/p>\n<pre class=\"brush: delphi\">    Metadata.Clear;\r\n    Metadata.Values[SMDPath] := ExtractFilePath(FileName);\r\n    Metadata.Values[SMDFrom] := GetComputerandUserName;\r\n\r\n    Content := ContentOf(FileName);\r\n    BlobName := ExtractFileName(FileName);<\/pre>\n<p>O m\u00e9todo ContentOf retorna o conte\u00fado do arquivo em TBytes.<\/p>\n<pre class=\"brush: delphi\">function TCloud.ContentOf(const FileName: String;\r\n  RequiredSizeMod: Integer): TBytes;\r\nvar\r\n  fs: TFileStream;\r\nbegin\r\n  if FileName &lt;&gt; EmptyStr then\r\n  begin\r\n    fs := TFileStream.Create(FileName, fmOpenRead);\r\n    try\r\n      if RequiredSizeMod &lt; 1 then\r\n        SetLength(Result, fs.Size)\r\n      else\r\n        SetLength(Result, ((fs.Size div RequiredSizeMod) + 1) *\r\n          RequiredSizeMod);\r\n      fs.ReadBuffer(Result[0], fs.Size);\r\n    finally\r\n      fs.Free;\r\n    end;\r\n  end\r\n  else\r\n    SetLength(Result, 0);\r\n\r\nend;<\/pre>\n<p>O resultado do envio ser\u00e1 um par\u00e2metro de sa\u00edda do tipo TCloudResponseInfo, este cont\u00e9m a propriedade StatusCode, requisi\u00e7\u00f5es realizadas com sucesso retornam o c\u00f3digo 200 ou 201.<\/p>\n<pre class=\"brush: delphi\">    BlobService.PutBlockBlob(ContainerName, BlobName, Content, '', nil,\r\n      Metadata, Result);\r\n    ShowResponseInfo(TClouds[AzureIndex], Result);<\/pre>\n<p>Abaixo a implementa\u00e7\u00e3o completa da unit CloudDM.pas.<\/p>\n<pre class=\"brush: delphi\">unit CloudDM;\r\n\r\ninterface\r\n\r\nuses\r\n  System.SysUtils, System.Classes, Data.Cloud.AzureAPI, Data.Cloud.CloudAPI,\r\n  Data.Cloud.AmazonAPI, Winapi.Windows, IniFiles, IOUtils,\r\n  System.Generics.Collections;\r\n\r\ntype\r\n  TCloud = class(TDataModule)\r\n    AzureConnection: TAzureConnectionInfo;\r\n    AmazonConnection: TAmazonConnectionInfo;\r\n  private\r\n    { Private declarations }\r\n    FHandle: HWND;\r\n    function GetComputerandUserName: String;\r\n    function UploadtoAmazon(FileName: String): TCloudResponseInfo;\r\n    function UploadtoAzure(FileName: String): TCloudResponseInfo;\r\n    function ContentOf(const FileName: String;\r\n      RequiredSizeMod: Integer = 0): TBytes;\r\n    procedure ShowResponseInfo(Title: String; Response: TCloudResponseInfo);\r\n  public\r\n    { Public declarations }\r\n\r\n    function LoadConfiguration: Boolean;\r\n    function Upload(FileName: String; Cloud: Integer): TCloudResponseInfo;\r\n\r\n    class procedure SaveLog(s: String);\r\n    constructor Create(AOWner: TComponent; Handle: HWND); reintroduce; overload;\r\n  end;\r\n\r\nvar\r\n  Cloud: TCloud;\r\n\r\nConst\r\n  AmazonIndex = 0;\r\n  AzureIndex = 1;\r\n  TClouds: Array [0 .. 1] of PWideChar = ('Amazon S3', 'Microsoft Azure');\r\n\r\nimplementation\r\n\r\nuses CloudContainerList;\r\n\r\nConst\r\n  SMyAzureKey = 'MyAzureKey'; \/\/ do not translate\r\n  SMyAmazonKey = 'MyAmazonKey'; \/\/ do not translate\r\n  SInternetConfig = 'Internet Access Configuration'; \/\/ do not translate\r\n\r\n  SAccountName = 'AccountName'; \/\/ do not translate\r\n  SAccountKey = 'AccountKey'; \/\/ do not translate\r\n  SProxyHost = 'ProxyHost'; \/\/ do not translate\r\n  SProxyPort = 'ProxyPort'; \/\/ do not translate\r\n\r\n  SStorageEndpoint = 'StorageBlobEndpoint'; \/\/ do not translate\r\n\r\n  SMDPath = 'originalfilepath';\r\n  SMDFrom = 'uploadfrom';\r\n  SMDCreateby = 'createdby';\r\n\r\n{$R *.dfm}\r\n  { TCloudContainer }\r\n\r\nfunction TCloud.ContentOf(const FileName: String;\r\n  RequiredSizeMod: Integer): TBytes;\r\nvar\r\n  fs: TFileStream;\r\nbegin\r\n  if FileName &lt;&gt; EmptyStr then\r\n  begin\r\n    fs := TFileStream.Create(FileName, fmOpenRead);\r\n    try\r\n      if RequiredSizeMod &lt; 1 then\r\n        SetLength(Result, fs.Size)\r\n      else\r\n        SetLength(Result, ((fs.Size div RequiredSizeMod) + 1) *\r\n          RequiredSizeMod);\r\n      fs.ReadBuffer(Result[0], fs.Size);\r\n    finally\r\n      fs.Free;\r\n    end;\r\n  end\r\n  else\r\n    SetLength(Result, 0);\r\n\r\nend;\r\n\r\nconstructor TCloud.Create(AOWner: TComponent; Handle: HWND);\r\nbegin\r\n  inherited Create(AOWner);\r\n  FHandle := Handle\r\n\r\nend;\r\n\r\nfunction TCloud.GetComputerandUserName: String;\r\nvar\r\n  cName, uName: array [0 .. 255] of char;\r\n  c: DWORD;\r\nbegin\r\n  c := SizeOf(cName);\r\n\r\n  GetComputerName(cName, c);\r\n  GetUserName(uName, c);\r\n\r\n  Result := StrPas(cName) + '\\' + StrPas(uName);\r\nend;\r\n\r\nfunction TCloud.LoadConfiguration: Boolean;\r\nvar\r\n  IniFile: string;\r\n  Ini: TIniFile;\r\n  Port: Integer;\r\n  SUrl: String;\r\nbegin\r\n\r\n  IniFile := GetHomePath + '\\CloudUpload-Extension.ini';\r\n  Ini := TIniFile.Create(IniFile);\r\n\r\n  try\r\n    \/\/ The ini file will be created in case it doesn't exist\r\n    if not FileExists(IniFile) then\r\n    begin\r\n      \/\/ Azure parameters\r\n      Ini.WriteString(SMyAzureKey, SAccountName, EmptyStr);\r\n      Ini.WriteString(SMyAzureKey, SAccountKey, EmptyStr);\r\n      Ini.WriteString(SMyAzureKey, SStorageEndpoint, EmptyStr);\r\n\r\n      \/\/ Amazon parameters\r\n      Ini.WriteString(SMyAmazonKey, SAccountName, EmptyStr);\r\n      Ini.WriteString(SMyAmazonKey, SAccountKey, EmptyStr);\r\n      Ini.WriteString(SMyAmazonKey, SStorageEndpoint, EmptyStr);\r\n\r\n      \/\/ Internet access configuration\r\n      Ini.WriteString(SInternetConfig, SProxyHost, EmptyStr);\r\n      Ini.WriteString(SInternetConfig, SProxyPort, EmptyStr);\r\n\r\n      Ini.UpdateFile;\r\n      Result := False;\r\n    end\r\n    else\r\n    begin\r\n\r\n      TryStrToInt(Ini.ReadString(SInternetConfig, SProxyPort, '0'), Port);\r\n\r\n      with AzureConnection do\r\n      begin\r\n        AccountName := Ini.ReadString(SMyAzureKey, SAccountName, EmptyStr);\r\n        AccountKey := Ini.ReadString(SMyAzureKey, SAccountKey, EmptyStr);\r\n\r\n        RequestProxyHost := Ini.ReadString(SInternetConfig, SProxyHost,\r\n          EmptyStr);\r\n        RequestProxyPort := Port;\r\n\r\n        SUrl := Ini.ReadString(SMyAzureKey, SStorageEndpoint, EmptyStr);\r\n\r\n        UseDefaultEndpoints := SUrl = EmptyStr;\r\n        BlobEndpoint := SUrl;\r\n      end;\r\n\r\n      with AmazonConnection do\r\n      begin\r\n        AccountName := Ini.ReadString(SMyAmazonKey, SAccountName, EmptyStr);\r\n        AccountKey := Ini.ReadString(SMyAmazonKey, SAccountKey, EmptyStr);\r\n\r\n        RequestProxyHost := Ini.ReadString(SInternetConfig, SProxyHost,\r\n          EmptyStr);\r\n        RequestProxyPort := Port;\r\n\r\n        SUrl := Ini.ReadString(SMyAmazonKey, SStorageEndpoint, EmptyStr);\r\n\r\n        UseDefaultEndpoints := SUrl = EmptyStr;\r\n        StorageEndpoint := SUrl;\r\n      end;\r\n      Result := True;\r\n    end;\r\n\r\n  finally\r\n    Ini.Free;\r\n  end;\r\nend;\r\n\r\nclass procedure TCloud.SaveLog(s: String);\r\nvar\r\n  LogFile: TextFile;\r\nbegin\r\n  { open the log file }\r\n  AssignFile(LogFile, 'c:\\Shell.txt');\r\n  if FileExists('c:\\Shell.txt') then\r\n    Append(LogFile)\r\n  else\r\n    Rewrite(LogFile);\r\n\r\n  WriteLn(LogFile, s + #13#10);\r\n\r\n  { write and close the logfile }\r\n  CloseFile(LogFile);\r\nend;\r\n\r\nprocedure TCloud.ShowResponseInfo(Title: String; Response: TCloudResponseInfo);\r\nbegin\r\n  case Response.StatusCode of\r\n    200, 201:\r\n      MessageBox(FHandle, 'File Uploaded', PWideChar(Title), MB_OK);\r\n  else\r\n    MessageBox(FHandle, PWideChar('Error ' + Response.StatusMessage),\r\n      PWideChar(Title), MB_ICONWARNING);\r\n  end;\r\nend;\r\n\r\nfunction TCloud.Upload(FileName: String; Cloud: Integer): TCloudResponseInfo;\r\nbegin\r\n  case Cloud of\r\n    AmazonIndex:\r\n      Result := UploadtoAmazon(FileName);\r\n    AzureIndex:\r\n      Result := UploadtoAzure(FileName);\r\n  else\r\n    Result := TCloudResponseInfo.Create;\r\n  end;\r\nend;\r\n\r\nfunction TCloud.UploadtoAmazon(FileName: String): TCloudResponseInfo;\r\nvar\r\n  StorageService: TAmazonStorageService;\r\n  BucketList, Metadata: TStrings;\r\n  Content: TBytes;\r\n  ResponseList: TCloudResponseInfo;\r\n  FrmList: TFrmContainerList;\r\n  Act: TContainerAction;\r\n  BucketName: String;\r\n  I: Integer;\r\nbegin\r\n  Result := TCloudResponseInfo.Create;\r\n\r\n  if (FileName = EmptyStr) then\r\n    Exit;\r\n\r\n  StorageService := TAmazonStorageService.Create(AmazonConnection);\r\n\r\n{$REGION 'Define the Bucket'}\r\n  ResponseList := TCloudResponseInfo.Create;\r\n  BucketList := StorageService.ListBuckets(ResponseList);\r\n\r\n  if ResponseList.StatusCode = 200 then\r\n  begin\r\n\r\n    \/\/ Amazon return date\/time information for each Bucket\r\n    \/\/ this for is required to remove that information\r\n    for I := 0 to BucketList.Count - 1 do\r\n      BucketList[I] := BucketList.Names[I];\r\n\r\n    FrmList := TFrmContainerList.Create(nil, BucketList, TClouds[AmazonIndex]);\r\n    try\r\n      FrmList.ShowModal;\r\n      Act := FrmList.Action;\r\n\r\n      case Act of\r\n        caCreate:\r\n          begin\r\n            if StorageService.CreateBucket(FrmList.Container, amzbaNotSpecified,\r\n              amzrNotSpecified, Result) then\r\n              BucketName := FrmList.Container;\r\n          end;\r\n        caUpload:\r\n          begin\r\n            BucketName := FrmList.Container;\r\n          end;\r\n      end;\r\n    finally\r\n      FrmList.Free;\r\n    end;\r\n\r\n    if Act = TContainerAction.caNone then\r\n      Exit;\r\n\r\n  end;\r\n{$ENDREGION}\r\n  try\r\n\r\n    Metadata := TStringList.Create;\r\n    Metadata.Values[SMDPath] := ExtractFilePath(FileName);\r\n    Metadata.Values[SMDFrom] := GetComputerandUserName;\r\n\r\n    Content := ContentOf(FileName);\r\n\r\n    FileName := StringReplace(FileName, ' ', '%20', [rfReplaceAll, rfIgnoreCase]);\r\n\r\n    StorageService.UploadObject(BucketName, ExtractFileName(FileName), Content,\r\n      False, Metadata, nil, amzbaPublicRead, Result);\r\n    ShowResponseInfo(TClouds[AmazonIndex], Result);\r\n\r\n  except\r\n    on E: Exception do\r\n    begin\r\n      MessageBox(FHandle, PWideChar('Error ' + E.Message),\r\n        TClouds[AmazonIndex], MB_OK);\r\n    end;\r\n  end;\r\n\r\n  FreeAndNil(Metadata);\r\n  FreeAndNil(StorageService);\r\nend;\r\n\r\nfunction TCloud.UploadtoAzure(FileName: String): TCloudResponseInfo;\r\nvar\r\n  BlobService: TAzureBlobService;\r\n  SList, Metadata: TStrings;\r\n  ContainerList: TList;\r\n  ContainerObj: TAzureContainer;\r\n  Content: TBytes;\r\n  BlobName, ContainerName: String;\r\n  ResponseList: TCloudResponseInfo;\r\n  FrmList: TFrmContainerList;\r\n  Act: TContainerAction;\r\nbegin\r\n\r\n  Result := TCloudResponseInfo.Create;\r\n\r\n  if (FileName = EmptyStr) then\r\n    Exit;\r\n\r\n  BlobService := TAzureBlobService.Create(AzureConnection);\r\n  try\r\n\r\n{$REGION 'Define the container'}\r\n    ResponseList := TCloudResponseInfo.Create;\r\n    ContainerList := BlobService.ListContainers(nil, ResponseList);\r\n    Metadata := TStringList.Create;\r\n\r\n    if ResponseList.StatusCode = 200 then\r\n    begin\r\n\r\n      SList := TStringList.Create;\r\n      for ContainerObj in ContainerList do\r\n        SList.Add(ContainerObj.Name);\r\n      ContainerList.Free;\r\n\r\n      FrmList := TFrmContainerList.Create(nil, SList, TClouds[AzureIndex]);\r\n      try\r\n        FrmList.ShowModal;\r\n        Act := FrmList.Action;\r\n\r\n        case Act of\r\n          caCreate:\r\n            begin\r\n              Metadata.Values[SMDCreateby] := GetComputerandUserName;\r\n\r\n              if BlobService.CreateContainer(FrmList.Container, Metadata,\r\n                bpaBlob, Result) then\r\n                ContainerName := FrmList.Container;\r\n            end;\r\n          caUpload:\r\n            begin\r\n              ContainerName := FrmList.Container;\r\n            end;\r\n        end;\r\n      finally\r\n        SList.Free;\r\n        FrmList.Free;\r\n      end;\r\n\r\n      if Act = TContainerAction.caNone then\r\n        Exit;\r\n\r\n    end;\r\n{$ENDREGION}\r\n\r\n    Metadata.Clear;\r\n    Metadata.Values[SMDPath] := ExtractFilePath(FileName);\r\n    Metadata.Values[SMDFrom] := GetComputerandUserName;\r\n\r\n    Content := ContentOf(FileName);\r\n    BlobName := ExtractFileName(FileName);\r\n\r\n    BlobService.PutBlockBlob(ContainerName, BlobName, Content, '', nil,\r\n      Metadata, Result);\r\n    ShowResponseInfo(TClouds[AzureIndex], Result);\r\n\r\n  except\r\n    on E: Exception do\r\n    begin\r\n      MessageBox(FHandle, PWideChar('Error ' + E.Message),\r\n        TClouds[AzureIndex], MB_OK);\r\n    end;\r\n  end;\r\n\r\n  FreeAndNil(ResponseList);\r\n  FreeAndNil(Metadata);\r\n  FreeAndNil(BlobService);\r\n\r\nend;\r\n\r\nend.<\/pre>\n<p>O c\u00f3digo fonte completo est\u00e1 dispon\u00edvel no reposit\u00f3rio do RAD Studio XE2 no sourceforge, no <a href=\"http:\/\/www.andreanolanusse.com\/pt\/shell-extension-para-windows-32-bit-e-64-bit-com-delphi-xe2\/\">artigo anterior<\/a> voc\u00ea pode obter as informa\u00e7\u00f5es de como obter os fontes.<br \/>\nAt\u00e9 o pr\u00f3ximo artigo que ir\u00e1 abordar o envio de arquivos para Amazon S3.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>No meu recente artigo Shell Extension para Windows 32-bit e Windows 64-bit com Delphi XE\u00a0expliquei passo a passo como criar extens\u00f5es para o Windows Explorer, possibilitando o envio de arquivo para Amazon S3 e Windows Azure, neste artigo vamos ver como utilizar o Cloud API para enviar os arquivos para Amazon S3 e Windows Azure [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":1393,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"_s2mail":"yes","footnotes":""},"categories":[102],"tags":[63,181],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v16.2 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>CloudAPI - Envio de arquivos para Amazon S3 e Windows Azure - Parte 1 | Andreano Lanusse | Tecnologia e Desenvolvimento de Software<\/title>\n<meta name=\"description\" content=\"No meu recente artigo Shell Extension para Windows 32-bit e Windows 64-bit com Delphi XE\u00a0expliquei passo a passo como criar extens\u00f5es para o Windows\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"http:\/\/www.andreanolanusse.com\/pt\/cloudapi-envio-de-arquivos-para-amazon-s3-e-windows-azure-parte-1\/\" \/>\n<meta property=\"og:locale\" content=\"pt_BR\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"CloudAPI - Envio de arquivos para Amazon S3 e Windows Azure - Parte 1 | Andreano Lanusse | Tecnologia e Desenvolvimento de Software\" \/>\n<meta property=\"og:description\" content=\"No meu recente artigo Shell Extension para Windows 32-bit e Windows 64-bit com Delphi XE\u00a0expliquei passo a passo como criar extens\u00f5es para o Windows\" \/>\n<meta property=\"og:url\" content=\"http:\/\/www.andreanolanusse.com\/pt\/cloudapi-envio-de-arquivos-para-amazon-s3-e-windows-azure-parte-1\/\" \/>\n<meta property=\"og:site_name\" content=\"Andreano Lanusse | Tecnologia e Desenvolvimento de Software\" \/>\n<meta property=\"article:published_time\" content=\"2011-10-26T01:40:13+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2013-05-22T03:49:27+00:00\" \/>\n<meta property=\"og:image\" content=\"http:\/\/www.andreanolanusse.com\/pt\/wp-content\/uploads\/2011\/10\/AmazonAccount.png\" \/>\n\t<meta property=\"og:image:width\" content=\"975\" \/>\n\t<meta property=\"og:image:height\" content=\"590\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@andreanolanusse\" \/>\n<meta name=\"twitter:site\" content=\"@andreanolanusse\" \/>\n<meta name=\"twitter:label1\" content=\"Est. tempo de leitura\">\n\t<meta name=\"twitter:data1\" content=\"10 minutos\">\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebSite\",\"@id\":\"http:\/\/www.andreanolanusse.com\/pt\/#website\",\"url\":\"http:\/\/www.andreanolanusse.com\/pt\/\",\"name\":\"Andreano Lanusse | Tecnologia e Desenvolvimento de Software\",\"description\":\"Andreano Lanusse blog - artigos, tutoriais e v&iacute;deos sobre tecnologia, desenvolvimento de software (Delphi XE4, C#, PHP, .NET) e t&eacute;cnicas de programa&ccedil;&atilde;o\",\"publisher\":{\"@id\":\"http:\/\/www.andreanolanusse.com\/pt\/#\/schema\/person\/620bd05e81598c3aba4781796cbe8903\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":\"http:\/\/www.andreanolanusse.com\/pt\/?s={search_term_string}\",\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"pt-BR\"},{\"@type\":\"ImageObject\",\"@id\":\"http:\/\/www.andreanolanusse.com\/pt\/cloudapi-envio-de-arquivos-para-amazon-s3-e-windows-azure-parte-1\/#primaryimage\",\"inLanguage\":\"pt-BR\",\"url\":\"http:\/\/www.andreanolanusse.com\/pt\/wp-content\/uploads\/2011\/10\/AmazonAccount.png\",\"contentUrl\":\"http:\/\/www.andreanolanusse.com\/pt\/wp-content\/uploads\/2011\/10\/AmazonAccount.png\",\"width\":975,\"height\":590},{\"@type\":\"WebPage\",\"@id\":\"http:\/\/www.andreanolanusse.com\/pt\/cloudapi-envio-de-arquivos-para-amazon-s3-e-windows-azure-parte-1\/#webpage\",\"url\":\"http:\/\/www.andreanolanusse.com\/pt\/cloudapi-envio-de-arquivos-para-amazon-s3-e-windows-azure-parte-1\/\",\"name\":\"CloudAPI - Envio de arquivos para Amazon S3 e Windows Azure - Parte 1 | Andreano Lanusse | Tecnologia e Desenvolvimento de Software\",\"isPartOf\":{\"@id\":\"http:\/\/www.andreanolanusse.com\/pt\/#website\"},\"primaryImageOfPage\":{\"@id\":\"http:\/\/www.andreanolanusse.com\/pt\/cloudapi-envio-de-arquivos-para-amazon-s3-e-windows-azure-parte-1\/#primaryimage\"},\"datePublished\":\"2011-10-26T01:40:13+00:00\",\"dateModified\":\"2013-05-22T03:49:27+00:00\",\"description\":\"No meu recente artigo Shell Extension para Windows 32-bit e Windows 64-bit com Delphi XE\\u00a0expliquei passo a passo como criar extens\\u00f5es para o Windows\",\"breadcrumb\":{\"@id\":\"http:\/\/www.andreanolanusse.com\/pt\/cloudapi-envio-de-arquivos-para-amazon-s3-e-windows-azure-parte-1\/#breadcrumb\"},\"inLanguage\":\"pt-BR\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"http:\/\/www.andreanolanusse.com\/pt\/cloudapi-envio-de-arquivos-para-amazon-s3-e-windows-azure-parte-1\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"http:\/\/www.andreanolanusse.com\/pt\/cloudapi-envio-de-arquivos-para-amazon-s3-e-windows-azure-parte-1\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"item\":{\"@type\":\"WebPage\",\"@id\":\"http:\/\/www.andreanolanusse.com\/pt\/\",\"url\":\"http:\/\/www.andreanolanusse.com\/pt\/\",\"name\":\"In\\u00edcio\"}},{\"@type\":\"ListItem\",\"position\":2,\"item\":{\"@id\":\"http:\/\/www.andreanolanusse.com\/pt\/cloudapi-envio-de-arquivos-para-amazon-s3-e-windows-azure-parte-1\/#webpage\"}}]},{\"@type\":\"Article\",\"@id\":\"http:\/\/www.andreanolanusse.com\/pt\/cloudapi-envio-de-arquivos-para-amazon-s3-e-windows-azure-parte-1\/#article\",\"isPartOf\":{\"@id\":\"http:\/\/www.andreanolanusse.com\/pt\/cloudapi-envio-de-arquivos-para-amazon-s3-e-windows-azure-parte-1\/#webpage\"},\"author\":{\"@id\":\"http:\/\/www.andreanolanusse.com\/pt\/#\/schema\/person\/620bd05e81598c3aba4781796cbe8903\"},\"headline\":\"CloudAPI &#8211; Envio de arquivos para Amazon S3 e Windows Azure &#8211; Parte 1\",\"datePublished\":\"2011-10-26T01:40:13+00:00\",\"dateModified\":\"2013-05-22T03:49:27+00:00\",\"mainEntityOfPage\":{\"@id\":\"http:\/\/www.andreanolanusse.com\/pt\/cloudapi-envio-de-arquivos-para-amazon-s3-e-windows-azure-parte-1\/#webpage\"},\"commentCount\":2,\"publisher\":{\"@id\":\"http:\/\/www.andreanolanusse.com\/pt\/#\/schema\/person\/620bd05e81598c3aba4781796cbe8903\"},\"image\":{\"@id\":\"http:\/\/www.andreanolanusse.com\/pt\/cloudapi-envio-de-arquivos-para-amazon-s3-e-windows-azure-parte-1\/#primaryimage\"},\"keywords\":[\"Cloud\",\"Delphi\"],\"articleSection\":[\"Delphi\"],\"inLanguage\":\"pt-BR\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"http:\/\/www.andreanolanusse.com\/pt\/cloudapi-envio-de-arquivos-para-amazon-s3-e-windows-azure-parte-1\/#respond\"]}]},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"http:\/\/www.andreanolanusse.com\/pt\/#\/schema\/person\/620bd05e81598c3aba4781796cbe8903\",\"name\":\"Andreano Lanusse\",\"image\":{\"@type\":\"ImageObject\",\"@id\":\"http:\/\/www.andreanolanusse.com\/pt\/#personlogo\",\"inLanguage\":\"pt-BR\",\"url\":\"http:\/\/0.gravatar.com\/avatar\/6a9c6f73c7c480fb826c7303288abfd3?s=96&d=mm&r=g\",\"contentUrl\":\"http:\/\/0.gravatar.com\/avatar\/6a9c6f73c7c480fb826c7303288abfd3?s=96&d=mm&r=g\",\"caption\":\"Andreano Lanusse\"},\"logo\":{\"@id\":\"http:\/\/www.andreanolanusse.com\/pt\/#personlogo\"},\"sameAs\":[\"https:\/\/twitter.com\/andreanolanusse\"]}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","_links":{"self":[{"href":"http:\/\/www.andreanolanusse.com\/pt\/wp-json\/wp\/v2\/posts\/1391"}],"collection":[{"href":"http:\/\/www.andreanolanusse.com\/pt\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.andreanolanusse.com\/pt\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.andreanolanusse.com\/pt\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.andreanolanusse.com\/pt\/wp-json\/wp\/v2\/comments?post=1391"}],"version-history":[{"count":0,"href":"http:\/\/www.andreanolanusse.com\/pt\/wp-json\/wp\/v2\/posts\/1391\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"http:\/\/www.andreanolanusse.com\/pt\/wp-json\/wp\/v2\/media\/1393"}],"wp:attachment":[{"href":"http:\/\/www.andreanolanusse.com\/pt\/wp-json\/wp\/v2\/media?parent=1391"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.andreanolanusse.com\/pt\/wp-json\/wp\/v2\/categories?post=1391"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.andreanolanusse.com\/pt\/wp-json\/wp\/v2\/tags?post=1391"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}