Show Access Report in dialog - c#

I want to show a Access Report without showing the MainForm from Access. I want to show it in a Dialog or something like that. I can show a report but with opening the Main Window of Access:
_access.DoCmd.OpenReport(
"myReport", //ReportName
AcView.acViewReport, //View
System.Reflection.Missing.Value,
"my Where Condition"
);
But this opens Access all the time. I only want to see my Report in a Dialog. Even when I set the AcWindowMode.acDialog property it opens Access behind it.
I also know that I can save it as PDF and open this. But this is not possible in my case.
Is there a way to show a Access Report in a Dialog without showing (or hiding) the Access Main Window behind it?

You can do it this way:
First, in the access application, set the interface to tabbed. and un-check show tabs.
Now write a code stub in a standard code module in Access.
Say like this:
Sub RunMyReport(s As String)
DoCmd.ShowToolbar "Ribbon", acToolbarNo
' now launch report
DoCmd.OpenReport "qryHotels", acViewReport
End Sub
Now, your .net code will look like this
(I not even bothering with interop - it don't help much).
You have this .net code:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim objAccess As Object = CreateObject("Access.Application")
objAccess.OpenCurrentDatabase("C:\test\test44.accdb")
objAccess.Run("RunMyReport", "qryHotels")
objAccess.Visible = True
End Sub
And the results will now look like this:
note the vb form that launched the form.
Note the Access report,
it shows no ribbon or background interface.
And note that we get to pass the report name to the given routine.
Now you likely could move the VBA code of this:
DoCmd.ShowToolbar "Ribbon", acToolbarNo
' now launch report
DoCmd.OpenReport "qryHotels", acViewReport
To the .net side, and not even have to call a VBA routine.
Dim objAccess As Object = CreateObject("Access.Application")
objAccess.OpenCurrentDatabase("C:\test\test44.accdb")
objAccess.DoCmd.ShowToolbar("Ribbon", 2) ' acToolbarNo = 2
objAccess.DoCmd.OpenReport("qryHotels", 5) ' acViewReport = 5
objAccess.Visible = True
So, in fact we don't need the VBA helper function, and we can open any report. The command to hide the ribbon works, and the other settings (hide nav pane, and tabbed interface is to be set in the access application).
So above should work. Given it only a few lines of vb.net code, then as c#, it should be easy to convert. Eg this should work:
{
var objAccess = Interaction.CreateObject("Access.Application");
objAccess.OpenCurrentDatabase(#"C:\test\test44.accdb");
objAccess.DoCmd.ShowToolbar("Ribbon", 2); // acToolbarNo = 2
objAccess.DoCmd.OpenReport("qryHotels", 5); // acViewReport = 5
objAccess.Visible = true;
}
You can consider the inter-op assemblies, as that can help in intel-sense, but above is written without any references to office or use of the inter-op assemblies.

Related

How to click button in MS Access using C# and Office Interop?

I am trying to automate some tasks in MS Access which are involving some button presses. Here are my best guesses so far, but I never find a way to finally execute a click...
using Microsoft.Office.Interop.Access;
Application access = new Application();
access.OpenCurrentDatabase("SomeDatabaseName.accdb");
access.DoCmd.OpenForm("SomeFormName", AcFormView.acNormal);
access.DoCmd.GoToControl("SomeButtonName");
access.DoCmd... // I can go to the control, but how do I click it?
Or maybe there is another approach using the Microsoft.Office.Interop.Access.CommandButton instance?
var form = access.Forms["SomeFormName"];
foreach (var control in form.Controls)
{
if (control is CommandButton button)
{
// I can get the CommandButton, but how do I execute the click procedure?
string onClick = button.OnClick; // it's just this string: "[Event Procedure]"
}
}
access.CloseCurrentDatabase();
access.Quit(AcQuitOption.acQuitSaveNone);
Is this possible using the MS Office Interop assemblies? Or are there any alternatives? Unfortunately, these interop assemblies are very poorly documented.
You can use the CommandBars.ExecuteMso method which executes the control identified by the idMso parameter. This method is useful in cases where there is no object model for a particular command. Works on controls that are built-in buttons, toggleButtons, and splitButtons. On failure it returns E_InvalidArg for an invalid idMso, and E_Fail for controls that are not enabled or not visible. For example:
Application.CommandBars.ExecuteMso("Copy")
If you need to execute non-ribbon controls you may consider using Windows API functions or Accessibility API for that.

load bloomberg page from c#

I have an old excel workbook that I am trying to replace with a c# application. The only bit of functionality that I have not been able to replicate is the code below.
So the code below takes a bloomberg ticker (i.e. "VOD LN") and then with DDEInitiate it loads the bloomberg page.
I have read that C# doesn't support DDE or even if it does it is best avoided. In which case how can I do this via C#?
Public Sub LoadBbergPage(string ticker)
' loads bberg page
Dim strExe As String
Dim channelGP As Long
channelGP = DDEInitiate("Winblp", "BBK")
strExe = "<blp-2><home>" & Strings.Trim(ticker) & "<EQUITY><GO>"
DDEExecute channelGP, strExe
DDETerminate channelGP
End Sub
If you're trying to make it easier for your users to launch data into the terminal, you can use 'B-links'. Access it like any other web link. Below is an example for "IBM US Equity" - replace spaces with %20
https://blinks.bloomberg.com/securities/[ticker]/[function]
https://blinks.bloomberg.com/securities/IBM%20US%20Equity/DES
It will ask the user the first time to allow / remember settings and then should launch to terminal. If there are issues, you can go to https://blinks.bloomberg.com/help. Documentation is available on terminal via DOCS BLINKS<GO> (tons more special syntax)
But if you're trying to do some kind of screen scraping etc via DDE, don't bother; just use the Reference Data API instead: https://www.bloomberg.com/professional/support/api-library/

Screenshot of VBA editor in debug mode in terminal, or use Excel DOM to find error line and desc in VBA editor?

An Excel workbook is called by a command line, which itself is launched from c# (3.5). The workbook runs, but there is an error in the VBA. For example, a column is missing in a pivot and Excel prompts the user with an error message, with the option to "debug".
From the process in C#, we can detect that the error window is open, and we take a screenshot of the error message, and then we close the error box.
If this was an interactive session, Excel would then present the VBA editor, in debug mode, with the line where the error occurred highlighted.
However, because this is running in an unattended terminal session, we are then unable to take a screenshot of the VBA editor (the screenshot is a black screen).
We are then able to close the excel program, using the windows PID.
The questions is: how do we either get a screenshot of the VBA editor, or how do we bind (with COM or interop) with the Excel in debug mode, and traverse the dom to find the error line, and possibly error message?
(1) If you have authoring control of the Excel workbook(s), you can insert line numbers and a error handler to write to file Err.Number, Err.Description, Err.Source, Erl.
(2) If (1) is not an option, but you can set Macro Security on the host to allow programmatic control of the Visual Basic project, then you can get the active line number:
Dim xl As excel.Application
Dim StartLine As Long, StartColumn As Long, EndLine As Long, EndColumn As Long
Set xl = GetObject(, "Excel.Application")
xl.VBE.ActiveCodePane.GetSelection StartLine, StartColumn, EndLine, EndColumn
Debug.Print StartLine, StartColumn, EndLine, EndColumn
(3) If neither (1) nor (2) is an option, it is a bit hairy, but you can copy out the bitmap contents of the window: http://msdn.microsoft.com/en-us/library/windows/desktop/dd183402%28v=vs.85%29.aspx
The simplest solution if you have access to modify the VBA code might be to use On Error GoTo and a line label. This will stop the Debug message from popping up and instead, when a runtime error occurs, execution will jump to the specified label at which point you can access the information available in the global Err object. VBA does not have the concept of a try/catch block so this is pretty much the nearest proximally.
Sub Main()
On Error GoTo Catch
' Code that may trigger errors here...
GoTo Finally
Catch:
' Log Err info, etc...
Debug.Print "Error " & Err.Number & " - " & Err.Description
Finally:
' This is always reached last (error or no error)
End Sub
Snapshot of data structures, VBA excel
It sounds a lot like the question above in which I suggested to write the state of your code to a separate txt file (in the example, using a FileSystemObject) where you can afterwards analyze where you got stuck:
booleans on conditions / instantiation of objects, number on succesful loops, values contained in variables, well - whatever you want...).
In combination with an error handler (as suggested before) you can see where the code stopped + code / description of the error.
A copy-paste for your sake:
dim sFile As string
Dim FSO As FileSystemObject
Dim FSOFile As TextStream
sFile = "U:/Log.txt"
Set FSO = New FileSystemObject
Set FSOFile = FSO.OpenTextFile(sFile, 2, True)
FSOFile.writeline (<Descriptions+Property/variable value>)
FSOFile.Close set FSO = nothing
I agree that it is a more work, but you'll know where to find the bug.
All depends on how hard and often you need this, in combination with how long the code is that you need to describe. Since I am not aware of your situation, I cannot judge on that.
In the end, it seems a lot of work, but actually it's quite easy since it's just describing the code that is already there.
Hope it helps.

Bind to already opened form created using CreateObject

I was wondering if what I am trying to do is possible. I have created a C# class library which invokes a form when called from VBScript using CreateObject.
I have a VBS that passes some data to the Form and once the script is complete, obviously all references are lost. I wanted to know if there is a way for me to connect and use the existing form the next time I call the VBS script again?
Set e = CreateObject("MyObject")
'SendEvents to Form'
'Script ends.. all references lost'
'Script is run again'
Set e = CreateObject("MyObject")
'Is it possible to send events to the existing form, instead of closing it and creating new one?'
*Edit: Currently, I am using my class lib to close the existing form when the script is called again. However, I have a user request to keep it open regardless of how many times the script is called. I am not sure how I can use the existing form for the next time CreateObject is called. Is it possible?
Try it like this
Set e = CreateObject("MyObject")
'SendEvents to Form'
'Script ends.. all references lost'
'Script is run again'
Set e = GetObject(, "MyObject") 'no, the empty parameter is no typo
See http://technet.microsoft.com/en-us/library/ee176980.aspx for more info.

.NET Interop Passing VB6 Form byRef

I am trying to develop a .NET class that updates a VB6 Form and its controls with various new captions (It is in an assembly that is COM visible).
I pass a VB6 form ByRef as an object to the .NET class and then update the caption etc on the form as follows:
Public Sub AddFormRefLegacy(ByRef objForm As Object)
Try
objForm.Caption = "some new caption"
For Each ctl As Object In objForm.Controls
Select Case TypeName(ctl)
Case "Label"
ctl.caption = "some new caption"
Case "Frame"
ctl.caption = "some new caption"
Case "CommandButton", "PushButton"
ctl.caption = "some new caption"
'etc etc
This works about 85% of the time but occasioanlly I get a run time error 80131500 no such interface (E_NOINTERFACE)
I'm not sure exactly where this is throwing the error but can anyone see anything obviously wrong with this?
EDIT
The problem seems to be occurring on this section:
Case "ITabStrip" 'MS Common Controls 6
For i = 0 To ctl.Tabs.Count - 1 ' this sometimes throws the error!
ctl.Tabs(i + 1).Caption = FindValue(objForm.Name, ctl.Name, i, ctl.Tabs(i + 1).Caption)
Next
One possible problem might be that VB6 labels aren't windowed controls but are drawn on the form's window. Another possible problem is if you're using certain 3rd party controls it's likely that they're using owner draw techniques that might do unexpected things.
I'd suggest trying to narrow it down by control and see if any of them have the problem.

Categories