Menú

Mostrar Mensajes

Esta sección te permite ver todos los mensajes escritos por este usuario. Ten en cuenta que sólo puedes ver los mensajes escritos en zonas a las que tienes acceso en este momento.

Mostrar Mensajes Menú

Mensajes - Eleкtro

#3671
Lo que ocurre es que estás controlando el evento inadecuado, en el evento RichTextBox.KeyDown NO se desplaza el caret, por ende, estás intentando obtener una información (índice de columna/linea) que todavía no ha sido asignada a la nueva posición del caret.

Aparte de eso, no es buena idea que llames al método Form.Update() o RichTextBox.Update() en cada pulsación, es innecesario y muy expensivo, además, en cualquier caso el método que deberías llamar debería ser StatusStrip.Update().

¿La solución?, controlar el evento RichTextBox.KeyUp:

VB.NET:
Código (vbnet) [Seleccionar]
   Private Sub RtbEditor_KeyUp(sender As Object, e As KeyEventArgs) _
   Handles RtbEditor.KeyUp
       Me.UpdateStatusBarInfo(DirectCast(sender, RichTextBox))
   End Sub

   Private Sub UpdateStatusBarInfo(ByVal rtb As RichTextBox)
       Dim lineIndex As Integer = rtb.GetLineFromCharIndex(rtb.SelectionStart)
       Dim colIndex As Integer = (rtb.SelectionStart - rtb.GetFirstCharIndexFromLine(lineIndex))

       TsLblLine.Text = Convert.ToString(lineIndex)
       TsLblCol.Text = Convert.ToString(colIndex)
   End Sub


C#:
Código (csharp) [Seleccionar]
private void RtbEditor_KeyUp(object sender, KeyEventArgs e)
{
this.UpdateStatusBarInfo((RichTextBox)sender);
}

private void UpdateStatusBarInfo(RichTextBox rtb)
{
int lineIndex = rtb.GetLineFromCharIndex(rtb.SelectionStart);
int colIndex = (rtb.SelectionStart - rtb.GetFirstCharIndexFromLine(lineIndex));

TsLblLine.Text = Convert.ToString(lineIndex);
TsLblCol.Text = Convert.ToString(colIndex);
}

//=======================================================
//Service provided by Telerik (www.telerik.com)
//=======================================================


Saludos
#3672
Cita de: Meta en 29 Mayo 2016, 09:44 AMSi bajo el valor, la barra de progreso no baja, se queda donde alcanzó su valor máximo.

Que la "barra de progreso" no disminuya es sinónimo de que no estás eliminando los caracteres sobrantes.

Si tu imprimes esto:
----- (5)

Y vuelves a la posición inicial para escribir esto:
---- (4)

Al final lo que tienes es esto:
----- (4+1)

Asegúrate de limpiar la linea actual antes de escribir el nuevo "porcentaje" de la "barra de progreso".
Código (csharp) [Seleccionar]

public static void ClearCurrentConsoleLine()
{
    int currentLineCursor = Console.CursorTop;
    Console.SetCursorPosition(0, Console.CursorTop);
    Console.Write(new string(' ', Console.WindowWidth));
    Console.SetCursorPosition(0, currentLineCursor);
}


Saludos
#3673
Cita de: fary en 29 Mayo 2016, 07:53 AMDe todas formas aquí tienes tu solución.
https://msdn.microsoft.com/es-es/library/system.threading.thread.suspend(v=vs.110).aspx?cs-save-lang=1&cs-lang=vb#code-snippet-1

Yo creo que él más bien se refiere a suspender la ejecución de un hilo por un tiempo definido como hace el método Thread.Sleep(), pero pudiendo especificar un identificador del hilo.




Cita de: dante93150 en 29 Mayo 2016, 04:09 AM
thread.sleep(1000)
como agrego la id o addres del proceso???

No puedes especificar un thread-id, el método Thread.Sleep() solamente afecta al hilo desde donde se invocó a dicha función, de hecho las funciones Win32 Sleep y SleepEx tienen el mismo comportamiento, simplemente NO es posible ...de forma "nativa".

Pero puedes recurrir a las funciones Win32 relacionadas (SuspendThread, ResumeThread), aplicando metodologías asincrónicas.

Te dejo esta solución que he elaborado (lo testeé con el thread-id del UI thread):

