Trigering Essbase Macro with C# - c#

I'm trying to automatize some Excel reports. Currently I need to retrieve some data from an Essbase Server, in order to achieve this I've created a macro to retrieve and set data in an Excel sheet, my VBA code is the following:
Option Explicit
Declare Function EssVRetrieve Lib "ESSEXCLN.XLL" (ByVal sheetName As Variant, ByVal range As Variant, ByVal lockflag As Variant) As Long
Declare Function EssVConnect Lib "ESSEXCLN.XLL" (ByVal sheetName As Variant, ByVal userName As Variant, ByVal password As Variant, ByVal server As Variant, ByVal application As Variant, ByVal database As Variant) As Long
Declare Function EssVDisconnect Lib "ESSEXCLN.XLL" (ByVal sheetName As Variant) As Long
Sub Essbase_Update_Pulls()
Dim rangeString As String
rangeString = "B3:AC5033"
MsgBox ("Starting macro")
Dim wbSrc As Workbook
Dim m As Variant
Dim mySheetname As Variant, myUserName As Variant, myPassword As Variant, myServer, myApp As Variant, myDB As Variant
Dim lockflag As Integer
Dim myrng As range
Dim x As Integer
Dim y As Integer
Dim z As Integer
Dim strMsgTxt As String
Dim blnRetVal As Boolean
Set wbSrc = ActiveWorkbook
Set myrng = range(rangeString)
lockflag = 1
MsgBox ("Data set")
mySheetname = "Sheet"
myServer = "Server"
myApp = "App"
myDB = "DB"
myUserName = "User"
myPassword = "Pass"
MsgBox ("Trying connection")
x = EssVConnect(mySheetname, myUserName, myPassword, myServer, myApp, myDB)
MsgBox (CStr(x))
If x < 0 Then
blnRetVal = False
strMsgTxt = "Essbase Login - Local Failure"
MsgBox (strMsgTxt)
ElseIf x > 0 Then
blnRetVal = False
strMsgTxt = "Essbase Login - Server Failure"
MsgBox (strMsgTxt)
Else
blnRetVal = True
strMsgTxt = "Success"
MsgBox ("Connection Succeeded")
y = EssVRetrieve(mySheetname, myrng, lockflag)
If y = 0 Then
MsgBox ("Retrieve successful.")
z = EssVDisconnect(mySheetname)
If z = 0 Then
MsgBox ("Disconnect Succeed.")
Else
MsgBox ("Disconnect failed.")
End If
Else
MsgBox ("Retrieve failed.")
End If
End If
End Sub
Variable x is supposed to return the status code (0 is success any other is failed).
So here comes the trick, whenever I run this macro within Excel it runs perfectly, however when I call it from C# using xlApp.Run("Essbase_Update_Pulls"); it returns a status code of -3.
Doing some research I found out that whenever an Excel Application is created in code it doesn't have the add-ins loaded, so they have to be manually loaded
https://community.oracle.com/thread/2480398 .
I iterated over the xlApp.AddIns and found that the "essexcln.xll" was correctly installed so I have no idea what to do now. Also I found out that Add-Ins can be added during runtime but this just causes an exception, here is the source:
http://www.network54.com/Forum/58296/thread/957392331/Visual+Basic-Excel+Api+call+to+Essbase

Found out that excel isn't loading all the dll's and xll's required to connect to de Essbase server. In order to make it work it is necessary to start excel as a process and the acquire the instance and relate it to the interop class. I found the solution here:Excel interop loading XLLs and DLLs. The user pretty much had the same problem but with Bloomberg. I would just add that in the SearchExcelInterop method it needs a Thread.Sleep() to wait for Excel to load properly, in my case it threw a StackOverflowException.

Related

Remote logout tool

