CommandBar / RibbonBar issue with Outlook 2016 and VB6 - plugins

I am trying to revive / recompile an old Outlook Plugin that was written in VB6 however I am getting an error seemingly related to setting a button on the Ribbon bar. Just cannot work out why and would appreciate any feedback / guidance.
The Plugin still works fine on Outlook 2003 on Windows 7 for both x86 and x64
The issue though is trying to recompile it so I can tweak it and also have it run with the more recent versions of Outlook name 2013 - 2018
In compiling I am getting - Error in loading DLL for xxxx.CommandBars ( Lines 40 and I presume also 70 )
Public Function CreateTSEButton() As Boolean
10 On Error GoTo CreateTSEButton_Error
20 If Not objExplorer Is Nothing Then
Dim mCommandBar As CommandBar
30 On Error Resume Next
40 Set mCommandBar = objExplorer.CommandBars("E-mail")
50 On Error GoTo 0
60 If mCommandBar Is Nothing Then
70 Set mCommandBar = objExplorer.CommandBars("Standard")
80 End If
90 If mCommandBar Is Nothing Then Exit Function
'Command Bar Initialized, Now Find the Control First
Dim mControl As Object
100 For Each mControl In mCommandBar.Controls
110 If UCase$(Trim$(TypeName(mControl))) = UCase$(Trim$("CommandBarButton")) Then
120 If UCase$(Trim$(mControl.Caption)) = UCase$(Trim$(IDS_TSE_ON)) Or UCase$(Trim$(mControl.Caption)) = UCase$(Trim$(IDS_TSE_OFF)) Then
'Button Found
130 Set mTSEButton = mControl
140 Exit For
150 End If
160 End If
170 Next
180 If Not mTSEButton Is Nothing Then
190 Call UpdateButtonStatus
200 Else
210 Set mTSEButton = mCommandBar.Controls.add(msoControlButton, , , , True)
220 mTSEButton.Style = msoButtonIconAndCaption
230 mTSEButton.BeginGroup = True
240 mTSEButton.Enabled = True
250 mTSEButton.Visible = True
260 Call UpdateButtonStatus
270 End If
280 Set mControl = Nothing
290 Set mCommandBar = Nothing
300 End If
310 Exit Function
CreateTSEButton_Error:
Definitions ;
Private WithEvents objOLApp As Outlook.Application
Private WithEvents colInspectors As Outlook.Inspectors
Private WithEvents objExplorer As Outlook.Explorer
Private WithEvents mTSEButton As Office.CommandBarButton
References (image grab);
screen grab of the references list
I have done a lot of hunting around and a bunch of reading and from what I have seen Microsoft moved to a XML type model along the lines of CodeJock if that name rings a bell.
The code in the plugin is solid, I just cannot compile it due to the above error which if having to guess relates to the new XML format that should be used for 2013 onwards ?
I do have a couple of other VB6 apps here that use CodeJock for the Ribbon bar so they are self contained and work fine in VB6 so I can see what goes on there.
However tapping into Outlook and from the VB6 code and adding / interacting with a button in the Outlook Command bar or Ribbon bar as I think it is now called is not working for me.
My questions (or requests for help) fall around the following ( I'm not very clued up on Outlook interfacing );
a) has "Outlook.Explorer" been replaced with something else so it is just a matter of using what the new whatever is ?
b) I have read about IDTExtensibility2 but not sure how that factors in if at all
c) Do I actually have to rewrite the code completely for placing button on the Ribbon Bar / Command Bar of Outlook 2013 + and if so could you point me to an example please for VB6 and Outlook 2013 or 2016 etc as I am having trouble finding anything.
I would prefer not to have to rewrite this VB6 code in VB.Net if I can help it.
Thanks