Modo de empleo:
Código (vbnet) [Seleccionar]
Dim threadId As Integer = GetCurrentThreadId().
SleepThread(threadId, TimeSpan.FromSeconds(5))


Código fuente:
Código (vbnet) [Seleccionar]
Public Shared Sub SleepThread(ByVal threadId As Integer, ByVal timespan As TimeSpan)

   Dim hThread As IntPtr
   Dim win32Err As Integer

   Dim suspendFunc As Func(Of Integer) =
       Function() As Integer ' Returns the previous suspend count for the thread.
           Dim suspendCount As Integer
           Debug.WriteLine("Sleeping...")
           Thread.Sleep(timespan)
           Debug.WriteLine("Resuming thread...")
           suspendCount = ResumeThread(hThread)
           CloseHandle(hThread)
           Return suspendCount
       End Function

   hThread = OpenThread(ThreadAccessRights.SuspendResume Or ThreadAccessRights.Terminate, True, threadId)
   win32Err = Marshal.GetLastWin32Error()

   If (hThread = IntPtr.Zero) Then
       Throw New Win32Exception(win32Err)

   Else
       Debug.WriteLine("Pausing thread...")
       Dim suspendTask As Task(Of Integer) = Task.Factory.StartNew(Of Integer)(suspendFunc)
       SuspendThread64(hThread)

   End If

End Sub


P/Invoking:
Código (vbnet) [Seleccionar]
<SuppressUnmanagedCodeSecurity>
<DllImport("kernel32.dll", SetLastError:=False)>
Public Shared Function GetCurrentThreadId(
) As <MarshalAs(UnmanagedType.U4)> Integer
End Function

<DllImport("kernel32.dll", SetLastError:=True)>
Public Shared Function OpenThread(
   <MarshalAs(UnmanagedType.I4)> ByVal dwDesiredAccess As ThreadAccessRights,
 <MarshalAs(UnmanagedType.Bool)> ByVal bInheritHandle As Boolean,
   <MarshalAs(UnmanagedType.U4)> ByVal dwThreadId As Integer
) As IntPtr
End Function

<DllImport("kernel32.dll", EntryPoint:="Wow64SuspendThread", SetLastError:=True)>
Public Shared Function SuspendThread32(
    <MarshalAs(UnmanagedType.SysInt)> ByVal hThread As IntPtr
) As Integer
End Function

<DllImport("kernel32.dll", EntryPoint:="SuspendThread", SetLastError:=True)>
Public Shared Function SuspendThread64(
    <MarshalAs(UnmanagedType.SysInt)> ByVal hThread As IntPtr
) As Integer
End Function

<DllImport("kernel32.dll", SetLastError:=True)>
Public Shared Function ResumeThread(
    <MarshalAs(UnmanagedType.SysInt)> ByVal hThread As IntPtr
) As Integer
End Function

<DllImport("kernel32.dll", SetLastError:=True)>
Public Shared Function CloseHandle(
<MarshalAs(UnmanagedType.SysInt)> ByVal hObject As IntPtr
) As <MarshalAs(UnmanagedType.Bool)> Boolean
End Function

<Flags>
Public Enum ThreadAccessRights As Integer
   Terminate = &H1
   SuspendResume = &H2
End Enum


PD: Todo esto lo puedes encontrar en mi API ElektroKit (en mi firma, aquí abajo).

Saludos.
#3674
Cita de: Tazmania40 en 28 Mayo 2016, 12:22 PMcon Windows Presentation Foundation (WPF) se podría añadir recursos de audio que no sean WAV, en My.Resources

El administrador de recursos de WPF puede identificar los mismos tipos de archivo que para WinForms:



Pero como ya he explicado, puedes añadir cualquier tipo de archivo y leerlo.

En WPF puedes utilizar la class MediaPlayer, aunque no he comprobado si funciona con archivos MIDI:

Código (vbnet) [Seleccionar]
Dim fileUri As New Uri("file:///C:\Archivo.mid")
Dim player = New MediaPlayer()
player.Open(uri)
player.Play()


Ten en cuenta que puedes referenciar los ensamblados de WPF en tu proyecto WinForms para utilizar cualquier class de WPF, no es necesario migrar de tecnología.




Cita de: Tazmania40 en 28 Mayo 2016, 12:22 PMEn este proyecto me será imposible porque Windows Media Player trae consigo dos librerías (AxInterop.WMPLib.dll e Interop.WMPLib.dll) aunque apenas ocupan, pero ya por lo menos todos los sonidos los tendré compilados con el ejecutable.