I'm writing a remote log out tool for the school I attend. As system admins, we use it to log out users after our on-campus labs have closed to make sure that all the computers get updates at night. With windows 7, the tool we have now works fine. But we're updating to windows 10 for all of our machines and the tool has mysteriously stopped functioning. It's written in VB.net as of right now (open to a change to c# if needed). Currently we have 2 main functions for the program:
Private Sub LogOut()
Dim AdminAccount As String = txtUsr.Text
Dim AdminDomain As String = txtDomain.Text
Dim AdminPassword As String = txtPwd.Text
Dim ShutDownLocal As String = "c:\bin\"
Dim LogOutProgram As String = "c:\bin\Logout.cmd"
Dim TargetMachine As String = cboDom.Text & ComboBox1.Text & "p" & txtMachine.Text & txtDomain.Text
Dim ShutDownCommand As String = "shutdown -t 300 /r /m \\" & TargetMachine
If RunAs.RunAs(AdminAccount, AdminPassword, AdminDomain, ShutDownCommand, ShutDownLocal) Then
Status.Text = "5 Minute Logout sent to machine"
End If
End Sub
and
Public Shared Function RunAs(ByVal UserName As String, _
ByVal Password As String, _
ByVal DomainName As String, _
ByVal CommandLine As String, _
ByVal StartIn As String) As Boolean
Dim iRet As Integer
Dim si As New STARTUPINFO
Dim pi As PROCESS_INFORMATION
si.cb = Marshal.SizeOf(si)
si.wShowWindow = 0
iRet = CreateProcessWithLogonW(UserName, DomainName, Password, _
LOGON_WITH_PROFILE, Nothing, CommandLine, _
NORMAL_PRIORITY_CLASS, 0, StartIn, si, pi)
If iRet = 0 Then
MessageBox.Show("Password incorrect.", "Error")
Return False
Else
CloseHandle(pi.hThread)
CloseHandle(pi.hProcess)
Return True
End If
End Function
Currently this functions absolutely fine on windows 7 machines but for attempting it on windows 10 machines we either get "access denied(5)" or "The entered computer name is not valid or remote shutdown is not supported on the target computer. Check the name and then try again or contact your system administrator.(53)"
I already checked with the administrator and he said that it is enabled. We use a domain level firewall so the individual computers aren't rejecting the connection. Every machine has the same administrator groups (Which I am using the credentials for every attempt). I'm not sure of any other solutions to look into. Sorry for the wall of text, any solutions can be tested for the most part. No third party software unfortunately.
Thanks!

Programmatically create a SQL Server Compact database on the client machines

