Dán dữ liệu hình từ Clipboard vào Outlook bằng cách nào?

Liên hệ QC

Quang_Hải

Thành viên gạo cội
Tham gia
21/2/09
Bài viết
6,069
Được thích
7,992
Nghề nghiệp
Làm đủ thứ
Khi ta dùng lệnh Range(gi do).CopyPicture thì ta có 1 dữ liệu dạng picture trong ClipBoard. Khi ta mở OutLook và ấn phím Ctrl + V thì dán cái ảnh đó vào MailBody của OutLook.
Vậy có cách nào để thực hiện điều này bằng VBA hay không?
Mình dùng lệnh .GetText(1) thì chỉ cho ra Text mà thôi

Mình chỉ muốn xét trường hợp của Clipboard thôi không dùng cách khác. Vì viết hàm để lấy 1 range cho vào mailbody với đầy đủ định dạng thì mình biết cách viết code.

Mong các anh chị gợi ý.
 
Khi ta dùng lệnh Range(gi do).CopyPicture thì ta có 1 dữ liệu dạng picture trong ClipBoard. Khi ta mở OutLook và ấn phím Ctrl + V thì dán cái ảnh đó vào MailBody của OutLook.
Vậy có cách nào để thực hiện điều này bằng VBA hay không?
Mình dùng lệnh .GetText(1) thì chỉ cho ra Text mà thôi

Mình chỉ muốn xét trường hợp của Clipboard thôi không dùng cách khác. Vì viết hàm để lấy 1 range cho vào mailbody với đầy đủ định dạng thì mình biết cách viết code.

Mong các anh chị gợi ý.

Vậy sau khi CopyPicture, tại sao ta không lưu thành file trên đĩa rồi load vào Outlook có phải khỏe hơn không?
Việc copy và Save picture đương nhiên sẽ dùng VBA. Hải nghĩ sao?
 
Upvote 0
Vậy sau khi CopyPicture, tại sao ta không lưu thành file trên đĩa rồi load vào Outlook có phải khỏe hơn không?
Việc copy và Save picture đương nhiên sẽ dùng VBA. Hải nghĩ sao?
Cái vấn đề làm em tức tưởi là tại sao dùng Ctrl +V thì dán được, nhưng không thể code theo cách này nên em bực bội. Nếu tạo thành file ảnh lưu vào đĩa rồi dán ra mailbody rồi kill cái file ảnh tạm đó thì em biết vì đã vọc code của các anh rồi.
 
Upvote 0
Nếu tạo thành file ảnh lưu vào đĩa rồi dán ra mailbody rồi kill cái file ảnh tạm đó thì em biết vì đã vọc code của các anh rồi.