WMP es un componente multimedia bastante "pesado" para lo que quieres hacer, si tener un código liviano es lo que quieres lograr, entonces yo te insisto en implementar la API de MCI para reproducir sonidos de fondo (varios al mismo tiempo).

Solo necesitas declarar esta función Win32:
Cita de: https://github.com/ElektroStudios/ElektroKit/blob/master/Solution/Elektro.Interop/Win32/NativeMethods/NativeMethods_Audio.vb
Código (vbnet) [Seleccionar]
<SuppressUnmanagedCodeSecurity>
<DllImport("winmm.dll", EntryPoint:="mciSendString", SetLastError:=True,
                       CharSet:=CharSet.Auto, BestFitMapping:=False, ThrowOnUnmappableChar:=True)>
Public Shared Function MciSendString(ByVal command As String,
                                    ByVal buffer As StringBuilder,
                                    ByVal bufferSize As Integer,
                                    ByVal hwndCallback As IntPtr
) As Integer
End Function

Llamar a la función de la siguiente manera para cargar y reproducir archivos MIDI:
Cita de: https://github.com/ElektroStudios/ElektroKit/blob/master/Solution/Elektro.Multimedia/Types/AudioPlayer.vb
Código (vbnet) [Seleccionar]
Dim filepath As String = "C:\Archivo.mid"'
Dim alias As String = "midi_1"
MciSendString(String.Format("open sequencer! ""{0}"" alias {1}", filepath, alias), Nothing, 0, IntPtr.Zero)
MciSendString(String.Format("play {0} from 0", alias), Nothing, 0, IntPtr.Zero)

Y liberar los recursos no-administrados cuando ya no necesites reproducir:
Cita de: https://github.com/ElektroStudios/ElektroKit/blob/master/Solution/Elektro.Interop/Win32/NativeMethods/NativeMethods_Audio.vb
Código (vbnet) [Seleccionar]
MciSendString(String.Format("stop {0}", alias), Nothing, 0, IntPtr.Zero)
MciSendString(String.Format("close {0}", alias), Nothing, 0, IntPtr.Zero)

Aquí tienes la documentación:

PD: También podrías copiar y pegar en tu código fuente una implementación ya hecha como por ejemplo la mía, no es necesario usar y/o distribuir mis dlls, puedes extraer esa parte del código y compilarla bajo .NetFx 3.5.

Saludos
#3675
¡¡ NUEVA VERSIÓN v1.6 YA DISPONIBLE !!