I have recently started experimenting with SQL Server Compact and EF6. I am currently using the model first approach and generating my classes and tables from it. I am curious though, about one thing. How can I get my program to dynamically create the database. It exists on my machine as I created it with the SQL Server Compact/SQLite toolkit, but when the program is deployed to client computers, the database will need to be created.
I would want to prompt them on first run for a good location, then create the entire DB schema and just use that in the future. I looked into this guide but vs started complaining about it not working because I didn't use a code-first approach.
If you need more info let me know! Thanks.
I have a little app I'm working on using SQL CE and EF and I deploy the template database when the app is installed (clickonce). Then I use a spash screen on application start to either load a previously created database or let the user create a new one.
When they create a new db I simply prompt them for a location and copy the template database out to their desired location with their desired name. I've also set it up to use the deployed database without giving them the opportunity have multiple database files.
We are dealing with a few pieces here as follows:
SQL CE database file
My stock/template .sdf file sits in my project folder and is included in the project within Visual Studio (I'm using 2015). Rightclick on the file in the Solution Explorer and select properties you want to set the following:
Build Action - Content
Copy to Output Directory - Copy always
Create global variable
Either use an existing module file or create a new one that looks like this:
Public Module Globals
Friend g_recipeData As RecipeEntities
End Module
Create setting for last file path
Rightclick on your project name in the solution explorer and pick Properties. Click the Settings tab and add a new setting as follows:
Name: lastpath
Type: String
Scope: User
Value:
Create splash screen form (frmSplash)
Mine looks like this:
Controls on the form are as follows:
txtFile
cmdSelectDatabase
cmdNew
cmdOpen
cmdExit
Splash Screen (frmSplash) Code
Region "Form Methods"
Private Sub OnFormLoad() Handles Me.Load
txtFile.Text = My.Settings.lastpath
If txtFile.Text <> "" Then
cmdOpen.Enabled = True
cmdOpen.Select()
Else
cmdNew.Select()
End If
End Sub
Private Sub FileSelect()
Try
Dim openFileDialog As New OpenFileDialog()
openFileDialog.Filter = "sdf files (*.sdf)|*.sdf|All files (*.*)|*.*"
openFileDialog.FilterIndex = 1
openFileDialog.RestoreDirectory = True
Dim result As DialogResult = openFileDialog.ShowDialog(Me)
If result = DialogResult.Cancel Then
cmdSelectDatabase.Select()
Exit Sub
End If
txtFile.Text = openFileDialog.FileName
If txtFile.Text <> "" Then
cmdOpen.Enabled = True
cmdOpen.Select()
My.Settings.lastpath = openFileDialog.FileName
My.Settings.Save()
Else
cmdOpen.Enabled = False
cmdSelectDatabase.Select()
End If
Catch ex As Exception
MessageBox.Show(ex.Message.ToString, "Application Error")
Application.Exit()
Finally
End Try
End Sub
Private Sub SetConnectionString()
Try
Dim providerName As String = "System.Data.SqlServerCe.4.0"
Dim datasource As String = txtFile.Text
Dim sqlCeBuilder As New SqlCeConnectionStringBuilder
sqlCeBuilder.DataSource = datasource
sqlCeBuilder.PersistSecurityInfo = True
g_SQLCeConnectionString = sqlCeBuilder.ConnectionString
Dim providerString As String = sqlCeBuilder.ToString()
Dim entityBuilder As New EntityConnectionStringBuilder()
entityBuilder.Provider = providerName
entityBuilder.ProviderConnectionString = providerString
entityBuilder.Metadata = "res://*/RecipeModel.csdl|res://*/RecipeModel.ssdl|res://*/RecipeModel.msl"
Dim c As System.Configuration.Configuration = ConfigurationManager.OpenExeConfiguration(System.Reflection.Assembly.GetExecutingAssembly().Location)
Dim section As ConnectionStringsSection = DirectCast(c.GetSection("connectionStrings"), ConnectionStringsSection)
g_EntityConnectionString = entityBuilder.ConnectionString
section.ConnectionStrings("RecipeEntities").ConnectionString = g_EntityConnectionString
c.Save(ConfigurationSaveMode.Modified)
ConfigurationManager.RefreshSection("connectionStrings")
Catch ex As Exception
MessageBox.Show(ex.Message.ToString, "Application Error")
Application.Exit()
End Try
End Sub
Private Sub CreateDatabase()
Try
Dim saveFileDialog As New SaveFileDialog()
saveFileDialog.Filter = "sdf files (*.sdf)|*.sdf"
saveFileDialog.Title = "Create Database"
saveFileDialog.FilterIndex = 1
If saveFileDialog.ShowDialog() = DialogResult.OK Then
File.Copy(Path.Combine(ApplicationDeployment.CurrentDeployment.DataDirectory, "rw.sdf"), saveFileDialog.FileName, True)
Dim strPathandFile As String = saveFileDialog.FileName
txtFile.Text = strPathandFile
My.Settings.lastpath = strPathandFile
My.Settings.Save()
cmdOpen.Enabled = True
End If
Catch ex As Exception
MessageBox.Show(ex.Message.ToString, "Application Error")
Application.Exit()
End Try
End Sub
Private Sub LoadMainApplication()
Try
Dim objNewForm As New FrmMain
objNewForm.Show()
Me.Close()
Catch ex As Exception
MessageBox.Show(ex.Message.ToString, "Application Error")
Application.Exit()
End Try
End Sub
End Region
Region "Event Handlers"
Private Sub cmdSelectDatabase_Click(sender As Object,
e As EventArgs) Handles cmdSelectDatabase.Click
FileSelect()
cmdOpen.Select()
End Sub
Private Sub cmdCancel_Click(sender As Object, e As EventArgs) Handles cmdExit.Click
Me.Close()
End Sub
Private Sub cmdOk_Click(sender As Object, e As EventArgs) Handles cmdOpen.Click
Me.Cursor = Cursors.WaitCursor
SetConnectionString()
LoadMainApplication()
Me.Cursor = Cursors.Default
End Sub
Private Sub txtFile_Validated(sender As Object, e As EventArgs) Handles txtFile.Validated
If txtFile.Text.Length = 0 Then
cmdOpen.Enabled = False
Else
cmdOpen.Enabled = True
End If
End Sub
Private Sub cmdNew_Click(sender As Object,
e As EventArgs) Handles cmdNew.Click
CreateDatabase()
SetConnectionString()
LoadMainApplication()
End Sub
Private Sub CatchEnterKey(ByVal sender As Object,
ByVal e As System.Windows.Forms.KeyPressEventArgs) _
Handles txtFile.KeyPress, txtPassword.KeyPress
If e.KeyChar = ChrW(Keys.Enter) Then
cmdOk_Click(sender, e)
e.Handled = True
Exit Sub
End If
End Sub
Set global variable value
On the form of your main application (frmMain above) add the following to the constructor:
Public Sub New()
InitializeComponent()
g_recipeData = New RecipeEntities
End Sub
If you perform the above action when you create the variable in the module file then the connection string for the entity is set and you can't change it. You must set the connection string in app.config (using the above code) first and then the entity will use desired connection string when instantiated.
I think that's the basics for now. I highly recommend you reading through it again now that I'm done. I made some corrections and even added a step for the lastpath setting. Just hit me up if something isn't working or is confusing and I'll do my best to help. Good luck!

Setting the volume of target process using win32 waveOutSetVolume function?

I would like to set the volume of an specified process that is playing audio.
I found that I can do it with the waveOutSetVolume WinAPI function because it works as per-process, however, after I read these docs below I still can't figure out how to do it.
waveOutSetVolume function - MSDN
waveOutSetVolume function - pinvoke.net
I'm searching for a solution in C# or VB.Net.
This is the firm of my waveOutSetVolume:
<DllImport("winmm.dll", EntryPoint:="waveOutSetVolume", SetLastError:=True)>
Friend Shared Function WaveOutSetVolume(byval hwo As IntPtr,
byval dwVolume As UInteger) As Integer
End Function
And this is how I'm trying to call the function:
Public Sub SetVolume(ByVal hwo As IntPtr, ByVal volume As Integer)
If (volume < 0) OrElse (volume > 100) Then
Throw New ArgumentOutOfRangeException(
paramName:="volume",
message:="A value between 0 and 100 is required.")
Else
Dim valueFromPercent As UShort = CUShort(volume / (100US / UShort.MaxValue))
' Left channel volume
Dim loBytes As Byte() = BitConverter.GetBytes(valueFromPercent)
' Right channel volume
Dim hiBytes As Byte() = BitConverter.GetBytes(valueFromPercent)
Dim dWord As UInteger =
BitConverter.ToUInt32(loBytes.Concat(hiBytes).ToArray, 0)
NativeMethods.WaveOutSetVolume(hwo, dWord)
End If
End Sub
I know that an hwo will not be the same as a process handle, but as I said I can't figure it out how to discover the hwo of a process.
Note my DWORD calculation seems not be the problem because if I pass a Intptr.Zero to the function then it sets the expected volume for the current application.

How to hide publishing progress bar for ExportAsFixedFormat

I am trying to convert Excel file to PDF using interop.excel, while executing ExportAsFixedFormat 'publishing' progress bar displays on the site. Is there any way to hide this? I found this issue for Excel files having size above 300KB.
Code is given below:
//(tried using Application instead of ApplicationClass)
Microsoft.Office.Interop.Excel.ApplicationClass excelApplication = new Microsoft.Office.Interop.Excel.ApplicationClass();
excelApplication.ScreenUpdating = false;
excelApplication.DisplayAlerts = false;
excelApplication.Visible = false;
if (excelWorkbook == null)
{
excelApplication.Quit();
excelApplication = null;
excelWorkbook = null;
return false;
}
var exportSuccessful = true;
try
{
excelApplication.AlertBeforeOverwriting = false;
excelWorkbook.ExportAsFixedFormat(Microsoft.Office.Interop.Excel.XlFixedFormatType.xlTypePDF, outputPath);
}
catch (System.Exception ex)
{
exportSuccessful = false;
}
I can't find any solution. My project is a C# web application.
It took me a few days to figure out, but finally here is a workarround which uses some WinAPI functions to observe windows events. While the hook is active, every new window is compared to whether its class is the same one as the PDF save dialog class. If that's the case, the window gets hidden.
Thanks for solution ideas go to some chinese guys:
http://www.itjie.wang/officebase/516998.html
Usage requirement:
OS (= Operating System) must be Windows because of WinAPI usage.
Warning:
If the "SetWinEventHook" isn't stopped again due to some errors, it is better to restart your system, otherwise you could run into some serious problems with Windows.
Note:
By default, the PDF save dialog doesn't appear regularly. It depends on the time necessary to save the PDF file. If it takes longer the save popup will show up. If it takes shorter the save popup won't show up. Anyway, you don't have to worry about whether the save dialog would appear or not, the code already does this for you.
Instruction:
In your Excel workbook, if you don't already have a module, create a new one (name doesn't matter) & paste following code:
' WINDOWS API FUNCTIONS:
Private Declare Function SetWinEventHook Lib "user32" (ByVal eventMin As Long, ByVal eventMax As Long, ByVal hmodWinEventProc As Long, ByVal pfnWinEventProc As Long, ByVal idProcess As Long, ByVal idThread As Long, ByVal dwFlags As Long) As Long
Private Declare Function UnhookWinEvent Lib "user32" (ByVal hWinEventHook As Long) As Long
Private Declare Function apiGetClassName Lib "user32" Alias "GetClassNameA" (ByVal hWnd As Long, ByVal lpClassname As String, ByVal nMaxCount As Long) As Long
Private Declare Function apiShowWindow Lib "user32" Alias "ShowWindow" (ByVal hWnd As Long, ByVal nCmdShow As Long) As Long
' CONSTANT VARIABLES:
Private Const SW_HIDE = 0
Private Const DLG_CLSID = "CMsoProgressBarWindow"
Private Const EVENT_SYSTEM_FOREGROUND = &H3&
Private Const WINEVENT_OUTOFCONTEXT = 0
' GLOBAL VARIABLES:
Dim long_WinEventHook As Long
Public Function StartEventHook() As Long
long_WinEventHook = SetWinEventHook(EVENT_SYSTEM_FOREGROUND, EVENT_SYSTEM_FOREGROUND, 0&, AddressOf WinEventFunc, 0, 0, WINEVENT_OUTOFCONTEXT)
StartEventHook = long_WinEventHook
End Function
Public Sub StopEventHook()
Dim b_unhooked As Boolean
If long_WinEventHook = 0 Then
MsgBox "WinEventHook couldn't be stopped! " & _
"Variable 'long_WinEventHook' is empty! " & _
"Better restart Windows now!"
Exit Sub
End If
b_unhooked = UnhookWinEvent(long_WinEventHook)
If b_unhooked = True Then
Else
MsgBox "WinEventHook couldn't be stopped! " & _
"Variable 'b_unhooked' is false! " & _
"Better restart Windows now!"
End If
End Sub
' CALLBACK FUNC OF "SetWinEventHook" (DEFINE ACTIONS TO RUN ON THE EVENTS):
' http://stackoverflow.com/questions/20486944/detecting-in-vba-when-the-window-containing-an-excel-instance-becomes-active
Public Function WinEventFunc(ByVal HookHandle As Long, ByVal LEvent As Long, ByVal hWnd As Long, ByVal idObject As Long, ByVal idChild As Long, ByVal idEventThread As Long, ByVal dwmsEventTime As Long) As Long
'This function is a callback passed to the win32 api
'We CANNOT throw an error or break. Bad things will happen
On Error Resume Next
Dim l_handle As Long
Dim s_buffer As String
Dim b_visible As Boolean
Dim i_bufferLength As Integer
s_buffer = String$(32, 0)
i_bufferLength = apiGetClassName(hWnd, s_buffer, Len(s_buffer))
If Left(s_buffer, i_bufferLength) = DLG_CLSID Then
b_visible = apiShowWindow(hWnd, SW_HIDE)
WinEventFunc = hWnd
End If
End Function
In your VBA code, when you want to save your excel workbook as PDF, you would call above macros like this:
' ADD WINDOWS EVENT HOOK BEFORE SAVING:
Application.Run XL_WB.Name & "!StartEventHook"
' SAVE EXCEL AS PDF:
' https://msdn.microsoft.com/de-de/library/microsoft.office.tools.excel.worksheetbase.exportasfixedformat.aspx
XL_WB.ExportAsFixedFormat _
Type:=xlTypePDF, _
Filename:="C:\PDF.pdf", _
Quality:=xlQualityStandard, _
IncludeDocProperties:=True, _
IgnorePrintAreas:=False, _
OpenAfterPublish:=False
' REMOVE WINDOWS EVENT HOOK AFTER SAVING:
Application.Run XL_WB.Name & "!StopEventHook"
In the above VBA code example "XL_WB" is a variable. You have to adjust it to your needs. For example use "ActiveSheet" instead.
From following other websites users also asked for help with that particular problem:
https://social.msdn.microsoft.com/Forums/office/en-US/e6078904-0715-46a2-8937-c38626464425/exportasfixedformat-progress-bar-can-you-hide-it?forum=exceldev
http://www.vbaexpress.com/forum/archive/index.php/t-41431.html
http://www.excelbanter.com/showthread.php?t=446463
...