Note that there is no way to load a 32-bit DLL into a 64-bit process (and vice versa).
I'm pretty sure VB 6.0 runtime files are 32-bit. So your Outlook 2016 should be 32-bit as well. The reason it works okay with Outlook 2003 is because Outlook 2003 is a 32-bit application.
A possible solution would be either (1) or (2) as listed below:
rebuild this plugin under VB.Net to get 64-bit binary
use 32-bit version of Outlook 2013 - 2016

You need to rewrite your code that accesses the command bars in Outlook with XML based ribbons. You'd be better off creating a new VSTO addin in VB.Net - that will let you use the built-in Ribbon designer.
See https://learn.microsoft.com/en-us/visualstudio/vsto/walkthrough-creating-your-first-vsto-add-in-for-outlook?view=vs-2019

Related

AutoHotKey / SendMessage/ How should i retrieve the corresponding number of an action for a specific control with sendmessage

I'd like to select a date in my calendar with a AHK script.
For this, i'm using the function sendMessage because i'd like to select a date from an external app.
I'd like to use the SETCURSEL_MCM message from Microsoft documentation.
How could i find the corresponding number from this message ? Bc it's not on this page
https://learn.microsoft.com/en-us/windows/win32/controls/mcm-setcursel
SendMessage, myCorrespondingNumberAsParam???, 0, lparam(which is my date),control, wintitle
By analogy, if i want to send a text to an edit control in notepad, i should send the WM_SETTEXT. The value of this message is clearly referenced by ahk doc as 12 for that control. But it's not the case for MCM_SETCURSEL message.
I tried to put the send message in a loop, an stop the loop when it executed the message, but it's too long, and it send bugs to the program.
If anyone could help me,
Thank you,
Gilles
You see from the documentation that this message is defined in the Commctrl.h header.
So you want to open that header from your Windows SDK files, the path might be e.g.
C:\Program Files (x86)\Windows Kits\10\Include\10.0.19041.0\um, but really I recommend just using some proper Windows search engine (such as Everything), and searching that header name to find it quickly.
Then you'll see in that header that the message is defined as follows:
#define MCM_FIRST 0x1000
// BOOL MonthCal_GetCurSel(HWND hmc, LPSYSTEMTIME pst)
// returns FALSE if MCS_MULTISELECT
// returns TRUE and sets *pst to the currently selected date otherwise
#define MCM_GETCURSEL (MCM_FIRST + 1)
#define MonthCal_GetCurSel(hmc, pst) (BOOL)SNDMSG(hmc, MCM_GETCURSEL, 0, (LPARAM)(pst))
// BOOL MonthCal_SetCurSel(HWND hmc, LPSYSTEMTIME pst)
// returns FALSE if MCS_MULTISELECT
// returns TURE and sets the currently selected date to *pst otherwise
#define MCM_SETCURSEL (MCM_FIRST + 2)
#define MonthCal_SetCurSel(hmc, pst) (BOOL)SNDMSG(hmc, MCM_SETCURSEL, 0, (LPARAM)(pst))
And there's your value, 0x1000 + 2.

DN4800/MELDAS 500 CNC machine ATC problem

I've got a DN4800 CNC machine with MELDAS 500 control.
When I tried to use the ATC for changing to a specific tool, for example, T10 M6, the ATC didn't move, it's stuck and the control panel gives me this failure code:
P290 IF SNT. ERROR MDI EDIT
I looked in many Mitsubishi manuals and found this:
But I don't know what 'Reconsider the program' even mean
Any suggestions?

Order of events reversed 'Ribbon_Load' and 'ThisAddin_Startup' Word VSTO Add-in. (Build 8201.2025 onwards)