Không biết Hải đang nói đến code nào? Vì nếu đúng là cái này:
Mã:
Function PictureFromObject(ByVal Target As Object, Optional ByVal bType As Boolean = True) As IPictureDisp
  Dim hPtr As Long, hCopy As Long, PicType As Long
  Const CF_BITMAP = 2
  Const CF_PALETTE = 9
  Const CF_ENHMETAFILE = 14
  Const IMAGE_BITMAP = 0
  Const LR_COPYRETURNORG = &H4
  Const PicType_BITMAP = 1
  Const PicType_ENHMETAFILE = 4
  [COLOR=#ff0000]Target.CopyPicture , IIf(bType, xlBitmap, xlPicture)[/COLOR]
  ...................
  .................
End Function
thì xem như Hải đã làm trước đoạn màu đỏ rồi (CopyPicture). Phần còn lại là lấy nó ra từ trong clipboard chính là những đoạn code bên dưới đoạn màu đỏ ấy thôi (kết quả trả về là IPictureDisp, muốn làm gì tiếp tùy ý)
(tiếc là máy tôi không cài Outlook nên không thể thí nghiệm được)
 
Upvote 0
Không biết Hải đang nói đến code nào? Vì nếu đúng là cái này:
Mã:
Function PictureFromObject(ByVal Target As Object, Optional ByVal bType As Boolean = True) As IPictureDisp
  Dim hPtr As Long, hCopy As Long, PicType As Long
  Const CF_BITMAP = 2
  Const CF_PALETTE = 9
  Const CF_ENHMETAFILE = 14
  Const IMAGE_BITMAP = 0
  Const LR_COPYRETURNORG = &H4
  Const PicType_BITMAP = 1
  Const PicType_ENHMETAFILE = 4
  [COLOR=#ff0000]Target.CopyPicture , IIf(bType, xlBitmap, xlPicture)[/COLOR]
  ...................
  .................
End Function
thì xem như Hải đã làm trước đoạn màu đỏ rồi (CopyPicture). Phần còn lại là lấy nó ra từ trong clipboard chính là những đoạn code bên dưới đoạn màu đỏ ấy thôi (kết quả trả về là IPictureDisp, muốn làm gì tiếp tùy ý)
(tiếc là máy tôi không cài Outlook nên không thể thí nghiệm được)
Để em tranh thủ cày xem ra cái gì rồi la lên cho cách anh tiếp sức.
 
Upvote 0
Cái vấn đề làm em tức tưởi là tại sao dùng Ctrl +V thì dán được, nhưng không thể code theo cách này nên em bực bội. Nếu tạo thành file ảnh lưu vào đĩa rồi dán ra mailbody rồi kill cái file ảnh tạm đó thì em biết vì đã vọc code của các anh rồi.

Nếu tôi hiểu được ý bạn (không ghi gì ra đĩa và đọc vào từ đĩa) thì ta dùng cơ cấu Automation.

Để chắc tôi hỏi thêm: code đặt ở Excel?

Cái ta cần là có được đối tượng gốc của WORD, OutLook là Application. Lúc đó có thể truy cập (có được) mọi đối tượng con, cháu, chắt, chít và read / write thuộc tính hay gọi các phương thức của chúng.

Ví dụ bạn đã có WORD, Outlook đang mở. Nếu chưa mở thì thay GetObject bằng CreateObject.

Mã:
Sub ExcelRangeToWordAndMailBody()
Dim OutlookApp As Object, mailItem As Object, wordEditor As Object
    Sheet1.Range("A1:C3").CopyPicture
'    dan vao WORD
    Set wordApp = GetObject(, "Word.Application")
    wordApp.Selection.Paste

'    dan vao Outlook
    Set OutlookApp = GetObject(, "Outlook.Application")
    Set mailItem = OutlookApp.CreateItem(olMailItem)
    mailItem.Display
    Set wordEditor = OutlookApp.ActiveInspector.wordEditor
    wordEditor.Application.Selection.Paste
End Sub
 
Upvote 0
Nếu tôi hiểu được ý bạn (không ghi gì ra đĩa và đọc vào từ đĩa) thì ta dùng cơ cấu Automation.

Để chắc tôi hỏi thêm: code đặt ở Excel?

Cái ta cần là có được đối tượng gốc của WORD, OutLook là Application. Lúc đó có thể truy cập (có được) mọi đối tượng con, cháu, chắt, chít và read / write thuộc tính hay gọi các phương thức của chúng.

Ví dụ bạn đã có WORD, Outlook đang mở. Nếu chưa mở thì thay GetObject bằng CreateObject.

Mã:
Sub ExcelRangeToWordAndMailBody()
Dim OutlookApp As Object, mailItem As Object, wordEditor As Object
    Sheet1.Range("A1:C3").CopyPicture
'    dan vao WORD
    Set wordApp = GetObject(, "Word.Application")
    wordApp.Selection.Paste

'    dan vao Outlook
    Set OutlookApp = GetObject(, "Outlook.Application")
    Set mailItem = OutlookApp.CreateItem(olMailItem)
    mailItem.Display
    Set wordEditor = OutlookApp.ActiveInspector.wordEditor
    wordEditor.Application.Selection.Paste
End Sub
Hic hic, em test không chạy gì hết anh ơi. Em đặt code trong excel, không mở OutLook và cũng không có mở Word.

Em tự mày mò mãi thì cũng có được 1 cách nhưng em vẫn muốn tìm hiểu cách không sử dụng thêm hàm hỗ trợ như file em đang thử nghiệm
PHP:
Sub Range_To_Mail_Body()
Dim Sarr(), i, Rng As Range
Set Rng = Range([A2], [E65536].End(3))
Sarr = Range([A3], [E65536].End(3))
ActiveSheet.[A:E].Columns.AutoFit
For i = 1 To UBound(Sarr)
   Rng.AutoFilter 2, Sarr(i, 2)
   Rng.SpecialCells(12).Copy
   With CreateObject("Outlook.Application")
      .Session.Logon
         With .CreateItem(0)
           .To = Sarr(i, 5)
           .Subject = "THONG BAO"
           .HTMLBody = "<B>Dear " & Sarr(i, 2) & ",</B><BR>" & "</B><BR>" _
           & "noi dung dong 1" & "</B><BR>" _
           & "noi dung dong 2" & "</B><BR>" _
           & "noi dung dong 3" & "</B><BR>" _
           & "noi dung dong 4" & "</B><BR>" _
           & "noi dung dong 5" & "</B><BR>" _
           & RangetoHTML([A2:E7]) & "</B><BR>" & "</B><BR>" _
           & "<B>Nguyen Van Teo"
           .Display
         End With
   End With
Next
Rng.AutoFilter
End Sub
PHP:
Function RangetoHTML(Rng As Range)
    Dim FSO As Object, TS As Object
    Dim TempFile As String
    Dim TempWB As Workbook
    TempFile = Environ$("temp") & "\temp.htm"
    Rng.Copy
    Set TempWB = Workbooks.Add(1)
    With TempWB.Sheets(1)
      .Cells(1).PasteSpecial 8
      .Cells(1).PasteSpecial 1
      .Parent.PublishObjects.Add(xlSourceRange, TempFile, _
      .Name, .UsedRange.Address, xlHtmlStatic).Publish
      .Parent.Close False
    End With
      Set FSO = CreateObject("Scripting.FileSystemObject")
      RangetoHTML = FSO.GetFile(TempFile).OpenAsTextStream(1, -2).ReadAll:
      FSO.GetFile(TempFile).OpenAsTextStream(1, -2).Close
      RangetoHTML = Replace(RangetoHTML, "align=center x:publishsource=", "align=left x:publishsource=")
      Kill TempFile
    Set TS = Nothing:    Set FSO = Nothing:    Set TempWB = Nothing
End Function

Và đây là code em sửa lại từ code anh viết nhưng cứ báo lỗi tại dòng wordApp.Selection.Paste
Không biết là còn thiếu gì không. Đọc code thì không hiểu hết nên cứ rối lên
PHP:
Sub ExcelRangeToWordAndMailBody()
Dim OutlookApp As Object, mailItem As Object, wordEditor As Object
Dim wordApp As Object, olMailItem As Object
    Sheet1.Range("A1:C3").CopyPicture
    Set wordApp = CreateObject("Word.Application")
    wordApp.Selection.Paste
    Set OutlookApp = CreateObject("Outlook.Application")
    Set mailItem = OutlookApp.CreateItem(olMailItem)
    mailItem.Display
    Set wordEditor = OutlookApp.ActiveInspector.wordEditor
    wordEditor.Application.Selection.Paste
End Sub
 

File đính kèm

  • RangeToHTMLBody.rar
    19.3 KB · Đọc: 13
Lần chỉnh sửa cuối:
Upvote 0
Hic hic, em test không chạy gì hết anh ơi. Em đặt code trong excel, không mở OutLook và cũng không có mở Word

Em tự mày mò mãi thì cũng có được 1 cách nhưng em vẫn muốn tìm hiểu cách không sử dụng thêm hàm hỗ trợ như file em đang thử nghiệm


Nếu chưa mở thì phải dùng CreateObject. Tôi viết rõ mà. Tôi thử với XP + Excel 2007 thì OK

Quên mất. Thêm dòng đỏ đỏ vào code. Code ở dưới đã được thêm.

Mã:
[COLOR=#ff0000]Private Const olMailItem = 0[/COLOR]


Sub ExcelRangeToWordAndMailBody()
Dim OutlookApp As Object, mailItem As Object, wordEditor As Object
    Sheet1.Range("A1:C3").CopyPicture
'    dan vao Outlook
    Set OutlookApp = CreateObject("Outlook.Application")
    Set mailItem = OutlookApp.CreateItem(olMailItem)
    mailItem.Display
    Set wordEditor = OutlookApp.ActiveInspector.wordEditor
    wordEditor.Application.Selection.Paste
End Sub

----------
Cái hàm của bạn vẫn phải ghi tập tin (html) ra đĩa. Bạn thử module tôi viết xem sao

module
Mã:
Private Const GMEM_MOVEABLE As Long = &H2
Private Const GMEM_DDESHARE As Long = &H2000
Private Const CF_UNICODETEXT = 13

Private Const CP_UTF8 = 65001

Private Declare Function GetLastError Lib "kernel32" () As Long

Private Declare Function OpenClipboard Lib "user32" (ByVal hwnd As Long) As Long
Private Declare Function SetClipboardData Lib "user32.dll" (ByVal wFormat As Long, ByVal hMem As Long) As Long
Private Declare Function EmptyClipboard Lib "user32.dll" () As Long
Private Declare Function CloseClipboard Lib "user32" () As Long
Private Declare Function EnumClipboardFormats Lib "user32" (ByVal wFormat As Long) As Long
Private Declare Function GetClipboardFormatName Lib "user32" Alias "GetClipboardFormatNameA" (ByVal wFormat As Long, ByVal lpString As String, ByVal nMaxCount As Long) As Long
Private Declare Function IsClipboardFormatAvailable Lib "user32" (ByVal wFormat As Long) As Long
Private Declare Function GetClipboardData Lib "user32" (ByVal wFormat As Long) As Long

Private Declare Function GlobalSize Lib "kernel32" (ByVal hMem As Long) As Long
Private Declare Function GlobalAlloc Lib "kernel32.dll" (ByVal wFlags As Long, ByVal dwBytes As Long) As Long
Private Declare Function GlobalLock Lib "kernel32.dll" (ByVal hMem As Long) As Long
Private Declare Function GlobalUnlock Lib "kernel32.dll" (ByVal hMem As Long) As Long
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" _
    (Destination As Any, Source As Any, ByVal Length As Long)

Public Declare Function MultiByteToWideChar Lib "kernel32.dll" (ByVal CodePage As Long, ByVal dwFlags As Long, _
    lpMultiByteStr As Any, ByVal cchMultiByte As Long, ByVal lpWideCharStr As String, _
    ByVal cchWideChar As Long) As Long
    
Public Declare Function ShellExecute Lib "shell32.dll" Alias "ShellExecuteA" (ByVal hwnd As Long, ByVal lpOperation As String, ByVal lpFile As String, ByVal lpParameters As String, ByVal lpDirectory As String, ByVal nShowCmd As Long) As Long

Function RangeToHTML(rng As Range) As String
Dim text As String, format As Long, m() As Byte, hData As Long, pData As Long, size As Long, index As Long, start As Long, formatname As String
Dim strSize As Long
On Error Resume Next
'    copy range vao Clipboard
    rng.Copy

    If OpenClipboard(0) = 0 Then Exit Function
    format = EnumClipboardFormats(0)
    Do While format > 0
        formatname = String(64, Chr(0))
        size = GetClipboardFormatName(format, formatname, 64)
        formatname = Left(formatname, size)

        If formatname = "HTML Format" Then
'            trong ClipBoard có Format - HTML Format, vậy ta đọc Handle của Data
            hData = GetClipboardData(format)
            If hData = 0 Then MsgBox GetLastError
'            muốn đọc Data thì trước hết phải có "địa chỉ" của Data trong RAM - đọc ra bằng hàm GlobalLock
            pData = GlobalLock(hData)
'            độ lớn của Data đọc ra bằng hàm GlobalSize
            size = GlobalSize(hData)
            
'            chuẩn bị mảng có độ lớn thích hợp để đọc Data
'            ReDim m(0 To size - 1)
''            chép toàn bộ Data vào mảng
'            CopyMemory m(0), ByVal pData, size
'
'            strSize = MultiByteToWideChar(CP_UTF8, 0, m(0), size, vbNullString, 0)
'            text = String(2 * strSize, Chr(0))
'            MultiByteToWideChar CP_UTF8, 0, m(0), size, text, strSize
            
            strSize = MultiByteToWideChar(CP_UTF8, 0, ByVal pData, size, vbNullString, 0)
            text = String(2 * strSize, Chr(0))
            MultiByteToWideChar CP_UTF8, 0, ByVal pData, size, text, strSize
            
'            cuối cùng là UnLock
            GlobalUnlock hData
'            lọc nội dung HTML
            text = StrConv(text, vbFromUnicode)
            text = WideStrToWebStringUTF(text)
            
            index = InStr(1, text, ":", vbTextCompare)
            index = InStr(index + 1, text, ":", vbTextCompare)
'            vị trí mà từ đó bắt đầu nội dung HTML
            start = CLng(Mid(text, index + 1, InStr(index, text, vbCr) - index)) + 1
'            lấy nội dung HTML
            RangeToHTML = Mid(text, start)
            
            Exit Do
        End If
        format = EnumClipboardFormats(format)
    Loop
    CloseClipboard

    Application.CutCopyMode = False
End Function

Function WideStrToWebStringUTF(ByVal text As String) As String
Dim slowo As Integer, index As Long, c As String, s As String
    If Len(text) Then
        For index = 1 To Len(text)
            c = Mid(text, index, 1)
            If AscW(c) < &H80 Then
                s = s & c
            Else
                s = s & "&#" & AscW(c) & ";"
            End If
        Next index
    End If
    WideStrToWebStringUTF = s
End Function
 
Lần chỉnh sửa cuối:
Upvote 0
Nếu chưa mở thì phải dùng CreateObject. Tôi viết rõ mà. Tôi thử với XP + Excel 2007 thì OK

Mã:
Sub ExcelRangeToWordAndMailBody()
Dim OutlookApp As Object, mailItem As Object, wordEditor As Object
    Sheet1.Range("A1:C3").CopyPicture
'    dan vao Outlook
    Set OutlookApp = CreateObject("Outlook.Application")
    Set mailItem = OutlookApp.CreateItem(olMailItem)
    mailItem.Display
    Set wordEditor = OutlookApp.ActiveInspector.wordEditor
    wordEditor.Application.Selection.Paste
End Sub

----------
Chạy tốt rồi anh ơi. Vậy dùng cách mượn WordApp cho khỏe, dùng hàm hỗ trợ chóng mặt quá. Đọc hoa cả mắt vậy mà anh cũng viết ra được hay thiệt. Khâm phục anh thật.
 
Upvote 0
Anh chị nào test hộ đoạn code này với. Sao máy tính mình nó chạy lúc thì ok, nhưng đa phần là lỗi tại dòng này

WordEditor.Application.Selection.Paste


PHP:
Option Explicit
Private Const olMailItem = 0
Sub ExcelRangeToWordAndMailBody2()
Dim OutlookApp As Object, MailItem As Object, WordEditor As Object
    Sheet1.Range("A1:C3").CopyPicture
    Set OutlookApp = CreateObject("Outlook.Application")
    Set MailItem = OutlookApp.CreateItem(olMailItem)
    MailItem.Display
    Set WordEditor = OutlookApp.ActiveInspector.WordEditor
    WordEditor.Application.Selection.Paste
    Set OutlookApp = Nothing
    Set MailItem = Nothing
    Set WordEditor = Nothing
End Sub
 
Upvote 0
Anh chị nào test hộ đoạn code này với. Sao máy tính mình nó chạy lúc thì ok, nhưng đa phần là lỗi tại dòng này

WordEditor.Application.Selection.Paste


PHP:
Option Explicit
Private Const olMailItem = 0
Sub ExcelRangeToWordAndMailBody2()
Dim OutlookApp As Object, MailItem As Object, WordEditor As Object
    Sheet1.Range("A1:C3").CopyPicture
    Set OutlookApp = CreateObject("Outlook.Application")
    Set MailItem = OutlookApp.CreateItem(olMailItem)
    MailItem.Display
    Set WordEditor = OutlookApp.ActiveInspector.WordEditor
    WordEditor.Application.Selection.Paste
    Set OutlookApp = Nothing
    Set MailItem = Nothing
    Set WordEditor = Nothing
End Sub

Win 7, 2010 chạy bình thường, không lỗi.
 
Upvote 0
Vậy anh copy và dán bình thường = SendKeys thử nhé
Thử làm như sau:

Mã:
Sub TestGuiMail()
Dim OutlookApp As Object, MailItem As Object
    Sheet1.Range("A4:E18").CopyPicture
    Set OutlookApp = CreateObject("Outlook.Application")
    Set MailItem = OutlookApp.CreateItem(0)
   
    With MailItem
       .To = [B1]
       .Subject = [B2]
       .Display
    End With
    SendKeys "^({v})", True
    
    Set OutlookApp = Nothing
    Set MailItem = Nothing
   
End Sub
 

File đính kèm

  • SendMail.xlsm
    20.5 KB · Đọc: 22
Upvote 0
Code thế này thì ngắn gọn nhưng chẳng biết làm sao cho cái hình nó chịu nằm ở giữa các dòng text mình cần.
Cái hình nó cứ chạy lên đầu nằm mới bực chứ. Các anh có cách nào cho nó nằm đúng chỗ không.
(Mình muốn nghiên cứu cách khi dùng SendKeys mà hình có thể nằm giữa 2 đoạn Text)
PHP:
Sub ExcelRangeToWordAndMailBody()
    Sheet1.Range("A1:C3").CopyPicture
      With CreateObject("Outlook.Application")
         With .CreateItem(0)
            .To = "A"
            .Subject = "B"
            .Display
            SendKeys ("^v")
            .HTMLBoDy = " <B><BR>" & "Dear" & _
            "</B><BR><BR><BR><BR>" & "Tran Trong"
         End With
      End With
End Sub
 
Upvote 0
Code thế này thì ngắn gọn nhưng chẳng biết làm sao cho cái hình nó chịu nằm ở giữa các dòng text mình cần.
Cái hình nó cứ chạy lên đầu nằm mới bực chứ. Các anh có cách nào cho nó nằm đúng chỗ không.
(Mình muốn nghiên cứu cách khi dùng SendKeys mà hình có thể nằm giữa 2 đoạn Text)
PHP:
Sub ExcelRangeToWordAndMailBody()
    Sheet1.Range("A1:C3").CopyPicture
      With CreateObject("Outlook.Application")
         With .CreateItem(0)
            .To = "A"
            .Subject = "B"
            .Display
            SendKeys ("^v")
            .HTMLBoDy = " <B><BR>" & "Dear" & _
            "</B><BR><BR><BR><BR>" & "Tran Trong"
         End With
      End With
End Sub
Thử sửa lại như sau:

Mã:
Sub ExcelRangeToWordAndMailBody()
    Sheet1.Range("A1:C3").CopyPicture
      With CreateObject("Outlook.Application")
         With .CreateItem(0)
            .To = "A"
            .Subject = "B"
            .Display
            .HTMLBoDy = " <B>Dear</B>" & _
            "<BR><BR><BR><BR><B>Tran Trong</B>"
            SendKeys "({DOWN})", True
            SendKeys "({DOWN})", True
            SendKeys "^({v})", True
         End With
      End With
End Sub
 
Upvote 0
Thử sửa lại như sau:

Mã:
Sub ExcelRangeToWordAndMailBody()
    Sheet1.Range("A1:C3").CopyPicture
      With CreateObject("Outlook.Application")
         With .CreateItem(0)
            .To = "A"
            .Subject = "B"
            .Display
            .HTMLBoDy = " <B>Dear</B>" & _
            "<BR><BR><BR><BR><B>Tran Trong</B>"
            SendKeys "({DOWN})", True
            SendKeys "({DOWN})", True
            SendKeys "^({v})", True
         End With
      End With
End Sub
Ok anh. Cách này coi như có thêm 1 giải pháp.
 
Upvote 0
Không có cao thủ nào hỗ trợ mình sao? Nếu code này không sử dụng được với hàng trăm email muốn auto send ko display thì các cao thủ có thể hỗ trợ mình một hướng khác không? Thanks so much
 
Lần chỉnh sửa cuối:
Upvote 0
Không có cao thủ nào hỗ trợ mình sao? Nếu code này không sử dụng được với hàng trăm email muốn auto send ko display thì các cao thủ có thể hỗ trợ mình một hướng khác không? Thanks so much
Xin lỗi vì em đào lên lại, code này dán xong lên display có thể gửi luôn không ạ, không cần phải thao tác click send nữa
 
Upvote 0
Web KT

Bài viết mới nhất

Back
Top Bottom