Clearing office clipboard so that copied data is not shared with other office programs

I am kind of stuck with implementing the important feature which requires data to be cleared from office clipboard the moment it is copied.
The intention is not to share the contents with other office programs e.g. word, powerpoint etc. the scenario is that I have some important content in my excel sheet. Once I make a copy of it, it is soon available on office clipboard. if I keep copying the stuff in excel, it keeps collecting in other office programs. However, the windows clipboard would contain only the recent enter which can be cleared using
System.Windows.Forms.Clipboard.clear():
Is there a way out to clear the office clipboard to?
I googled and found out that there may not be a clear cut solution to the program but getting office clipboard window with the help of FindWindowEx(....) should be possible and then message to can be sent in order to clear the contents. It seems that I am not able to get it this way.
can someone tell if they have experienced the same problem?
This might give you a nudge in the right direction... Taken From: mrexcel.com
Option Explicit
Sub myClr()
'Put this sub inta a Sheet Module, like: Sheet1.
Call ClearOfficeClipboard
End Sub
'Put the code from here down into a Standard Module, like Module1.
Private Declare Function FindWindowEx Lib "user32.dll" _
Alias "FindWindowExA" (ByVal hWnd1 As Long, _
ByVal hWnd2 As Long, ByVal lpsz1 As String, _
ByVal lpsz2 As String) As Long
Private Declare Function PostMessage Lib "user32.dll" Alias _
"PostMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, _
ByVal wParam As Long, ByVal lParam As Long) As Long
Private Const WM_LBUTTONDOWN As Long = &H201&
Private Const WM_LBUTTONUP As Long = &H202&
'creates a long variable out of two words
Private Function MakeLong(ByVal nLoWord As Integer, ByVal nHiWord As Integer) As Long
MakeLong = nHiWord * 65536 + nLoWord
End Function
Sub ClearOfficeClipboard()
Dim hMain&, hExcel2&, hWindow&, hParent&
Static sTask As String
'****Dim hClip As Long************************'changed by Lary
Dim octl, bScreenUpdatingIsOn As Boolean
Static lParameter As Long, bNotFirstVisibleTime As Boolean, hClip As Long, bNotFirstTime As Boolean
If Not (bNotFirstTime) Then
lParameter = MakeLong(120, 18)
sTask = Application.CommandBars("Task Pane").NameLocal
'Handle for XLMAIN
hMain = Application.hwnd
bNotFirstTime = True
End If
With Application.CommandBars("Task Pane")
If Not .Visible Then
'assume have to force the window if it is not visible, since it appears that
' the window class does not remain loaded if you clear a non-visible clipboard
'determine current status of screenupdating so that this sub does not change it
bScreenUpdatingIsOn = Application.ScreenUpdating
If bScreenUpdatingIsOn Then Application.ScreenUpdating = False
Set octl = Application.CommandBars(1).FindControl(ID:=809, recursive:=True)
If Not octl Is Nothing Then octl.Execute
.Visible = False
'return to screenupdating on if that is what it was in the beginning
If bScreenUpdatingIsOn Then Application.ScreenUpdating = True
If hClip = 0 Then
hParent = hMain: hWindow = 0
hWindow = FindWindowEx(hParent, hWindow, "MsoWorkPane", vbNullString)
If hWindow Then
hParent = hWindow: hWindow = 0
hClip = FindWindowEx(hParent, hWindow, "bosa_sdm_XL9", vbNullString)
End If
End If
Else
If Not (bNotFirstVisibleTime) Then** 'find hClip if window is visible
Do
hExcel2 = FindWindowEx(hMain, hExcel2, "EXCEL2", vbNullString)
hParent = hExcel2: hWindow = 0
hWindow = FindWindowEx(hParent, hWindow, "MsoCommandBar", sTask)
If hWindow Then
hParent = hWindow: hWindow = 0
hWindow = FindWindowEx(hParent, hWindow, "MsoWorkPane", vbNullString)
If hWindow Then
hParent = hWindow: hWindow = 0
hClip = FindWindowEx(hParent, hWindow, "bosa_sdm_XL9", vbNullString)
If hClip > 0 Then
Exit Do
End If
End If
End If
Loop While hExcel2 > 0
bNotFirstVisibleTime = True
End If
End If
End With
If hClip = 0 Then
MsgBox "Cant find Clipboard window"
Exit Sub
End If
Call PostMessage(hClip, WM_LBUTTONDOWN, 0&, lParameter)
Call PostMessage(hClip, WM_LBUTTONUP, 0&, lParameter)
End Sub
The code below has been customized for Excel 2013 in vb.net. Just add a button to your ribbon and code works like a charm.
Private Const WM_LBUTTONDOWN As Long = &H201&
Private Const WM_LBUTTONUP As Long = &H202&
WithEvents oAppWD As Excel.Application
Public oDoc As Excel.Workbook
Private Declare Sub Sleep Lib "kernel32.dll" (ByVal dwMilliseconds As Int32)
Private Declare Function FindWindowEx Lib "user32.dll" Alias "FindWindowExA" (ByVal hWnd1 As Int32, ByVal hWnd2 As Int32, ByVal lpsz1 As String, ByVal lpsz2 As String) As Int32
Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Int32
Private Declare Function PostMessage Lib "user32.dll" Alias "PostMessageA" (ByVal hWnd As Int32, ByVal wMsg As Int32, ByVal wParam As Int32, ByVal lParam As Int32) As Int32
Declare Function BringWindowToTop Lib "user32" (ByVal hWnd As Int32) As Int32
Private Sub Button1_Click(sender As Object, e As RibbonControlEventArgs) Handles Button1.Click
Dim hMain As Int32, hWord As Int32, hClip As Int32, hWindow As Int32, hParent As Int32
Dim lParameter As Int32
Dim sTask As String
Dim HWND As Int32
'Open the selected File
oAppWD = Globals.ThisAddIn.Application 'DirectCast(System.Runtime.InteropServices.Marshal.GetActiveObject("Excel.Application"), Excel.Application)
oAppWD.Visible = True
oDoc = oAppWD.ActiveWorkbook
oDoc.Activate()
oDoc.Windows(1).Activate()
Sleep(2000)
' MessageBox.Show("Doing it.....")
HWND = FindWindow("XLMAIN", vbNullString)
' Make Office Clipboard Visible
oAppWD.CommandBars("Office Clipboard").Visible = True
BringWindowToTop(HWND)
' Get the handles of the respective Windows Of the Office
sTask = "Office Clipboard"
hMain = HWND
hWord = FindWindowEx(hMain, 0, "EXCEL2", vbNullString)
hParent = hWord : hWindow = 0
hWindow = FindWindowEx(hParent, 0, "MsoCommandBar", sTask)
If hWindow Then
hParent = hWindow : hWindow = 0
hWindow = FindWindowEx(hParent, 0, "MsoWorkPane", vbNullString)
If hWindow Then
hParent = hWindow : hWindow = 0
hClip = FindWindowEx(hParent, 0, vbNullString, "Collect and Paste 2.0")
End If
End If
If hClip = 0 Then
MsgBox("Cant find Clipboard window")
Exit Sub
End If
' Pass the message 120,18 are the respective co-ordinates of the Clear all button.
lParameter = MakeLong(120, 18)
' Send the Message
Call PostMessage(hClip, WM_LBUTTONDOWN, 0&, lParameter)
Call PostMessage(hClip, WM_LBUTTONUP, 0&, lParameter)
Sleep(100)
End Sub
Private Function MakeLong(ByVal nLoWord As Integer, ByVal nHiWord As Integer) As Int32
MakeLong = nHiWord * 65536 + nLoWord
End Function

Categories