As of Build 8201.2025 there has been an unexpected change to the order of events when loading a VSTO addin with a Ribbon in Word.
Using Office version 16.0.8067.2115 or older. When loading the addin the following order of events is observed (as has always been the case).
Ribbon_Load event
ThisAddin_Startup event
Using Office versions 8201.2025, 8201.2064 or 8201.2075 or newer the order of events is reversed which is an unexpected breaking change.
ThisAddin_Startup event
Ribbon_Load event
I have created a simple VSTO Addin using a Visual Designer Ribbon to demonstrate the issue.
>
Public Class Ribbon1
Private Sub Ribbon1_Load(ByVal sender As System.Object, ByVal e As RibbonUIEventArgs) Handles MyBase.Load
System.Diagnostics.Debug.Write("Ribbon1_Load event called.")
'Pass the Ribbon to the Addin.
ThisAddIn.MyRibbon = Me
End Sub
End Class
Public Class ThisAddIn
Public Shared Property MyRibbon As Ribbon1 = Nothing
Private Sub ThisAddIn_Startup() Handles Me.Startup
Debug.Write("ThisAddin_Startup Called")
If (MyRibbon Is Nothing) Then
Debug.Write("MyRibbon is nothing - the ribbon was not captured.")
Else
Debug.Write("Ribbon captured successfully.")
End If
End Sub
End Class
Debug output for 16.0.8067.2115 32 bit
[7772] Ribbon1_Load event called.
[7772] ThisAddin_Startup Called
[7772] Ribbon captured successfully.
Debug output for 16.0.8201.2075 32 bit
[13556] ThisAddin_Startup Called
[13556] MyRibbon is nothing - the ribbon was not captured.
[13556] Ribbon1_Load event called
I have posted this up on the Microsoft Support forums however they have stopped responding and since released this version to the Current office channel I need help from the dev community.
Has anyone found a successful workaround? This change of timing is causing alot of problems with how we initialise. It would be ideal for Microsoft Support to provide a solution or workaround until they investigate this bug.
I always got Ribbon_Load before ThisAddin_Startup because I use Ribbon XML. Ribbon UI allow less controls ... As the both are "entry" points, I suggest you to use only Ribbon1_Load at startup. Or, if you use the Ribbon XML model and you want the very very first entry point, try its constructor
I am not feeling that issue as a bug, to make Word fast many processes are asynchronous. So, in my opinion, the first of ThisAddin_Startup or Ribbon1_Load to start can accidentally change depending on many factors: System performances, Word started alone, Word started via a doc ...
Hope this helps someone! We used the following workaround successfully to work around the changed office load behavior.
Within ThisAddIn_Startup loop until the Ribbon load event has fired and the ribbon is captured.
While m_oRibbon Is Nothing
If (timeWaited >= MAX_WAIT_TIME) Then
Exit Try
End If
Threading.Thread.Sleep(50)
timeWaited = timeWaited + 50
End While

EF6/Code First: Super slow during the 1st query, but only in Debug

I'm using EF6 rc1 with Code First strategy, without precompiled views and the problem is:
If I compile and run the exe application it takes like 15 seconds to run the first query (that's okay, since I'm still working on the pre-generated views). But if I use Visual Studio 2013 Preview to Debug the exact same application it takes almost 2 minutes BEFORE running the first query:
Dim Context = New MyEntities()
Dim Query = From I in Context.Itens '' <--- The debug takes 2 minutes in here
Dim Item = Query.FirstOrDefault()
Is there a way to remove this extra time? Am I doing something wrong here?
Ps.: The context itself is not complicated, its just full with 200+ tables.
Edit: Found out that the problem is that during debug time the EF appears to be generating the Views ignoring the pre-generated ones.
Using the source code from EF I discovered that the property:
IQueryProvider IQueryable.Provider
{
get
{
return _provider ?? (_provider = new DbQueryProvider(
GetInternalQueryWithCheck("IQueryable.Provider").InternalContext,
GetInternalQueryWithCheck("IQueryable.Provider").ObjectQueryProvider));
}
}
is where the time is being consumed. But this is strange since it only takes time in debug. Am I missing something here?
Edit: Found more info related to the question:
Using the Process Monitor (by Sysinternals) I found out that there its the 'desenv.exe' process that is consuming tons of time. To be more specific its consuming time with an 'Thread Exit'. It repeats the Thread Exit stack 36 times. I don't know if this info is very useful, but I saved a '.cvs' with the stack, here is his body: [...] (edit: removed the '.cvs' body, I can post it again by the comments if someone really think its going to be useful, but it was confusing and too big.)
Edit: Installed VS2013 Ultimate and Entity Framework 6 RTM. Installed the Entity Framework Power Tools Beta 4 and used it to generate the Views. Nothing changed... If I run the exe it takes 20 seconds, if I 'Start' debugging it takes 120 seconds.
Edit: Created a small project to simulate the error: http://sdrv.ms/16pH9Vm
Just run the project inside the environment and directly through the .exe, click the button and compare the loading time.
This is a known performance issue in Lazy (which EF is using) when the debugger is attached. We are currently working on a fix (the current approach we are looking at is removing the use of Lazy). We hope to ship this fix in a patch release soon. You can track progress of this issue on our CodePlex site - http://entityframework.codeplex.com/workitem/1778.
More details on the coming 6.0.2 patch release that will include a fix are here - http://blogs.msdn.com/b/adonet/archive/2013/10/31/ef6-performance-issues.aspx
I don't know if you have found the solution. But in my case, I had similar issue which wasted me close to a week after trying different suggestions. Finally, I found a solution by changing my web.config to optimizeCompilations="true" and performance improved dramatically from 15-30 seconds to about 2 seconds.