Novedades (no se mencionan todas):

  • El type OutlookMailClient, para administrar una cuenta online de Outlook.com (Hotmail) mediante la API de Microsoft Office 365 y Active Directory (ADAL). No es una class muy completa, pero facilita y simplifica tareas cotidianas como autorizarse, obtener acceso a una carpeta, obtener los mensajes de una carpeta, eliminar mensajes y/o moverlos a otra carpeta, con lo que se puede desarrollar un bonito crawler en unos pocos y sencillos pasos, u otras trastadas mayores...
    (esta class usa métodos asíncronicos así que solo es visible en la versión de ElektroKit que corre bajo los runtimes de .Net Framework 4.5)

  • La class ImgurUtil y el type ImgurUploader, para hospedar imágenes en Internet mediante la API de Imgur.

  • La class DwmPreviewManager, para administrar las imágenes que windows usará para generar la previsualización en miniatura d enuestra app, y también la previsualización peek (Aero Peek). Esta funcionalidad es algo curiosa, me gusta inetntar cosas exóticas :).

  • Nuevas propiedades para trucar algunos parámetros de Windows en la class SystemParameters, como por ejemplo mostrar/ocultar los archivos ocultos del sistema y los archivos protegidos, activar/desactivar la selección de elementos del Explorer mediante el checkbox de selección, ejecutar las instancias de Explorer.exe en procesos paralelos, activar/desactivar el diálogo de confirmación de eliminación de archivos, y mucho más!.
    (los cambios realizados mediante esas propiedades tienen efecto AL INSTANTE, a diferencia de otras implementaciones que se pueden encontrar por Internet que se basan en un uso brusco del registro de Windows lo que implica un reinicio de sesión para aplicar los cambios ;-D)

  • Métodos para la compresión de imágenes (reducción de tamaño más bien), y la extracción y/o el conteo de iconos de un archivo, en la class ImageUtil.

  • Métodos para comprobar la versión del sistema perativo actual (incluyendo Windows 10), en la class OS.

  • Métodos para administrar el esquema de energía actual, en la class Power (véase también el type PowerPlan).

  • Métodos de carga y descarga de Hives de registro (SAM, NTUSER.DAT, etc.) en la class Registry (métodos: LoadHive y UnloadHive).

  • Propiedades para establecer el modo de error de la aplicación o el thread actual, en la class AppUtil (Propiedades: ProcessErrorMode y ThreadErrorMode)

  • Nuevos métodos de descarga asincrónica de archivos, en la class WebUtil.

  • El método ShowShellAboutDialog en la class Applets, para mostrar un diálogo de shell-about personalizado.

  • Métodos para asignar un proceso como crítico, y también para asignar o eliminar privilegios expecíficos de procesos, en la class ProcessUtil.

  • La class VisualBasicProjectFileManager para manipular en tiempo de ejecución las propiedades de un archivo de proyecto de VB.NET (proyecto.vbproj).

  • La class DelphiUtil con un simple método de conversión de equivalencia de tipos para ayudar sobre la interoperabilidad entre Delphi y .NET Framework.

  • Los siguientes types para la interoperabilidad entre Win32: SafeWindowHandle, SafeIconHandle, SafeBitmapHandle, SafeCursorHandle, SafeRegionHandle, y ZeroInvalidHandle (base class).

  • La enumeración HResult para facilitar la programación de código no administrado, la cual contiene los códigos HRESULT más conocidos, incluyendo los códigos HRESULT controlados por las excepciones administradas de .NET Framework.

  • Una basta cantidad de nuevas funciones Win32 (públicas) en la class NativeMethods, con sus correspondientes types, interfaces y enumeraciones en el namespace Elektro.Interop.Win32.

  • Se ha extendido considerablemente los types del namespace Elektro.Application.ThirdParty.TagLibSharp, ahora soportan la manipulación de tags APEv2 y Lyrics3.

  • La cantidad de extensiones de método actuales asciende a 587, aquí tienen la lista:
    https://github.com/ElektroStudios/ElektroKit/blob/master/Documentation/Extension-Method%20List.txt

Cambios:

  • He modificado el nombre de todos los valores de la enumeración WindowsMessages y EditControlMessages, del patrón "WmAbc" a "WM_Abc"; no es correcto añadir un guión bajo en .NET, pero esto facilitará la experiencia de usabilidad al programar en código no administrado.

  • He destripado y eliminado todos los miembros innecesarios del proyecto de terceros WindowsAPICodePack, como los controles de usuario, por lo que ahora es una versión reducida y liviana específica para el uso de ElektroKit. Tenerlo en cuenta, por que he eliminado muchas características que venían en la versión completa de Microsoft.

  • El proyecto ElektroKit.sln ahora es compilado con Visual Studio 2015, lo comento por que no se muy bien si esto afectará a usuarios que intenten compilar en versiones anteriores de Visual Studio.

  • El tamaño total de las librerías de ElektroKit, tanto en modo DEBUG como RELEASE, se ha reducido bastante, ahora pesan alrededor de 1,20 MB en su totalidad los 9 archivos .dll. Esto se debe al modo en que las compila Visual Studio 2015.

  • La class Input, que está relacionada con la API Win32 RAW_INPUT (implementada en funcionalidades de keylogging y mouselogging en el namespace Elektro.Core.IO) se ha dividido en dos classes distintas, Input32 y Input64. Esto es experimental y no lo he testeado, en caso de que Input32 no funcionase en equipos de 32-Bit entonces usar siempre la class Input64, debería funcionar.

