kucingblue Publish time 12-8-2010 12:32 PM

.NET Framework 3.5 and MS Office 2007 VBA

ok, here's the thing. Aku dah lebih 8 bulan takde keje kat office. so bosan bosan, aku start programming.

aku nak design satu program yg hantar short message to Excel file aku. The Excel file has a built-in VBA codes that automatically run when the workbook is opened. I wrote the VBA so I can change it, I just don't want to rebuild it.

So, untuk IPC, aku decided on using Memory Mapped File.

External program tu aku buat pakai VB.net 3.5. Terpaksa pakai 3.5 sebab tak sume orang dalam company aku ade .net 4 and tak leh nak install sendiri.

Bile aku buat external program tu pakai .net 4, no problem. I can communicate with my Excel VBA. .Net 4 memang dah ade built-in functions utk MMF. But .Net 3.5 kena import kernel32 manually.

So, ade sesape kat sini penah pakai .Net 3.5 utk buat MMF? Kalo ade tolong tunjuk ajar. I have no problem creating the MMF, but when it comes to CopyMemory (RtlMoveMemory) aku pening sket. Puas aku search online. :(

Or kalo ade suggestion protocol lain selain MMF, please share. Thanks.

p/s: I'm a Mechanical Engineer. So my programming knowledge is quite limited.

kucingblue Publish time 14-8-2010 06:16 AM

nvm. I've figured it out.

webxcrawler Publish time 18-8-2010 08:42 PM

nvm. I've figured it out.
kucingblue Post at 14-8-2010 06:16 http://forum.cari.com.my/images/common/back.gif

berminat nak tau. leh berkongsi? huhuhu

kucingblue Publish time 21-8-2010 01:01 PM

Post Last Edit by kucingblue at 20-8-2010 21:02

Reply 3# webxcrawler

sure.

so basically cammana nak external program to kasi message kat excel vba punya code.

download example file kat sini.
http://steekr.com/n/50-17/share/LNK53424c6f5a9353394/
dalam tu ade transmitter.exe and receiverc.xlsm.

open excel file tu. enable macro.
run transmitter.exe. pastu tulis short message kat textbox, and tekan button .net4 or .net3.5 or both.
back to excel file tu, tekan one of the buttons. you'll see a message box showing the message received from the transmitter.exe.

that's a short demonstration of how it works.

code dia plak camni.

untuk transmitter.exe
aku compile pakai Visual Basic Express (it's a free program by Microsoft, light version of Visual Basic Studio 10 kot.).



Public Class Form1

    Dim mmf As MemoryMappedFile = MemoryMappedFile.CreateNew("Peta4", 16)   'untuk .Net4 method. Peta4 ni nama memory-mapped file untuk method ni.




'/////////////////////////declaration untuk .net3.5 method//////////////////////////////////////


    Const PAGE_READONLY As Integer = &H2
    Const PAGE_READWRITE As Integer = &H4
    Const PAGE_WRITECOPY As Integer = &H8

    Const FILE_MAP_COPY As Integer = 1
    Const FILE_MAP_WRITE As Integer = 2
    Const FILE_MAP_READ As Integer = 4
    Const FILE_MAP_ALL_ACCESS As Integer = FILE_MAP_WRITE

    Const INVALID_HANDLE_VALUE As Integer = -1



    Private Declare Function OpenFileMapping Lib "kernel32" Alias "OpenFileMappingA" ( _
      ByVal dwDesiredAccess As Integer, _
      ByVal bInheritHandle As Integer, _
      ByVal lpName As String) As Integer

    Private Declare Function CreateFileMapping Lib "kernel32" Alias "CreateFileMappingA" ( _
      ByVal hFileMapTable As Integer, _
      ByVal lpFileMappingAttributes As Integer, _
      ByVal flProtect As Integer, _
      ByVal dwMaximumSizeHigh As Integer, _
      ByVal dwMaximumSizeLow As Integer, _
      ByVal lpName As String) As Integer

    Private Declare Function MapViewOfFile Lib "kernel32" ( _
      ByVal hFileMapTableMappingObject As Integer, _
      ByVal dwDesiredAccess As Integer, _
      ByVal dwFileOffsetHigh As Integer, _
      ByVal dwFileOffsetLow As Integer, _
      ByVal dwNumberOfBytesToMap As Integer) As Integer

    Private Declare Function UnmapViewOfFile Lib "kernel32" ( _
      ByVal lpBaseAddress As Integer) As Integer

    Private Declare Function CloseHandle Lib "kernel32" ( _
      ByVal hObject As Integer) As Integer

    Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" ( _
    ByVal Dst As Integer, _
    ByVal pSrc As Byte(), _
    ByVal ByteLen As Integer)

'/////////////////////////////////////////////////////////////////////////////////////////////////////////




    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
'label button-button
      Button1.Text = "Transmit" & vbNewLine & ".Net 4"
      Button3.Text = "Transmit" & vbNewLine & ".Net 3.5"

    End Sub



    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

      '.Net 4 method


      Dim stream As MemoryMappedViewStream = mmf.CreateViewStream

      Dim writer As BinaryWriter = New BinaryWriter(stream) 'first 4 bytes binarywriter contains the length of the string

      writer.Write(TextBox1.Text)

      stream = mmf.CreateViewStream



    End Sub






    Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click

      '.Net 3.5 method


      Dim handle As Integer, hPtr As Integer

      handle = CreateFileMapping(INVALID_HANDLE_VALUE, 0, PAGE_READWRITE, 0, 4096, "Peta3")'Peta3 ni nama memory-mapped file untuk method .net 3.5

      hPtr = MapViewOfFile(handle, FILE_MAP_ALL_ACCESS, 0, 0, 0)



      Dim utusan(3) As Byte
      Dim i As Integer
      i = Len(TextBox1.Text)            'kira panjang message ni
      utusan = BitConverter.GetBytes(i)         'convert to bytes

      Dim bytearray() As Byte

      bytearray = StrToByteArray(TextBox1.Text)         'convert message to byte array

      ReDim Preserve utusan(UBound(bytearray) + 4)      'resize array utusan

      Array.Copy(bytearray, 0, utusan, 4, UBound(bytearray) + 1)   'combine message dari bytearray into utusan

      CopyMemory(hPtr, utusan, UBound(utusan) + 1)


    End Sub



    Public Shared Function StrToByteArray(ByVal str As String) As Byte()
      Dim encoding As New System.Text.UTF8Encoding()
      Return encoding.GetBytes(str)
    End Function



End Class


bersambung....

kucingblue Publish time 21-8-2010 01:06 PM

code untuk receiver. code ni untuk terima message dari .Net 4 punya method.
code ni aku tulis dalam excel punya macro module.

unlike .Net 4, Excel 2007 VBA takde built-in support for Memory-Mapped Files. So kena import kernel32 punya functions manually.



Option Explicit

Private Const PAGE_READONLY As Long = &H2
Private Const PAGE_READWRITE As Long = &H4
Private Const PAGE_WRITECOPY As Long = &H8

Private Const FILE_MAP_COPY As Long = 1
Private Const FILE_MAP_WRITE As Long = 2
Private Const FILE_MAP_READ As Long = 4
Private Const FILE_MAP_ALL_ACCESS As Long = FILE_MAP_WRITE

Private Const INVALID_HANDLE_VALUE As Long = -1

'//////////////////////////////////////////////////

Private Declare Function OpenFileMapping Lib "kernel32" Alias "OpenFileMappingA" ( _
    ByVal dwDesiredAccess As Long, _
    ByVal bInheritHandle As Long, _
    ByVal lpName As String) As Long

Private Declare Function MapViewOfFile Lib "kernel32" ( _
    ByVal hFileMapTableMappingObject As Long, _
    ByVal dwDesiredAccess As Long, _
    ByVal dwFileOffsetHigh As Long, _
    ByVal dwFileOffsetLow As Long, _
    ByVal dwNumberOfBytesToMap As Long) As Long

Private Declare Function UnmapViewOfFile Lib "kernel32" ( _
    lpBaseAddress As Any) As Long

Private Declare Function CloseHandle Lib "kernel32" ( _
    ByVal hObject As Long) As Long


Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (ByRef dest As Any, _
   ByVal source As Long, ByVal bytes As Long)





Sub dotNet4()


    Dim handle As Long
    Dim hptr As Long
   
   
    handle = OpenFileMapping(FILE_MAP_READ, False, "Peta4")
    hptr = MapViewOfFile(handle, FILE_MAP_READ, 0, 0, 0)

    Dim sLen As Integer

    Dim barray() As Byte
   

    If hptr <> 0 Then
      Dim tali As String
      
      CopyMemory sLen, hptr, 1 'read string length

      ReDim barray(0 To sLen - 1)

      CopyMemory ByVal VarPtr(barray(0)), hptr + 1, sLen
            
      tali = ByteArrayToString(barray)
            
    Else      'kalau hptr=0 maknanya memory-mapped file tu tak jumpe
      MsgBox ("No transmission received")
   
    End If
   
   
    UnmapViewOfFile (hptr)
   
    CloseHandle (handle)
   


    MsgBox ("Message received from .Net 4 transmission: " & vbNewLine & tali)



End Sub


Public Function ByteArrayToString(bytArray() As Byte) As String
    Dim sAns As String
    Dim iPos As String
   
    sAns = StrConv(bytArray, vbUnicode)
    iPos = InStr(sAns, Chr(0))
    If iPos > 0 Then sAns = Left(sAns, iPos - 1)
   
    ByteArrayToString = sAns

End Function

kucingblue Publish time 21-8-2010 01:09 PM

ni code untuk terima message dari .Net 3.5 punya method.



Option Explicit

Private Const PAGE_READONLY As Long = &H2
Private Const PAGE_READWRITE As Long = &H4
Private Const PAGE_WRITECOPY As Long = &H8

Private Const FILE_MAP_COPY As Long = 1
Private Const FILE_MAP_WRITE As Long = 2
Private Const FILE_MAP_READ As Long = 4
Private Const FILE_MAP_ALL_ACCESS As Long = FILE_MAP_WRITE

Private Const INVALID_HANDLE_VALUE As Long = -1

'//////////////////////////////////////////////////

Private Declare Function OpenFileMapping Lib "kernel32" Alias "OpenFileMappingA" ( _
    ByVal dwDesiredAccess As Long, _
    ByVal bInheritHandle As Long, _
    ByVal lpName As String) As Long


Private Declare Function MapViewOfFile Lib "kernel32" ( _
    ByVal hFileMapTableMappingObject As Long, _
    ByVal dwDesiredAccess As Long, _
    ByVal dwFileOffsetHigh As Long, _
    ByVal dwFileOffsetLow As Long, _
    ByVal dwNumberOfBytesToMap As Long) As Long

Private Declare Function UnmapViewOfFile Lib "kernel32" ( _
    lpBaseAddress As Any) As Long

Private Declare Function CloseHandle Lib "kernel32" ( _
    ByVal hObject As Long) As Long


Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (ByRef dest As Any, _
   ByVal source As Any, ByVal bytes As Long)
   


Sub dotNet3point5()


    Dim handle As Long
    Dim hptr As Long
   
   
    handle = OpenFileMapping(FILE_MAP_READ, False, "Peta3")
    hptr = MapViewOfFile(handle, FILE_MAP_READ, 0, 0, 0)


    Dim sLen As Integer
    Dim slen2(3) As Byte
   
    Dim barray() As Byte
   
   
    If hptr <> 0 Then
      Dim tali As String
      
      CopyMemory ByVal VarPtr(slen2(0)), hptr, 4 'read string length
      sLen = slen2(0) + (slen2(1) * 16 ^ 2) + (slen2(2) * 16 ^ 3 + (slen2(3) * 16 ^ 4))
      
      
      ReDim barray(0 To 2 * sLen)

      

            CopyMemory ByVal VarPtr(barray(0)), hptr + 4, sLen
            
            tali = ByteArrayToString(barray)
            
    Else
      MsgBox ("No transmission received")
   
    End If
   
    UnmapViewOfFile (hptr)
   
    CloseHandle (handle)
   


MsgBox ("Message received from .Net 3.5 transmission: " & vbNewLine & tali)
   

   
End Sub






Public Function ByteArrayToString(bytArray() As Byte) As String
    Dim sAns As String
    Dim iPos As String
   
    sAns = StrConv(bytArray, vbUnicode)
    iPos = InStr(sAns, Chr(0))
    If iPos > 0 Then sAns = Left(sAns, iPos - 1)
   
    ByteArrayToString = sAns

End Function

kucingblue Publish time 21-8-2010 01:11 PM

so there. I managed to make my external program talk to my excel macro by sharing a memory.
it took me a couple of weeks to figure this out. the problem is Excel punya VBA kalo silap sket jek pakai function CopyMemory tu trus crash. tu pasal la makan masa. lagi satu i think VBA 2007 is like the old version of Visual Basic. Visual Basic .Net cam lain sket. so confused gak la.
Pages: [1]
View full version: .NET Framework 3.5 and MS Office 2007 VBA


ADVERTISEMENT