Im trying to get this code to work with buttons in visual basic. Ive looked on the internet and the only solutions I could find for volume controls are all written in C#. I converted this code to Visual Basic. Can someone overlook this code for me?
I was getting errors with me.handle
Imports System
Imports System.Windows.Forms
Imports System.Runtime.InteropServices
Namespace Test
Public Class Test
Private Const APPCOMMAND_VOLUME_MUTE As Integer = &H80000
Private Const APPCOMMAND_VOLUME_UP As Integer = &HA0000
Private Const APPCOMMAND_VOLUME_DOWN As Integer = &H90000
Private Const WM_APPCOMMAND As Integer = &H319
<DllImport("user32.dll")>
Public Shared Function SendMessageW(ByVal hWnd As IntPtr, ByVal Msg As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As IntPtr
Private Sub Mute()
SendMessageW(Me.Handle, WM_APPCOMMAND, Me.Handle, CType(APPCOMMAND_VOLUME_MUTE, IntPtr))
End Sub
Private Sub VolDown()
SendMessageW(Me.Handle, WM_APPCOMMAND, Me.Handle, CType(APPCOMMAND_VOLUME_DOWN, IntPtr))
End Sub
Private Sub VolUp()
SendMessageW(Me.Handle, WM_APPCOMMAND, Me.Handle, CType(APPCOMMAND_VOLUME_UP, IntPtr))
End Sub
End Class
End Namespace
In your code, Me.Handle is trying to reference a field or property called Handle on the same class (Test), but no such field or property exists.
You will need to find a way of obtaining the handle. The approach varies based on whether you are a WinForms or WPF application. If you are a console application, you will need to create a window (even if you don't show it) to participate in Windows Messages (i.e. the WM_* values you're using).
I have a form that spawns a BackgroundWorker, that should update form's own textbox (on main thread), hence Invoke((Action) (...)); call.
If in HandleClosingEvent I just do bgWorker.CancelAsync() then I get ObjectDisposedException on Invoke(...) call, understandably. But if I sit in HandleClosingEvent and wait for bgWorker to be done, than .Invoke(...) never returns, also understandably.
Any ideas how do I close this app without getting the exception, or the deadlock?
Following are 3 relevant methods of the simple Form1 class:
public Form1() {
InitializeComponent();
Closing += HandleClosingEvent;
this.bgWorker.RunWorkerAsync();
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) {
while (!this.bgWorker.CancellationPending) {
Invoke((Action) (() => { this.textBox1.Text = Environment.TickCount.ToString(); }));
}
}
private void HandleClosingEvent(object sender, CancelEventArgs e) {
this.bgWorker.CancelAsync();
/////// while (this.bgWorker.CancellationPending) {} // deadlock
}
The only deadlock-safe and exception-safe way to do this that I know is to actually cancel the FormClosing event. Set e.Cancel = true if the BGW is still running and set a flag to indicate that the user requested a close. Then check that flag in the BGW's RunWorkerCompleted event handler and call Close() if it is set.
private bool closePending;
protected override void OnFormClosing(FormClosingEventArgs e) {
if (backgroundWorker1.IsBusy) {
closePending = true;
backgroundWorker1.CancelAsync();
e.Cancel = true;
this.Enabled = false; // or this.Hide()
return;
}
base.OnFormClosing(e);
}
void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
if (closePending) this.Close();
closePending = false;
// etc...
}
I've found another way. If you have more backgroundWorkers you can make:
List<Thread> bgWorkersThreads = new List<Thread>();
and in every backgroundWorker's DoWork method make:
bgWorkesThreads.Add(Thread.CurrentThread);
Arter that you can use:
foreach (Thread thread in this.bgWorkersThreads)
{
thread.Abort();
}
I used this in Word Add-in in Control, which i use in CustomTaskPane. If someone close the document or application earlier then all my backgroundWorkes finishes their work, it raises some COM Exception(I don't remember exatly which).CancelAsync() doesn't work.
But with this, I can close all threads which are used by backgroundworkers Immediately in DocumentBeforeClose event and my problem is solved.
Here was my solution (Sorry it's in VB.Net).
When I run the FormClosing event I run BackgroundWorker1.CancelAsync() to set the CancellationPending value to True. Unfortunately, the program never really gets a chance to check the value CancellationPending value to set e.Cancel to true (which as far as I can tell, can only be done in BackgroundWorker1_DoWork).
I didn't remove that line, although it doesn't really seem to make a difference.
I added a line that would set my global variable, bClosingForm, to True. Then I added a line of code in my BackgroundWorker_WorkCompleted to check both e.Cancelled as well as the global variable, bClosingForm, before performing any ending steps.
Using this template, you should be able to close your form out at any time even if the backgroundworker is in the middle of something (which might not be good, but it's bound to happen so it might as well be dealt with). I'm not sure if it's necessary, but you could dispose the Background worker entirely in the Form_Closed event after this all takes place.
Private bClosingForm As Boolean = False
Private Sub SomeFormName_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
bClosingForm = True
BackgroundWorker1.CancelAsync()
End Sub
Private Sub backgroundWorker1_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
'Run background tasks:
If BackgroundWorker1.CancellationPending Then
e.Cancel = True
Else
'Background work here
End If
End Sub
Private Sub BackgroundWorker1_RunWorkerCompleted(ByVal sender As System.Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
If Not bClosingForm Then
If Not e.Cancelled Then
'Completion Work here
End If
End If
End Sub
Can you not wait on the signal in the destructor of the form?
AutoResetEvent workerDone = new AutoResetEvent();
private void HandleClosingEvent(object sender, CancelEventArgs e)
{
this.bgWorker.CancelAsync();
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
while (!this.bgWorker.CancellationPending) {
Invoke((Action) (() => { this.textBox1.Text =
Environment.TickCount.ToString(); }));
}
}
private ~Form1()
{
workerDone.WaitOne();
}
void backgroundWorker1_RunWorkerCompleted( Object sender, RunWorkerCompletedEventArgs e )
{
workerDone.Set();
}
Firstly, the ObjectDisposedException is only one possible pitfall here. Running the OP's code has produced the following InvalidOperationException on a substantial number of occasions:
Invoke or BeginInvoke cannot be called
on a control until the window handle
has been created.
I suppose this could be amended by starting the worker on the 'Loaded' callback rather than the constructor, but this entire ordeal can be avoided altogether if BackgroundWorker's Progress reporting mechanism is used. The following works well:
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
while (!this.bgWorker.CancellationPending)
{
this.bgWorker.ReportProgress(Environment.TickCount);
Thread.Sleep(1);
}
}
private void bgWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
this.textBox1.Text = e.ProgressPercentage.ToString();
}
I kind of hijacked the percentage parameter but one can use the other overload to pass any parameter.
It is interesting to note that removing the above sleep call clogs the UI, consumes high CPU and continually increases the memory use. I guess it has something to do with the message queue of the GUI being overloaded. However, with the sleep call intact, the CPU usage is virtually 0 and the memory usage seems fine, too. To be prudent, perhaps a higher value than 1 ms should be used? An expert opinion here would be appreciated... Update: It appears that as long as the update isn't too frequent, it should be OK: Link
In any case, I can't foresee a scenario where the updating of the GUI has to be in intervals shorter than a couple of milliseconds (at least, in scenarios where a human is watching the GUI), so I think most of the time progress reporting would be the right choice
I really dont see why DoEvents is regarded as such a bad choice in this case if you are using this.enabled = false. I think it would make it quite neat.
protected override void OnFormClosing(FormClosingEventArgs e) {
this.Enabled = false; // or this.Hide()
e.Cancel = true;
backgroundWorker1.CancelAsync();
while (backgroundWorker1.IsBusy) {
Application.DoEvents();
}
e.cancel = false;
base.OnFormClosing(e);
}
Your backgroundworker should not use Invoke to update the textbox. It should ask the UI thread nicely to update the textbox using event ProgressChanged with the value to put in the textbox attached.
During event Closed (or maybe event Closing), the UI thread remembers that the form is closed before it cancels the backgroundworker.
Upon receiving the progressChanged the UI thread checks if the form is closed and only if not, it updates the textbox.
This won't work for everyone, but if you are doing something in a BackgroundWorker periodically, like every second or every 10 seconds, (perhaps polling a server) this seems to work well to stop the process in an orderly manner and without error messages (at least so far) and is easy to follow;
public void StopPoll()
{
MyBackgroundWorker.CancelAsync(); //Cancel background worker
AutoResetEvent1.Set(); //Release delay so cancellation occurs soon
}
private void bw_DoWork(object sender, DoWorkEventArgs e)
{
while (!MyBackgroundWorker.CancellationPending)
{
//Do some background stuff
MyBackgroundWorker.ReportProgress(0, (object)SomeData);
AutoResetEvent1.WaitOne(10000);
}
}
I'd pass in the SynchronizationContext associated with the textbox to the BackgroundWorker and use that to perform Updates on the UI thread. Using SynchronizationContext.Post, you can check if the control is disposed or disposing.
What about Me.IsHandleCreated?
Private Sub BwDownload_RunWorkerCompleted(sender As Object, e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BwDownload.RunWorkerCompleted
If Me.IsHandleCreated Then
'Form is still open, so proceed
End If
End Sub
Another way:
if (backgroundWorker.IsBusy)
{
backgroundWorker.CancelAsync();
while (backgroundWorker.IsBusy)
{
Application.DoEvents();
}
}
One solution that works, but too complicated. The idea is to spawn the timer that will keep trying to close the form, and form will refuse to close until said bgWorker is dead.
private void HandleClosingEvent(object sender, CancelEventArgs e) {
if (!this.bgWorker.IsBusy) {
// bgWorker is dead, let Closing event proceed.
e.Cancel = false;
return;
}
if (!this.bgWorker.CancellationPending) {
// it is first call to Closing, cancel the bgWorker.
this.bgWorker.CancelAsync();
this.timer1.Enabled = true;
}
// either this is first attempt to close the form, or bgWorker isn't dead.
e.Cancel = true;
}
private void timer1_Tick(object sender, EventArgs e) {
Trace.WriteLine("Trying to close...");
Close();
}
I have 1 web form and multiple user controls. One of the user controls fires an event. The page is listening and gets the value the control sends out. However the other user controls listening attach to the event but never get to the method.
User Control 1
public delegate void GetOrgIdEventHandler(long orgId);
public event GetOrgIdEventHandler GetOrgId;
protected void gvSearchResults_SelectedIndexChanged(object sender, EventArgs e)
{
if (GetOrgId != null)
{
GetOrgId(Id);
}
}
Web Form
//Search1 is the Id of the User Control on the web form - This is working.
//It calls the method in the assignment
Search1.GetOrgId +=
new SearchGridViewSelectedIndexChangedEventHandler(GetTheOrgId);
User Control 2
//SearchUserControl is the name of the User Control 2 Class
protected SearchUserControl mySuc = new SearchUserControl();
//The line below works, however the method does not get called. This is where it fails.
//I set a breakpoint in GetTheOrgId but I never get to that break.
mySuc.GetOrgId += new SearchGridViewSelectedIndexChangedEventHandler(GetTheOrgId);
Yes, you can raise events in the first control, have it picked up in the parent, and then have the parent call a method/function in the second control. Example (in VB.Net):
User control one:
Partial Class user_controls_myControl
Inherits System.Web.UI.UserControl
Public Event DataChange As EventHandler
'now raise the event somewhere, for instance when the page loads:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
RaiseEvent DataChange(Me, New EventArgs)
end sub
end Class
This will raise an event, called DataChange, when the control loads. Or, you can raise it in response to another event withing the controls (like if a button gets pushed). This will raise an event that the parent can subscibe to, like this (assuming you have a control on the page called MyControl1):
Main Page:
Protected Sub myControl_dataChange(ByVal sender As Object, ByVal e As EventArgs) handles myControl1.DataChange
End Sub
Now, you can then expose a method in your second control, like this:
Partial Class user_controls_myOtherControl
Inherits System.Web.UI.UserControl
public sub callMe()
'do something
end Sub
end Class
You can then call the method in the second control, from the parent page, like this:
me.userConrol2.callMe()
If you still have questions, let me know.
I have a simple outlook ribbon with an editBox. Once the user clicks the send button, I capture the string in the editBox and use it in the Application_ItemSend..
My problem is, after the function is done, I want to RESET the UI of the ribbon (just the editBox) so that the user won't have the previously typed string in the same box when opening up a new message screen. I tried the Ribbon.Invalidate but I can't seem to get rid of that string value. When I re-open the "New Email" screen, the old value is still there.
Here is the code:
<customUI xmlns="http://schemas.microsoft.com/office/2009/07/customui" onLoad="Ribbon_Load_2010">
<ribbon>
<tabs>
<tab idMso="TabNewMailMessage">
<group id="TaskManager" insertBeforeMso="GroupSend" label="Task Manager">
<editBox id="editboxTaskID" label="Task ID #: " onChange="editboxTaskID_OnChange"
imageMso="RecordsAddFromOutlook" sizeString="wwwwww"/>
</group>
</tab>
</tabs>
</ribbon>
</customUI>
And the VB Code:
<Runtime.InteropServices.ComVisible(True)> _
Public Class CustomRibbon
Implements Office.IRibbonExtensibility
Private ribbon As Office.IRibbonUI
Public strTask_ID As String = ""
Public Sub New()
End Sub
Public Function GetCustomUI(ByVal ribbonID As String) As String Implements Office.IRibbonExtensibility.GetCustomUI
Return GetResourceText("Addin.Ribbon.xml")
End Function
Private Sub Application_ItemSend(ByVal Item As Object, ByRef Cancel As Boolean)
Me.ribbon.Invalidate()
Try
'SOME CODE HERE WHICH WORKS FINE!
Catch ex As Exception
End Try
End Sub
'Create callback methods here. For more information about adding callback methods, select the Ribbon XML item in Solution Explorer and then press F1.
Public Sub Ribbon_Load_2010(ByVal ribbonUI As Office.IRibbonUI)
Me.ribbon = ribbonUI
AddHandler Globals.ThisAddIn.Application.ItemSend, AddressOf Application_ItemSend
End Sub
Public Sub editboxTaskID_OnChange(ByVal control As Office.IRibbonControl, ByVal Text As String)
strTask_ID = Text
End Sub
Public Sub AttachmentRibonClick(ByVal control As Microsoft.Office.Core.IRibbonControl)
Globals.ThisAddIn.TriggerTaskWindow("Attachment")
End Sub
Private Shared Function GetResourceText(ByVal resourceName As String) As String
Dim asm As Reflection.Assembly = Reflection.Assembly.GetExecutingAssembly()
Dim resourceNames() As String = asm.GetManifestResourceNames()
For i As Integer = 0 To resourceNames.Length - 1
If String.Compare(resourceName, resourceNames(i), StringComparison.OrdinalIgnoreCase) = 0 Then
Using resourceReader As IO.StreamReader = New IO.StreamReader(asm.GetManifestResourceStream(resourceNames(i)))
If resourceReader IsNot Nothing Then
Return resourceReader.ReadToEnd()
End If
End Using
End If
Next
Return Nothing
End Function
End Class
The invalidate method is used to signal that a control has been updated and needs to be re-rendered on the screen. It will not clear data from a control. What you need to do is set the property on the control (the edit box in this case) that stores the offending string value to an empty string.
Ok, I figured it out.
Apparently after you invalidate the controls, you need to use GetText function of the Editbox to init the value.
Public Function editboxTaskID_GetText(ByVal control As Office.IRibbonControl) As String
Return ""
End Function
I also noticed other sites use different signature for the function - which does not work. I believe Microsoft changed this from a Sub to a Function when moving to 2010 Interop.
I wish Microsoft had better documentation for this.
Happy programming!
Im trying to create a windows service with vb.net but when I run:
InstallUtil.exe myservice.exe
I'm getting the following error in the MyService.InstallLog file:
Restoring event log to previous state for source DebtorInvoiceMailingService.
An exception occurred during the Rollback phase of the System.Diagnostics.EventLogInstaller installer.
System.Security.SecurityException: The source was not found, but some or all event logs could not be searched. Inaccessible logs: Security.
An exception occurred during the Rollback phase of the installation. This exception will be ignored and the rollback will continue. However, the machine might not fully
DebtorInvoiceMailingService.vb
Imports System.ServiceProcess
Imports System.Timers
Public Class DebtorInvoiceMailingService
Inherits ServiceBase
Private _timer As Timer
Private _lastRun As DateTime = DateTime.Now
Private _notificationsManager As Notifications
Public Sub New()
Me.ServiceName = "DebtorInvoiceMailingService"
End Sub
'When service starts
Protected Overrides Sub OnStart(ByVal args() As String)
MyBase.OnStart(args)
'This object will do what im looking for (monitore a folder)
Me._notificationsManager = New Notifications
Me._timer = New Timer
'Service will be executed every 24 hours
Me._timer.Interval = 1000 * 60 * 60 * 24
Me._timer.Enabled = True
'Service will execute timer_Elapsed()
AddHandler Me._timer.Elapsed, AddressOf timer_Elapsed
End Sub
'When service stops
Protected Overrides Sub OnStop()
MyBase.OnStop()
Me._timer.Dispose()
End Sub
'Function executed every 24 hours
Private Sub timer_Elapsed(ByVal sender As Object, ByVal e As ElapsedEventArgs)
If (Me._lastRun.Date > DateTime.Now.Date) Then
Me._timer.Stop()
'You have to stop your timer because if the task that you
'are about to perform takes longer than the timer.interval
'the task will be executed multiple times
Me._notificationsManager.execute() 'this function will send an email
Me._lastRun = DateTime.Now
Me._timer.Start()
End If
End Sub
Shared Sub Main()
ServiceBase.Run(New DebtorInvoiceMailingService)
End Sub
End Class
ProjectInstaller.vb
Imports System
Imports System.ServiceProcess
Imports System.ComponentModel
Imports System.Configuration.Install
<RunInstallerAttribute(True)> _
Public Class ProjectInstaller
Inherits System.Configuration.Install.Installer
Public WithEvents ServiceProcessInstaller1 As ServiceProcessInstaller
Public WithEvents ServiceInstaller1 As ServiceInstaller
Public Sub New()
MyBase.New()
Me.ServiceProcessInstaller1 = New ServiceProcessInstaller()
Me.ServiceInstaller1 = New ServiceInstaller()
'ServiceProcessInstaller1
Me.ServiceProcessInstaller1.Account = System.ServiceProcess.ServiceAccount.LocalSystem
Me.ServiceProcessInstaller1.Password = Nothing
Me.ServiceProcessInstaller1.Username = Nothing
'ServiceInstaller1
Me.ServiceInstaller1.Description = "Auto mailing invoices to debtors every 24 hours."
Me.ServiceInstaller1.DisplayName = "DebtorInvoiceMailingService"
Me.ServiceInstaller1.ServiceName = "DebtorInvoiceMailingService"
Me.ServiceInstaller1.StartType = ServiceStartMode.Manual
'ProjectInstaller
Me.Installers.Add(Me.ServiceProcessInstaller1)
Me.Installers.Add(Me.ServiceInstaller1)
End Sub
Please Can someone help me? Thanks :)
Be sure to run the InstallUtil from a command windows launched "As Administrator".