I have a problem with the Rich Text Fields of Outlook 2007. I try to read the values(email addresses) in the "To,Bcc,Cc Fields". I've read that the problem is known and that you only can read the fields when the mailItem in Outlook is saved.
So, I tried to access the email addresses with a window handler and the SendMessage function. But it only returns :
{\rtf1\ansi\ansicpg1252\deff0\deflang1031{\fonttbl{\f0\fswiss\fprq2\fcharset0
Tahoma;}} {*\generator Riched20 12.0.6606.1000;}\viewkind4\uc1
\pard\f0\fs17{\pict\wmetafile0
So I think Outlook replaces the email address with an embedded object and this object shows the email address. Can anybody help and tell me how to access the object and get the email address?
Use the MailItem.Recipients collection - it will be populated at all times.
I know this, but in Outlook 2007 there is a bug or missing feature. When you delete a (Email-Address)recipient from the to field, the mailItem is not refreshing its recipients collection. It only refreshes when a recipient is added and resolved!
So the only way I see is to read the content of the To-Field is..via SendMessage.
private int EditStreamProc(MemoryStream dwCookie, IntPtr pbBuff, int cb, out int pcb)
{
pcb = cb;
byte[] buffer = new byte[cb];
Marshal.Copy(pbBuff, buffer, 0, cb);
dwCookie.Write(buffer, 0, cb);
return 0;
}
private delegate int EditStreamCallback(MemoryStream dwCookie, IntPtr pbBuff, int cb, out int pcb);
[StructLayout(LayoutKind.Sequential)]
private struct EDITSTREAM
{
public MemoryStream dwCookie;
public int dwError;
public EditStreamCallback pfnCallback;
}
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern IntPtr SendMessage(IntPtr hwnd, uint msg, uint wParam, ref EDITSTREAM lParam);
private const int WM_USER = 0x0400;
private const int SF_RTF =3;
private const int EM_STREAMOUT = WM_USER + 74;
public string ReadRTFContentInOL2007(IntPtr handle)
{
string result = String.Empty;
using (System.IO.MemoryStream stream = new MemoryStream())
{
EDITSTREAM editStream = new EDITSTREAM();
editStream.pfnCallback = new EditStreamCallback(EditStreamProc);
editStream.dwCookie = stream;
SendMessage(handle, EM_STREAMOUT, SF_RTF, ref editStream);
stream.Seek(0, SeekOrigin.Begin);
using (StreamReader reader = new StreamReader(stream))
{
result = reader.ReadToEnd();
}
}
return result;
}
When the email addresses are resolved then i receive this :
{\rtf1\ansi\ansicpg1252\deff0\deflang1031{\fonttbl{\f0\fswiss\fprq2\fcharset0 Tahoma;}} {*\generator Riched20 12.0.6606.1000;}\viewkind4\uc1 \pard\f0\fs17{\pict\wmetafile0
So Outlook replaces the plain text with an object and I need to receive all the Information of the RTF Content! I think somewhere in this content must be the email address. To - Field Class is : RichEdit20WPT
Related
I'm using this plugin for Katalon Studio to access the last unread message from my testing Gmail account.
My email util class is like:
public final class SMDEmailUtils {
public static final String MainInboxFolder = "INBOX";
public static final String SpamFolder = "[Gmail]/Spam";
public static String GetMainEmail() {
if (!GeneralWebUIUtils.GlobalVariableExists('emailID'))
return "dev#example.com";
return GlobalVariable.emailID.toString();
}
public static String ExtractSignUpLink() {
final String folderName = this.GetNewMessageFolderName(30, FailureHandling.STOP_ON_FAILURE);
return this.ProcessHTML(this.GetNewMessage(folderName), "//a[.//div[#class = 'sign-mail-btn-text']]/#href");
}
public static String GetNewMessageFolderName(int timeOut,
FailureHandling failureHandling = FailureHandling.STOP_ON_FAILURE) {
final long startTime = System.currentTimeMillis()
final Map<String, Integer> folderMessageCountDict = [
(this.MainInboxFolder) : this.GetMessageCount(this.MainInboxFolder),
(this.SpamFolder) : this.GetMessageCount(this.SpamFolder),
];
while (System.currentTimeMillis() < startTime + 1000 * timeOut) {
final String folderName = folderMessageCountDict.findResult({String folderName, int initialMessageCount ->
if (initialMessageCount < this.GetMessageCount(folderName))
return folderName;
return null;
})
if (folderName != null)
return folderName;
// TODO: we shouldn't have to do some hard-coded suspension of the runtime. We need to close the store somehow
Thread.sleep(1000 * 2);
}
throw new StepFailedException("Failed to find a folder with a new message in it after ${(System.currentTimeMillis() - startTime) / 1000} seconds");
}
public static int GetMessageCount(String folderName) {
return Gmail.getEmailsCount(this.GetMainEmail(), GlobalVariable.emailPassword, folderName);
}
public static String GetNewMessage(String folderName) {
return Gmail.readLatestEMailBodyContent(this.GetMainEmail(), GlobalVariable.emailPassword, folderName);
}
/**
* **NOTE**: forked from https://stackoverflow.com/a/2269464/2027839 , and then refactored
*
* Processes HTML, using XPath
*
* #param html
* #param xpath
* #return the result
*/
public static String ProcessHTML(String html, String xpath) {
final String properHTML = this.ToProperHTML(html);
final Element document = DocumentBuilderFactory.newInstance()
.newDocumentBuilder()
.parse(new ByteArrayInputStream( properHTML.bytes ))
.documentElement;
return XPathFactory.newInstance()
.newXPath()
.evaluate( xpath, document );
}
private static String ToProperHTML(String html) {
// SOURCE: https://stackoverflow.com/a/19125599/2027839
String properHTML = html.replaceAll( "(&(?!amp;))", "&" );
if (properHTML.contains('<!DOCTYPE html'))
return properHTML;
return """<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head></head>
<body>
${properHTML}
</body>
</html>
""";
}
}
My use case of that is the following:
a test member lead, whose email forwards to my testing email ([myTestingEmailName]+[memberLeadName]#gmail.com), gets a link to an agreement to sign
on successful signature, the physician, whose email also forwards to my testing email ([myTestingEmailName]+[physicianName]#gmail.com), gets a link to an agreement to sign
Step 1 works, the link gets extracted successfully via SMDEmailUtils.ExtractSignUpLink() .
However, when it is the physician's turn to sign, that same line of code doesn't work. It's giving me the link from the first email message (the one meant for the recipient in step 1, that was already signed).
I check out my inbox manually, and see this:
The AUT sent both email messages on the same thread, but the plugin can only handle the first message on the thread!
How do I handle this?
I am using UISpy.exe (Windows tool) to select UI Elements that also works with IE. However, for some IE Elements, all properties are not loaded in the automation framework or they have weird values with which they can not be uniquely and efficiently identified when looked for(like in the figure below, Name property).
The same properties that are available here are also available using the Windows Automation API Framework. I want to know if there is way, using this or any other library, to access the DOM of a selected window or pane. I know of one other application (UIExplorer from UI Path) that works this way but I can't figure how.
Here is an example of what UIExplorer's selector for the same element looks like. See how they have access to the DOM where as UISpy.exe is only displaying elements.
you can try this:
using System;
using System.Runtime.InteropServices;
using System.Windows.Automation;
using mshtml;
namespace ConsoleApp1
{
class Program
{
#region Native
[DllImport("user32", EntryPoint = "RegisterWindowMessageA", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
private static extern int RegisterWindowMessage(string lpString);
[DllImport("user32", EntryPoint = "SendMessageTimeoutA", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
private static extern int SendMessageTimeout(IntPtr hWnd, int msg, int wParam, int lParam, int fuFlags, int uTimeout, ref int lpdwResult);
[DllImport("oleacc", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
private static extern int ObjectFromLresult(int lResult, ref Guid riid, int wParam, ref IHTMLDocument2 ppvObject);
private const int SMTO_ABORTIFHUNG = 2;
#endregion Native
static void Main(string[] args)
{
var firstIeWindow = GetFirstIeWindow();
var firstIeTab = GetFirstIeTab(firstIeWindow);
var ieDom = GetIeDom(new IntPtr(firstIeTab.Current.NativeWindowHandle));
var firstInput = GetFirstInputElement(ieDom);
Console.WriteLine($"#{firstInput.id}[name={firstInput.name}] = {firstInput.value}");
}
private static AutomationElement GetFirstIeWindow()
{
var firstIeWindow = AutomationElement.RootElement.FindFirst(TreeScope.Children, new AndCondition(
new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Window),
new PropertyCondition(AutomationElement.ClassNameProperty, "IEFrame")))
?? throw new Exception("IEFrame not found");
return firstIeWindow;
}
private static AutomationElement GetFirstIeTab(AutomationElement ieWindow)
{
var frameTab = ieWindow.FindFirst(TreeScope.Children, new AndCondition(
new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Pane),
new PropertyCondition(AutomationElement.ClassNameProperty, "Frame Tab")))
?? throw new Exception("Frame Tab not found");
var tabWindow = frameTab.FindFirst(TreeScope.Children, new AndCondition(
new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Pane),
new PropertyCondition(AutomationElement.ClassNameProperty, "TabWindowClass")))
?? throw new Exception("TabWindowClass not found");
var ieServer = tabWindow.FindFirst(TreeScope.Descendants, new AndCondition(
new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Pane),
new PropertyCondition(AutomationElement.ClassNameProperty, "Internet Explorer_Server")))
?? throw new Exception("Internet Explorer_Server not found");
return ieServer;
}
private static DispHTMLDocument GetIeDom(IntPtr hWnd)
{
var lRes = 0;
var lMsg = RegisterWindowMessage("WM_HTML_GETOBJECT");
SendMessageTimeout(hWnd, lMsg, 0, 0, SMTO_ABORTIFHUNG, 1000, ref lRes);
if (lRes == 0) return null;
IHTMLDocument2 ieDomFromhWnd = null;
var iidIhtmlDocument2 = new Guid("626FC520-A41E-11CF-A731-00A0C9082637");
var hr = ObjectFromLresult(lRes, ref iidIhtmlDocument2, 0, ref ieDomFromhWnd);
if (hr != 0) throw new COMException($"{nameof(ObjectFromLresult)} has thrown an exception", hr);
return ieDomFromhWnd as DispHTMLDocument ?? throw new Exception("IE DOM not found");
}
private static DispHTMLInputElement GetFirstInputElement(DispHTMLDocument ieDom)
{
var firstInput = (ieDom.body as DispHTMLBody)?.getElementsByTagName("input").item(0) as DispHTMLInputElement
?? throw new Exception("Input element not found");
return firstInput;
}
}
}
I use org.apache.commons.fileupload to upload file
class StorageService is a service that use cloud storage APIs to store file
This is my code
public class UploadFileAction extends org.apache.struts.action.Action {
private static final String SUCCESS = "success";
private StorageService storage = new StorageService();
private static final int BUFFER_SIZE = 1024 * 1024;
#Override
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
ServletFileUpload upload = new ServletFileUpload();
FileItemIterator iter = upload.getItemIterator(request);
while (iter.hasNext()) {
FileItemStream item = iter.next();
String fileName = item.getName();
String mime = item.getContentType();
storage.init(fileName, mime);
InputStream is = item.openStream();
byte[] b = new byte[BUFFER_SIZE];
int readBytes = is.read(b, 0, BUFFER_SIZE);
while (readBytes != -1) {
storage.storeFile(b, BUFFER_SIZE);
readBytes = is.read(b, 0, readBytes);
}
is.close();
storage.destroy();
}
return mapping.findForward(SUCCESS);
}
}
package storageservice;
import com.google.appengine.api.files.*;
import com.google.appengine.api.files.GSFileOptions.GSFileOptionsBuilder;
import java.io.*;
import java.nio.channels.Channels;
public class StorageService {
private static final String BUCKET_NAME = "thoitbk";
private FileWriteChannel writeChannel = null;
private OutputStream os = null;
public void init(String fileName, String mime) throws Exception {
FileService fileService = FileServiceFactory.getFileService();
GSFileOptionsBuilder builder = new GSFileOptionsBuilder()
.setAcl("public_read")
.setBucket(BUCKET_NAME)
.setKey(fileName)
.setMimeType(mime);
AppEngineFile writableFile = fileService.createNewGSFile(builder.build());
boolean lock = true;
writeChannel = fileService.openWriteChannel(writableFile, lock);
os = Channels.newOutputStream(writeChannel);
}
public void storeFile(byte[] b, int readSize) throws Exception {
os.write(b, 0, readSize);
os.flush();
}
public void destroy() throws Exception {
os.close();
writeChannel.closeFinally();
}
}
In local this works fine but error when I deploy my app
Please help me!
Make sure your app's service account has WRITE access to the bucket in question, either by adding the service account to the team with can edit rights or else update the bucket acl to explicitly grant the service account WRITE access. See this question for more details.
I'm attempting to serve video files from ASP.NET MVC to iPhone clients. The video is formatted properly, and if I have it in a publicly accessible web directory it works fine.
The core issue from what I've read is that the iPhone requires you to have a resume-ready download environment that lets you filter your byte ranges through HTTP headers. I assume this is so that users can skip forward through videos.
When serving files with MVC, these headers do not exist. I've tried to emulate it, but with no luck. We have IIS6 here and I'm unable to do many header manipulations at all. ASP.NET will complain at me saying "This operation requires IIS integrated pipeline mode."
Upgrading isn't an option, and I'm not allowed to move the files to a public web share. I feel limited by our environment but I'm looking for solutions nonetheless.
Here is some sample code of what I'm trying to do in short...
public ActionResult Mobile(string guid = "x")
{
guid = Path.GetFileNameWithoutExtension(guid);
apMedia media = DB.apMedia_GetMediaByFilename(guid);
string mediaPath = Path.Combine(Transcode.Swap_MobileDirectory, guid + ".m4v");
if (!Directory.Exists(Transcode.Swap_MobileDirectory)) //Make sure it's there...
Directory.CreateDirectory(Transcode.Swap_MobileDirectory);
if(System.IO.File.Exists(mediaPath))
return base.File(mediaPath, "video/x-m4v");
return Redirect("~/Error/404");
}
I know that I need to do something like this, however I'm unable to do it in .NET MVC. http://dotnetslackers.com/articles/aspnet/Range-Specific-Requests-in-ASP-NET.aspx
Here is an example of an HTTP response header that works:
Date Mon, 08 Nov 2010 17:02:38 GMT
Server Apache
Last-Modified Mon, 08 Nov 2010 17:02:13 GMT
Etag "14e78b2-295eff-4cd82d15"
Accept-Ranges bytes
Content-Length 2711295
Content-Range bytes 0-2711294/2711295
Keep-Alive timeout=15, max=100
Connection Keep-Alive
Content-Type text/plain
And here is an example of one that doesn't (this is from .NET)
Server ASP.NET Development Server/10.0.0.0
Date Mon, 08 Nov 2010 18:26:17 GMT
X-AspNet-Version 4.0.30319
X-AspNetMvc-Version 2.0
Content-Range bytes 0-2711294/2711295
Cache-Control private
Content-Type video/x-m4v
Content-Length 2711295
Connection Close
Any ideas? Thank you.
UPDATE: This is now a project on CodePlex.
Okay, I got it working on my local testing station and I can stream videos to my iPad. It's a bit dirty because it was a little more difficult than I expected and now that it's working I don't have the time to clean it up at the moment. Key parts:
Action Filter:
public class ByteRangeRequest : FilterAttribute, IActionFilter
{
protected string RangeStart { get; set; }
protected string RangeEnd { get; set; }
public ByteRangeRequest(string RangeStartParameter, string RangeEndParameter)
{
RangeStart = RangeStartParameter;
RangeEnd = RangeEndParameter;
}
public void OnActionExecuting(ActionExecutingContext filterContext)
{
if (filterContext == null)
throw new ArgumentNullException("filterContext");
if (!filterContext.ActionParameters.ContainsKey(RangeStart))
filterContext.ActionParameters.Add(RangeStart, null);
if (!filterContext.ActionParameters.ContainsKey(RangeEnd))
filterContext.ActionParameters.Add(RangeEnd, null);
var headerKeys = filterContext.RequestContext.HttpContext.Request.Headers.AllKeys.Where(key => key.Equals("Range", StringComparison.InvariantCultureIgnoreCase));
Regex rangeParser = new Regex(#"(\d+)-(\d+)", RegexOptions.Compiled);
foreach(string headerKey in headerKeys)
{
string value = filterContext.RequestContext.HttpContext.Request.Headers[headerKey];
if (!string.IsNullOrEmpty(value))
{
if (rangeParser.IsMatch(value))
{
Match match = rangeParser.Match(value);
filterContext.ActionParameters[RangeStart] = int.Parse(match.Groups[1].ToString());
filterContext.ActionParameters[RangeEnd] = int.Parse(match.Groups[2].ToString());
break;
}
}
}
}
public void OnActionExecuted(ActionExecutedContext filterContext)
{
}
}
Custom Result based on FileStreamResult:
public class ContentRangeResult : FileStreamResult
{
public int StartIndex { get; set; }
public int EndIndex { get; set; }
public long TotalSize { get; set; }
public DateTime LastModified { get; set; }
public FileStreamResult(int startIndex, int endIndex, long totalSize, DateTime lastModified, string contentType, Stream fileStream)
: base(fileStream, contentType)
{
StartIndex = startIndex;
EndIndex = endIndex;
TotalSize = totalSize;
LastModified = lastModified;
}
public override void ExecuteResult(ControllerContext context)
{
if (context == null)
throw new ArgumentNullException("context");
HttpResponseBase response = context.HttpContext.Response;
response.ContentType = this.ContentType;
response.AddHeader(HttpWorkerRequest.GetKnownResponseHeaderName(HttpWorkerRequest.HeaderContentRange), string.Format("bytes {0}-{1}/{2}", StartIndex, EndIndex, TotalSize));
response.StatusCode = 206;
WriteFile(response);
}
protected override void WriteFile(HttpResponseBase response)
{
Stream outputStream = response.OutputStream;
using (this.FileStream)
{
byte[] buffer = new byte[0x1000];
int totalToSend = EndIndex - StartIndex;
int bytesRemaining = totalToSend;
int count = 0;
FileStream.Seek(StartIndex, SeekOrigin.Begin);
while (bytesRemaining > 0)
{
if (bytesRemaining <= buffer.Length)
count = FileStream.Read(buffer, 0, bytesRemaining);
else
count = FileStream.Read(buffer, 0, buffer.Length);
outputStream.Write(buffer, 0, count);
bytesRemaining -= count;
}
}
}
}
My MVC action:
[ByteRangeRequest("StartByte", "EndByte")]
public FileStreamResult NextSegment(int? StartByte, int? EndByte)
{
FileStream contentFileStream = System.IO.File.OpenRead(#"C:\temp\Gets.mp4");
var time = System.IO.File.GetLastWriteTime(#"C:\temp\Gets.mp4");
if (StartByte.HasValue && EndByte.HasValue)
return new ContentRangeResult(StartByte.Value, EndByte.Value, contentFileStream.Length, time, "video/x-m4v", contentFileStream);
return new ContentRangeResult(0, (int)contentFileStream.Length, contentFileStream.Length, time, "video/x-m4v", contentFileStream);
}
I really hope this helps. I spent a LOT of time on this! One thing you might want to try is removing pieces until it breaks again. It would be nice to see if the ETag stuff, modified date, etc. could be removed. I just don't have the time at the moment.
Happy coding!
I tried looking for an existing extension but I didn't immediately find one (maybe my search-fu is weak.)
My immediate thought is that you'll need to make two new classes.
First, create a class inheriting from ActionMethodSelectorAttribute. This is the same base class for HttpGet, HttpPost, etc. In this class you'll override IsValidForRequest. In that method, examine the headers to see if a range was requested. You can now use this attribute to decorate a method in your controller which will get called when someone is requested part of a stream (iOS, Silverlight, etc.)
Second, create a class inheriting from either ActionResult or maybe FileResult and override the ExecuteResult method to add the headers you identified for the byte range that you'll be returning. Return it like you would a JSON object with parameters for the byte range start, end, total size so it can generate the response headers correctly.
Take a look at the way FileContentResult is implemented to see how you access the context's HttpResponse object to alter the headers.
Take a look at HttpGet to see how it implements the check for IsValidForRequest. The source is available on CodePlex or you can use Reflector like I just did.
You might use this info to do a little more searching and see if anyone has already created this custom ActionResult already.
For reference, here is what the AcceptVerbs attribute looks like:
public override bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo)
{
if (controllerContext == null)
{
throw new ArgumentNullException("controllerContext");
}
string httpMethodOverride = controllerContext.HttpContext.Request.GetHttpMethodOverride();
return this.Verbs.Contains<string>(httpMethodOverride, StringComparer.OrdinalIgnoreCase);
}
And here is what FileResult looks like. Notice the use of AddHeader:
public override void ExecuteResult(ControllerContext context)
{
if (context == null)
{
throw new ArgumentNullException("context");
}
HttpResponseBase response = context.HttpContext.Response;
response.ContentType = this.ContentType;
if (!string.IsNullOrEmpty(this.FileDownloadName))
{
string headerValue = ContentDispositionUtil.GetHeaderValue(this.FileDownloadName);
context.HttpContext.Response.AddHeader("Content-Disposition", headerValue);
}
this.WriteFile(response);
}
I just pieced this together. I don't know if it will suit your needs (or works).
public class ContentRangeResult : FileStreamResult
{
public int StartIndex { get; set; }
public int EndIndex { get; set; }
public int TotalSize { get; set; }
public ContentRangeResult(int startIndex, int endIndex, string contentType, Stream fileStream)
:base(fileStream, contentType)
{
StartIndex = startIndex;
EndIndex = endIndex;
TotalSize = endIndex - startIndex;
}
public ContentRangeResult(int startIndex, int endIndex, string contentType, string fileDownloadName, Stream fileStream)
: base(fileStream, contentType)
{
StartIndex = startIndex;
EndIndex = endIndex;
TotalSize = endIndex - startIndex;
FileDownloadName = fileDownloadName;
}
public override void ExecuteResult(ControllerContext context)
{
if (context == null)
{
throw new ArgumentNullException("context");
}
HttpResponseBase response = context.HttpContext.Response;
if (!string.IsNullOrEmpty(this.FileDownloadName))
{
System.Net.Mime.ContentDisposition cd = new System.Net.Mime.ContentDisposition() { FileName = FileDownloadName };
context.HttpContext.Response.AddHeader("Content-Disposition", cd.ToString());
}
context.HttpContext.Response.AddHeader("Accept-Ranges", "bytes");
context.HttpContext.Response.AddHeader("Content-Range", string.Format("bytes {0}-{1}/{2}", StartIndex, EndIndex, TotalSize));
//Any other headers?
this.WriteFile(response);
}
protected override void WriteFile(HttpResponseBase response)
{
Stream outputStream = response.OutputStream;
using (this.FileStream)
{
byte[] buffer = new byte[0x1000];
int totalToSend = EndIndex - StartIndex;
int bytesRemaining = totalToSend;
int count = 0;
while (bytesRemaining > 0)
{
if (bytesRemaining <= buffer.Length)
count = FileStream.Read(buffer, 0, bytesRemaining);
else
count = FileStream.Read(buffer, 0, buffer.Length);
outputStream.Write(buffer, 0, count);
bytesRemaining -= count;
}
}
}
}
Use it like this:
return new ContentRangeResult(50, 100, "video/x-m4v", "SomeOptionalFileName", contentFileStream);
Can you move outside of MVC? This is a case where the system abstractions are shooting you in the foot, but a plain jane IHttpHandler should have alot more options.
All that said, before you implement your own streaming server, you are probably better off buying or renting one . . .
The header that work have the Content-type set to text/plain, is that correct or is a typo?.
Anyone, you can try to set this headers on the Action with:
Response.Headers.Add(...)
Guys am having some difficulty figuring this out:
I am trying to test whether the code(in c#) to broadcast a message and receiving the message works:
The code to send the datagram(in this case its the hostname) is:
public partial class Form1 : Form
{
String hostName;
byte[] hostBuffer = new byte[1024];
public Form1()
{
InitializeComponent();
StartNotification();
}
public void StartNotification()
{
IPEndPoint notifyIP = new IPEndPoint(IPAddress.Broadcast, 6000);
hostName = Dns.GetHostName();
hostBuffer = Encoding.ASCII.GetBytes(hostName);
UdpClient newUdpClient = new UdpClient();
newUdpClient.Send(hostBuffer, hostBuffer.Length, notifyIP);
}
}
And the code to receive the datagram is:
public partial class Form1 : Form
{
byte[] receivedNotification = new byte[1024];
String notificationReceived;
StringBuilder listBox;
UdpClient udpServer;
IPEndPoint remoteEndPoint;
public Form1()
{
InitializeComponent();
udpServer = new UdpClient(new IPEndPoint(IPAddress.Any, 1234));
remoteEndPoint=null;
startUdpListener1();
}
public void startUdpListener1()
{
receivedNotification = udpServer.Receive(ref remoteEndPoint);
notificationReceived = Encoding.ASCII.GetString(receivedNotification);
listBox = new StringBuilder(this.listBox1.Text);
listBox.AppendLine(notificationReceived);
this.listBox1.Items.Add(listBox.ToString());
}
}
For the reception of the code I have a form that has only a listbox(listBox1).
The problem here is that when i execute the code to receive, the program runs but the form isnt visible.
However when I comment the function call( startUdpListener1() ), the purpose isnt served but the form is visible.
Whats going wrong?
udpServer.Receive() is probably a blocking call, waiting for data (that it isn't getting)