Crystal Reports Exception: The maximum report processing jobs limit configured by your system administrator has been reached

I'm facing a very buggy issue, in ASP.NET application after viewing the same report many times simultaneously I got this exception:
The maximum report processing jobs limit configured by your system
administrator has been reached.
Wait I know there are tons of solutions out there but all of them are not working with me.
I put ReportDocument.Close(); ReportDocument.Dispose(); in CrystalReportViewer_Unload event, and still throw the exception.
Private Sub CrystalReportViewer1_Unload(ByVal sender As Object, ByVal e As System.EventArgs) Handles CrystalReportViewer1.Unload
reportFile.Close()
reportFile.Dispose()
GC.Collect()
End Sub
I edit the PrintJobLimit registry in HKEY_LOCAL_MACHINE\SOFTWARE\SAP BusinessObjects\Crystal Reports for .NET Framework 4.0\Report Application Server\InprocServer and HKEY_LOCAL_MACHINE\SOFTWARE\SAP BusinessObjects\Crystal Reports for .NET Framework 4.0\Report Application Server\Server to -1 even to 9999, and still throw the exception.
Here is the code snippet where I call my report:
Table_Infos = New TableLogOnInfos()
Table_Info = New TableLogOnInfo()
Con_Info = New ConnectionInfo()
With Con_Info
.ServerName = ConfigurationManager.AppSettings("server_name")
.DatabaseName = ConfigurationManager.AppSettings("DB")
.UserID = user_name
.Password = pass_word
.Type = ConnectionInfoType.SQL
.IntegratedSecurity = False
End With
Table_Info.ConnectionInfo = Con_Info
If Session("recpt_lang") = "Arabic" Then
reportFile.Load(Server.MapPath("/Reports/") & "collectrecpt_new_ar.rpt")
ElseIf Session("recpt_lang") = "English" Then
reportFile.Load(Server.MapPath("/Reports/") & "collectrecpt_new.rpt")
End If
For Each mytable In reportFile.Database.Tables
mytable.ApplyLogOnInfo(Table_Info)
Next
CrystalReportViewer1.ReportSource = reportFile
CrystalReportViewer1.SelectionFormula = Session("SelectionForumla")
CrystalReportViewer1 = Nothing
You have to Dispose your report instance after all.
If you Dispose the report after showing it, you will never see the error "The maximum report processing jobs limit configured by your system administrator has been reached" again.
Dim report1 As rptBill = clsBill.GetReport(billNumber)
rpt.Print()
'Cleanup the report after that!
rpt.Close()
rpt.Dispose()
I would recommend moving your close/dispose/gc.collect code outside of that unload process. In other words:
Load report
Assign to Viewer Control
Show Report in Viewer Control
Close Viewer Control and Unload (completely)
Then close/dispose/gc.collect outside of any viewer control code
My guess is the viewer control is not completely closed when the report is being cleaned up.
Crystal is a very memory intensive process and very finicky.
Crystal Report document implements IDisposable interface. So all you have to do is to enclose the report's instance with using statement. It will be automatically closed and disposed once the using statement is completed. You can write something like that:
using(var report = GetInvoiceReport())
{
// your logic here
}
or (depends on your context):
using(var report = new ReportDocument())
{
// your logic here
}
Greetings I am too late to have answer on it,
all reply are working and i have seen but in case still you are facing same problem and error then please once go in to TEMP folder under "windows" directory and delete all instances of crystal report.
I am saying this because all above option will work but you are still in the maximum reach so first of all delete all instance then apply all the above suggestion.
thanks
Make sure you are using PUSH model to display your reports. Next you have to make one change in your Server's registry: Follow the path:
"HKEY_LOCAL_MACHINE\SOFTWARE\SAP BusinessObjects\Crystal Reports for .NET Framework 4.0\Report Application Server\InprocServer"
and you will see an item " PrintJobLimit" and you will see that its default value is 75. that means the server can only handle 75 reports at a time.
Dont worry about that and just modify the value to -1
Make sure IIS user have sufficient permission to delete files present in "c:/windows/temp" folder.
I face the same issue once I provide write permission to that folder then it solved my issue.Also make sure dispose that object after generating the file
I was working on local report server. I have hosted my web application in other pc. When I got such error I just did IISRESET and working fine now.
Try this, this could help you.
You have to Dispose your report instance after all. If you Dispose the report after showing it, you will never see the error:
The maximum report processing jobs limit configured by your system administrator has been reached
Code:
Dim report1 As rptBill = clsBill.GetReport(billNumber)
rpt.Print()
'Cleanup the report after that!
rpt.Close()
rpt.Dispose()
In my case, the report had 4 subreports...
What solved for me was changing the value of "PrintJobLimit", from 75 to 500, in the following Regedit paths:
\HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\SAP BusinessObjects\Crystal Reports for .NET Framework 4.0\Report Application Server\InprocServer
\HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\SAP BusinessObjects\Crystal Reports for .NET Framework 4.0\Report Application Server\Server
I know this thread is older, but if you configure the app pool setting "Recycling..." to recycle at, say, 180 minutes instead of 1740 minutes (the default), this might free up the needed resources.
Use These methods when unload the page
ReportDocument crystalReport;
protected void Page_Unload(object sender, EventArgs e)
{
if (crystalReport != null)
{
crystalReport.Close();
crystalReport.Dispose();
}
}
OR
protected void Page_Unload(object sender, EventArgs e)
{
if (crystalReport != null)
{
crystalReport.Close();
crystalReport.Clone();
crystalReport.Dispose();
crystalReport = null;
GC.Collect();
GC.WaitForPendingFinalizers();
}
}
I ended up using GC.WaitForPendingFinalizers in addition to the GC.Collect, close and dispose. I believe my web page was perhaps unloading and stopping thread processing prematurely before the garbage was properly processed (really?)
This is on Server 2012, SQL 2012, CR 13.0.2000.0
Here's my code:
#Region "Cleanup"
Private Sub crCleanup(Optional blnForce As Boolean = False)
Try
' Crystal(code Is Not managed, i.e.it) 's COM interop => you have to manually
' release any objects instantiated. Make sure you set the ref to nothing and
' also call the dispose method if it has one.
' under some conditions, we don't want to destroy the ReportDocument (e.g. report page-to-page navigation)
If blnForce OrElse Me.blnPageHasFatalError OrElse (Not Me.CrystalUseCache) Then ' do not release when using cache! (unless forced)
If Not crReportDocument Is Nothing Then Me.crReportDocument.Close()
If Not crReportDocument Is Nothing Then Me.crReportDocument.Dispose()
If Not thisWebAppUser Is Nothing Then Me.thisWebAppUser.Dispose()
Me.thisWebAppUser.ClearReportCache() ' we are using HttpContext.Current.Cache.Item instead of sessions to save CR document
End If
' the rest of the items, we'll always want to clean up
If Not crParameterFieldDefinitions Is Nothing Then crParameterFieldDefinitions.Dispose()
If Not crParameterFieldDefinition Is Nothing Then crParameterFieldDefinition.Dispose()
crParameterFields = Nothing
crParameterField = Nothing
crParameterFieldName = Nothing
crParameterValues = Nothing
crParameterDiscreteValue = Nothing
crParameterDefaultValue = Nothing
crParameterRangeValue = Nothing
'
If Not crSections Is Nothing Then crSections.Dispose()
If Not crSection Is Nothing Then crSection.Dispose()
If Not crReportObjects Is Nothing Then crReportObjects.Dispose()
If Not crReportObject Is Nothing Then crReportObject.Dispose()
If Not crSubreportObject Is Nothing Then crSubreportObject.Dispose()
If Not crDatabase Is Nothing Then crDatabase.Dispose()
If Not crTables Is Nothing Then crTables.Dispose()
If Not crTable Is Nothing Then crTable.Dispose()
crLogOnInfo = Nothing
crConnInfo = Nothing
crDiskFileDestinationOptions = Nothing
ConnParam = Nothing
If Not subRepDoc Is Nothing Then subRepDoc.Dispose()
Catch ex As Exception
Me.thisWebAppUser.SendSysAdminMessage("Failed CR cleanup", ex.ToString)
End Try
' yes, use of the GC.Collect (and even more the GC.WaitForPendingFinalizers) is highly controversial
'
' the reality is that rendering crystal reports is rather slow compared to most web operations
' so it is expected that waiting for GC will have relatively little performance impact
' and will in fact, help tremendously with memory management.
'
' try setting these values to 1 and confirm for yourself by instantiating multiple crDocuments in different browsers if you don't believe it:
'
' HKEY_LOCAL_MACHINE\SOFTWARE\SAP BusinessObjects\Crystal Reports for .NET Framework 4.0\Report Application Server\InprocServer
' HKEY_LOCAL_MACHINE\SOFTWARE\SAP BusinessObjects\Crystal Reports for .NET Framework 4.0\Report Application Server\Server
'
' or google this error: The maximum report processing jobs limit configured by your system administrator has been reached
'
' I believe the problem is that on very fast servers, the page unloads and stops processing code to properly cleanup the Crystal Report objects
'
' This is done in 3 places:
' Report Viewer (Page_Unload and CrystalReportViewer1_Unload) rendering a report will of course always using a processing job
' Report Parameter Selector (Page_Unload) loading a crDocument without rendering a report still counts towards CR processing job limit.
' Custom Control crReportParameterSelectionTable (Public Overrides Sub dispose())
GC.Collect()
GC.WaitForPendingFinalizers()
End Sub
'***********************************************************************************************************************************
'
'***********************************************************************************************************************************
Private Sub Page_Unload(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Unload
'If Me.IsCallback Then Exit Sub ' the menutree causes callbacks, but we are not interested
crCleanup()
' response object not available here, so cannot redirect (such as in the case of XLS opeing in a separate window)
' if for some crazy reason there is STILL a crReportDocument, set it to nothing
' If Not crReportDocument Is Nothing Then Me.crReportDocument = Nothing
' Me.CrystalReportViewer1 = Nothing
End Sub
Private Sub CrystalReportViewer1_Unload(ByVal sender As Object, ByVal e As System.EventArgs) Handles CrystalReportViewer1.Unload
'If Me.IsCallback Then Exit Sub ' the menutree causes callbacks, but we are not interested
crCleanup()
End Sub
End Region