Correcciones:

  • El método RedirectUrl en la class WebUtil no redireccionaba correctamente si la url apuntaba hacia ciertos servicios conocidos, como por ejemplo una url de RapidGator.net.
    El motivo de este fallo es específico de cada servidor y sus headers, pero como solución generalizada y alternativa he añadido un overload para especificar un user-agent personalizado, lo cual funcionará según que servicios (para RapidGator.net, funciona).

  • No se estaba disminuyendo correctamente a 0 la cantidad de referencias R.C.W. de algunos objetos COM que se usan internamente por algunas classes de ElektroKit,
    Esto se ha solucionado llamando directamente al método Marshal.FinalReleaseComObject() en lugar de disminuir 1 sola referencia con Marshal.ReleaseComObject().

  • Se han limpiado y dereferenciado todos los ensamblados y namespaces de .NET Framework innecesarios.

  • Algunos módulos de extensiones no eran visibles mediante Intellisense al intentar escribir el namespace completo, eso se debe a que el nombre del módulo se llamaba de la misma manera que algún método en su interior, la solución ha sido cambiar el nombre de los módulos conflictivos.
    Este cambio no afecta en absoluto en caso de que estuviesemos utilizando las extensiones de método de forma regular (type.Extension()) y no escribiendo el namespace completo (Namespace.Extension(type)).

  • Constantes refactorizaciones/optimizaciones por aquí y por allá, sin mayor importancia en realidad, pero los nombres de algunos miembros de ElektroKit pueden haber cambiado, o su modo de empleo.

Saludos!
#3677
Cita de: fary en 16 Mayo 2016, 09:47 AM
Evez de usar 17 variables haz un array. Lo mismo sucede con los PictureBox, crear un array de controles.

Código (vb) [Seleccionar]
Dim bX(17) as Integer

Pero ese Array conendrá 18 elementos, no 17, ya que en VB.NET los índices están basados en Cero.

Sería así:
Código (vb) [Seleccionar]
Dim bX(16) as Integer




Cita de: aspiazu en 16 Mayo 2016, 12:12 PM
Poniendo PictureBox(i).Image = My.Resources.rojo me da ese fallo

Error   1   'PictureBox' es un tipo y no se puede usar como expresión.

El error se debe a que estás aplicando mal la solución que te proporcionó @Fary.

PictureBox debe ser un array que contenga tus controles de tipo PictureBox.

Imagino que al llamarse de la misma forma, eso te habrá llevado a la confusión.




Personálmente te sugiero utilizar un diccionario para poder relacionar cada control con su respectivo valor y así simplificar la tarea:

Código (vbnet) [Seleccionar]
Dim pcbDict As New Dictionary(Of PictureBox, Integer) From {
   {Me.PictureBox1, 0},
   {Me.PictureBox2, 1},
   {Me.PictureBox3, 1},
   {Me.PictureBox4, 0},
   {etc...}}

For Each kv As KeyValuePair(Of PictureBox, Integer) In Me.pcbDict
   If (kv.Value = 1) Then
       kv.Key.Image = My.Resources.rojo
   End If
Next


Si lo quieres simplificar todavía más, puedes utilizar la propiedad PictureBox.Tag para asignar un valor Integer a cada PictureBox, y entonces solo tendrías que iterar la colección de controles:

Código (vbnet) [Seleccionar]
For Each pcb As PictureBox In Me.Controls.OfType(Of PictureBox)
   Dim value As Integer = CType(pcb.Tag, Integer)
   If (value = 1) Then
       pcb.Image = My.Resources.rojo
   End If
Next pcb


Saludos.
#3678
Cita de: Ruben_efl18 en 17 Mayo 2016, 16:34 PM
PB f = new PB(); // Form creado Todo Bien.
CalC n = new CalC(); // Form agregado de otro programa, Este ultimo me lo marca como si no existiera el form


Asumiendo que la visibilidad del miembro CalC sea pública, y la class sea instanciable, deberías poder solucionarlo especificando el namesace completo o importando el namespace mediante la directiva using.

Ejemplo 1:
Código (csharp) [Seleccionar]
WindowsApplication1.MyFormTypes.CalC n = new WindowsApplication1.MyFormTypes.CalC();

Ejemplo 2:
Código (csharp) [Seleccionar]

using f = WindowsApplication1.MyFormTypes;
...
f.CalC n = new f.CalC();


Saludos
#3679
Cita de: Tazmania40 en 26 Mayo 2016, 14:02 PM1º El Objeto My.Resources permite añadir otro tipo de archivos de audio que no sean WAV, esto es para utilizarlo con el control Windows Media Player en Visual Basic 2013.

Sí, puedes añadir cualquier tipo de archivo a la tabla de recursos, ahora, el único formato de audio que Visual Studio puede identificar, es .wav, así que tus archivos mp3 y etc. se añadirán en la sección "Files".




Cita de: Tazmania40 en 26 Mayo 2016, 14:02 PM2º Hay alguna forma de añadir el sonido, aunque sea WAV sino se puede otro formato en el control Windows Media Player desde los recursos (My.Resources).

Puedes extraer los bytes del recurso para crear un archivo local, y entonces, cargarlo en el componente de WMP.

Código (vbnet) [Seleccionar]

''' <summary>
''' Extracts a resource to disk.
''' </summary>
<DebuggerStepThrough>
Public Shared Sub ExtractResourceToDisk(ByVal resource As Byte(),
                                       ByVal targetFilepath As String,
                                       Optional ByVal overwrite As Boolean = False)

   Dim mode As FileMode
   If overwrite Then
       mode = FileMode.Create
   Else
       mode = FileMode.CreateNew
   End If

   Dim bufferSize As Integer = 4096
   Using fs As New FileStream(targetFilepath, mode, FileAccess.Write, FileShare.Read, bufferSize)
       fs.Write(resource, 0, resource.Length)
   End Using

End Sub


Ejemplo de uso:
Código (vbnet) [Seleccionar]
Dim filepath As String = Path.GetTempFileName()
Dim fileUri As New Uri(String.Format("file:///{0}", filepath))
ExtractResourceToDisk(My.Resources.MyAudioFile1, filepath, overwrite:=True)

AxWindowsMediaPlayer1.URL = fileUri.AbsoluteUri


PD: Desconozco si el componente ActiveX de WMP acepta el formato de URI, es de suponer que si, pero de lo contrario modifica el código para usar una ruta de archivo regular.




Por último, quiero añadir que en mi API ElektroKit puedes encontrar un reproductor de audio basado en MCI.
Soporta MP3 y WAVE entre otros, y tiene métodos para pausar, reanudar, detener, saltar a...

(click en la imagen para ir al código fuente)


Ejemplo de uso:
Código (vbnet) [Seleccionar]
Dim player As New AudioPlayer

Sub Button_LoadFile_Click() Handles Button_LoadFile.Click

   If Not player.IsFileLoaded Then
       player.LoadFile("C:\File.wav")
   End If

End Sub

Sub Button_Play_Click() Handles Button_Play.Click

   If (player.Status <> PlayerStatus.Playing) Then
       player.Play(AudioPlayMode.Background)
   End If

End Sub

Sub Button_Stop_Click() Handles Button_Stop.Click

   If (player.Status <> PlayerStatus.Stopped) Then
       player.Stop()
   End If

End Sub

Sub Button_PauseResume_Click() Handles Button_PauseResume.Click

   If (player.Status = PlayerStatus.Playing) Then
       player.Pause()

   ElseIf (player.Status = PlayerStatus.Paused) Then
       player.Resume()

   End If

End Sub

Private Sub Button_SeekBackward_Click(sender As Object, e As EventArgs) Handles Button_SeekBackward.Click

   Dim currentPosition As Long = CLng(player.Position.TotalMilliseconds)

   If ((currentPosition - 5000) <= 0) Then
       player.Seek(0)

   Else
       player.Seek(currentPosition - 5000)

   End If

End Sub

Private Sub Button_SeekForward_Click(sender As Object, e As EventArgs) Handles Button_SeekForward.Click

   Dim currentPosition As Long = CLng(player.Position.TotalMilliseconds)

   If Not ((currentPosition + 5000) >= player.Length) Then
       player.Seek(currentPosition + 5000)
   End If

End Sub

Sub Button_UnloadFile_Click() Handles Button_UnloadFile.Click

   If player.IsFileLoaded Then
       player.UnLoadFile()
   End If

End Sub


Saludos
#3680
Por favor, cuando especifiques un error, muestra el código que lo genera. No somos adivinos.

De todas formas el mensaje de la excepción creo que te está indicando que por algún motivo en "X" miembro debes habilitar la comunicación entre los threads que se quieran comunicar con ese miembro via COM, y para ello ese miembro debe ejecutarse en un entorno de único hilo (single threaded apartment a.k.a. STA). Dicho miembro puede ser el punto de entrada de tu aplicación, u otro método, según lo que hagas en tu código y como lo estés haciendo.

Debes añadirle este atributo a dicho método:

Si estás usando un objeto de tipo Thread, también prueba utilizando el método Thread.SetApartmentState antes de iniciarlo.

Saludos.