Unblocking thread safe queue - check code, please (and use, if right for you) - Windows Phone 7 Development and Hacking

Hi friends.
I must solve big problem to finish HaRET (and other native applications) managed wrapper and UI (i. e. for example managed Silverlight UI controlled from unmanaged code), safe WP7 FTP client, interprocess cooperation on WP7, etc.
I know it is a basic issue, which is probably solved many time in operating systems (windows messages etc.) and many other examples.
But, I could find no any source code for queue, which is:
1. safe for more writers (threads from more processes) and for one reader,
2. unblocking for all writers,
3. unblocking for reader.
I found only very much unblocking ringbuffers or blocking queues, no one unblocking unlimited queue. Please, send corrections if I am bad looking.
Then, I tried code it...
First I want use std::queue with Thread Local Storage identifications (one subqueue for all writer and one abqueue for reader). But, TLS is very limited on CE based systems and I am not sure, if it solve interprocess safety too.
Finally, I tried to write the following code. It is designed for interthread queue only still, but interprocess can be added by safe named filemapping probably. Tell your opinion, it will be the basis for many complex applications here. For many years I have not worked with low-level synchronisation, I could make a fundamental mistake. So far I've missed templates and any wrapper, it's just the basic idea, usable in both C/C++ with very little changes:
PHP:
// This queue is unblocking and thread safe, when:
// 1. more writers are allowed,
// 2. one reader is allowed only.
// Motto: Pointers queue is both-directional, but frontal direction is changed by writers, backward direction by reader only!
#ifndef InterlockedExchangePointer
#define InterlockedExchangePointer(Target, Value) ((PVOID)InterlockedExchange((PLONG)(Target), (LONG)(Value)))
#endif
#ifndef InterlockedCompareExchangePointer
#define InterlockedCompareExchangePointer(Destination, ExChange, Comperand) ((PVOID)InterlockedCompareExchange((PLONG)(Destination), (LONG)(ExChange), (LONG)(Comperand)))
#endif
typedef struct SQItem
{
SQItem * pNext;
SQItem * pPrev;
void * pValue;
} * PItem;
SQItem EmptyItem = {NULL, NULL, NULL};
PItem pFront = &EmptyItem;
PItem pBack = &EmptyItem;
// Empty queue contains one item with both directions pointers nulled.
bool push_front(void * pNewValue) // nonblocking push, but theoretically forever cycle is possible for low priority thread! Practically improbable.
{
if (!pNewValue)
{
return false;
}
PItem pNewFront = new SQItem;
if (pNewFront)
{
PItem pProbablyFront;
InterlockedExchangePointer(&pProbablyFront, pFront);
pNewFront->pNext = pProbablyFront;
pNewFront->pPrev = NULL;
pNewFront->pValue = pNewValue;
while (InterlockedCompareExchangePointer(&pFront, pNewFront, pProbablyFront) != pProbablyFront)
{ // Another writer changed front pointer, active writer must try it again.
InterlockedExchangePointer(&pProbablyFront, pFront);
pNewFront->pNext = pProbablyFront;
}
return true; // Success allways.
}
return false; // Insufficient memory.
}
void * pop_back() // one reader allowed only!!!
{
PItem pBackward;
InterlockedExchangePointer(&pBackward, pFront); // Safe copy of actual front pointer
if (pBackward == pBack) // Queue is empty in time of interlocked attempt.
{
return NULL;
}
if (!pBack->pPrev)
{ // If backward queue is not continued here, reconstruct it from safe front pointer.
while (pBackward != pBack && !pBackward->pNext->pPrev)
{
pBackward->pNext->pPrev = pBackward;
pBackward = pBackward->pNext;
}
}
// One reader can safe read from back and manipulate with backward queue.
PItem pDelete = pBack;
pBack->pPrev->pNext = NULL;
pBack = pBack->pPrev;
delete pDelete;
return pBack->pValue;
/* // This is not necessary, but it is more clean:
void * pResult = pBack->pValue;
pBack->pValue = NULL;
return pResult;
*/
}
I am not sure, if heap allocation is not more "blocking" operation due to swapping and mm priorities, then object/signal waiting. What do you mean about it?
Mirror principle can be used to OneToMore queue making. Thanks unblocking, MoreToOne and OneToMore can be immeditelly piped to MoreToMore one.
But, when CE systems do not support two coupled pointers interlocked functions, there is no possibility to identify allowed reader safely, then this has not great significance.
As well, MoreToOne is much more needed now.

Template version
Using (simple example, the same way will be used between native threads and managed Silverlight UI):
Code:
#include "..\Templates\STQueue.h"
STQueue<tstring> qMessages(L"");
Code:
... // Called by [B]any thread[/B]:
void SafeMessage(tstring sMessage)
{
qMessages.push_front(sMessage);
PostMessage(hUnsafe, WM_FTP_MESSAGE, 0 , 0);
}
...
Code:
... // In UI thread:
LRESULT OnMsgMessage(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
bool bChange = false;
tstring szMessage = L"";
while ((szMessage = qMessages.pop_back()) != L"")
{
szMessages += szMessage;
szMessages += L"\r\n";
bChange = true;
}
if (bChange)
{
SetDlgItemText(hMainDlg, IDC_EDITMessage, szMessages.c_str());
}
return TRUE;
}
...
STQueue.h:
PHP:
template <class _Type> class STQItem
{
public:
STQItem<_Type> * pNext;
STQItem<_Type> * pPrev;
_Type Value;
STQItem(_Type & rV, STQItem<_Type> * pN = NULL, STQItem<_Type> * pP = NULL);
};
template <class _Type> class STQueue
{
protected:
STQItem<_Type> * pFront;
STQItem<_Type> * pBack;
_Type EmptyValue;
public:
STQueue(_Type EmptyV);
~STQueue();
bool push_front(const _Type & rNewValue);
const _Type & pop_back();
bool empty();
};
template <class _Type> STQItem<_Type>::STQItem(_Type & rV, STQItem<_Type> * pN, STQItem<_Type> * pP)
{
Value = rV;
pNext = pN;
pPrev = pP;
}
template <class _Type> STQueue<_Type>::STQueue(_Type EmptyV)
{
EmptyValue = EmptyV;
STQItem<_Type> * EmtyItem = new STQItem<_Type>(EmptyValue);
pFront = EmtyItem;
pBack = EmtyItem;
}
template <class _Type> STQueue<_Type>::~STQueue()
{
while (pop_back() != EmptyValue)
{
}
delete pBack;
}
template <class _Type> bool STQueue<_Type>::push_front(const _Type & rNewValue)
{ // nonblocking push, but theoretically forever cycle is possible for low priority thread!
STQItem<_Type> * pNewFront = new STQItem<_Type>(EmptyValue);
if (pNewFront)
{
STQItem<_Type> * pProbablyFront;
InterlockedExchangePointer(&pProbablyFront, pFront);
pNewFront->pNext = pProbablyFront;
pNewFront->pPrev = NULL;
pNewFront->Value = rNewValue;
while (InterlockedCompareExchangePointer(&pFront, pNewFront, pProbablyFront) != pProbablyFront)
{ // Another writer changed front pointer, active writer must try it again.
InterlockedExchangePointer(&pProbablyFront, pFront);
pNewFront->pNext = pProbablyFront;
}
return true; // Success allways.
}
return false; // Insufficient memory.
}
template <class _Type> const _Type & STQueue<_Type>::pop_back()
{ // one reader allowed only!!!
STQItem<_Type> * pBackward;
InterlockedExchangePointer(&pBackward, pFront); // Safe copy of actual front pointer
if (pBackward == pBack) // Queue is empty in time of interlocked attempt.
{
return EmptyValue;
}
if (!pBack->pPrev)
{ // If backward queue is not beginned, reconstruct it from safe front pointer.
while (pBackward != pBack && !pBackward->pNext->pPrev)
{
pBackward->pNext->pPrev = pBackward;
pBackward = pBackward->pNext;
}
}
// One reader can safe read from back and manipulate with backward queue.
STQItem<_Type> * pDelete = pBack;
pBack->pPrev->pNext = NULL;
pBack = pBack->pPrev;
delete pDelete;
return pBack->Value;
/* // This is not necessary, but it is more clean:
void * pResult = pBack->pValue;
pBack->pValue = NULL;
return pResult;
*/
}
template <class _Type> bool STQueue<_Type>::empty()
{
if(last==NULL)
return TRUE;
else
return FALSE;
}

Related

Kinetic Scroller

hello guys. just want to share this code to you
PHP:
using System;
namespace FBScroller
{
using System.Windows.Forms;
using System.Drawing;
public class KineticScroller
{
/*
* Kinetic Scroller
* by: Jayson Ragasa
* supports Windows Forms and WinMobile Forms
* ---------------------------------------
* Code stripped from: Implementing a smoothly animated ListBox
* http://www.codeproject.com/KB/list/SmoothListBox.aspx
*
* by: Fredrik Bornander
* http://www.codeproject.com/Members/Fredrik-Bornander
* ---------------------------------------
* Usage:
* make a panel1 on a form
* KineticScroller.HorizontalScroller ks = new KineticScroller.HorizontalScroller(panel1, this);
* make a new panel2 inside panel1
* KineticScroller.VerticalScroller ks2 = new KineticScroller.VerticalScroller(panel2, panel1);
*/
public class VerticalScroller
{
#region vars
private Point previousPoint = new Point();
private int draggedDistance = 0;
private float velocity = 0.0f;
private bool mouseIsDown = false;
private Control _ctl;
private Control _root;
Timer t = new Timer();
#endregion
#region animation stuff
private float dragDistanceFactor = 50.0f;
public float DragDistanceFactor
{
set
{
if (value < 1.0f)
throw new ArgumentException("DragDistanceFactor must be greater than or equal to 1.0", "value");
dragDistanceFactor = value;
}
}
private float maxVelocity = 9000.0f;
public float MaxVelocity
{
set
{
if (value < 1.0f)
throw new ArgumentException("MaxVelocity must be greater than or equal to 1.0", "value");
maxVelocity = value;
}
}
private float deaccelerationFactor = 0.9000f;
public float DeAccelerationFactor
{
set
{
if (value <= 0.0f || value >= 1.0f)
throw new ArgumentException("DeaccelerationFactor must fall within exclusive range 0.0 < value < 1.0", "value");
deaccelerationFactor = value;
}
}
private float snapBackFactor = 0.2f;
public float SnapBackFactor
{
set
{
if (value <= 0.0f || value >= 1.0f)
throw new ArgumentException("SnapBackFactor must fall within exclusive range 0.0 < value < 1.0", "value");
snapBackFactor = value;
}
}
#endregion
public VerticalScroller(Control control, Control root)
{
t.Interval = 50;
t.Enabled = true;
t.Tick += new EventHandler(t_Tick);
_ctl = control;
_ctl.Location = new Point(0, 0);
_ctl.MouseDown += new MouseEventHandler(_ctl_MouseDown);
_ctl.MouseMove += new MouseEventHandler(_ctl_MouseMove);
_ctl.MouseUp += new MouseEventHandler(_ctl_MouseUp);
_root = root;
}
void _ctl_MouseUp(object sender, MouseEventArgs e)
{
//if (e.Button == MouseButtons.Left)
{
velocity = Math.Min(Math.Max(dragDistanceFactor * draggedDistance, -maxVelocity), maxVelocity);
draggedDistance = 0;
Animate();
}
mouseIsDown = false;
}
void _ctl_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
Point absolutePoint = GetAbsolute(new Point(e.X, e.Y), _ctl, _root);
int delta = absolutePoint.Y - previousPoint.Y;
draggedDistance = delta;
Scroll(delta);
previousPoint = absolutePoint;
}
}
void _ctl_MouseDown(object sender, MouseEventArgs e)
{
mouseIsDown = true;
if (e.Button == MouseButtons.Left)
{
previousPoint = GetAbsolute(new Point(e.X, e.Y), _ctl, _root);
}
}
void t_Tick(object sender, EventArgs e)
{
Animate();
}
void Animate()
{
if (!mouseIsDown)
{
velocity *= deaccelerationFactor;
float elapsedTime = t.Interval / 1000.0f;
float deltaDistance = elapsedTime * velocity;
if (Math.Abs(deltaDistance) >= 1.0f)
{
Scroll((int)deltaDistance);
}
if (_ctl.Top != 0)
{
if (_ctl.Top > 0)
{
velocity = 0;
Scroll(-Math.Max(1, (int)(snapBackFactor * (float)(_ctl.Top))));
}
else
{
if (_ctl.Height > _root.ClientSize.Height)
{
int bottomPosition = _ctl.Top + _ctl.Height;
if (bottomPosition < _root.ClientSize.Height)
{
velocity = 0;
Scroll(Math.Max(1, (int)(snapBackFactor * (float)(_root.ClientSize.Height - bottomPosition))));
}
}
else
{
velocity = 0;
Scroll(Math.Max(1, -((int)(snapBackFactor * (float)_ctl.Top))));
}
}
}
}
}
void Scroll(int offset)
{
if (_ctl != null) _ctl.Top += offset;
}
private Point GetAbsolute(Point point, Control sourceControl, Control rootControl)
{
Point tempPoint = new Point();
for (Control iterator = sourceControl; iterator != rootControl; iterator = iterator.Parent)
{
tempPoint.Offset(iterator.Left, iterator.Top);
}
tempPoint.Offset(point.X, point.Y);
return tempPoint;
}
}
public class HorizontalScroller
{
#region vars
private Point previousPoint = new Point();
private int draggedDistance = 0;
private float velocity = 0.0f;
private bool mouseIsDown = false;
private Control _ctl;
private Control _root;
Timer t = new Timer();
#endregion
#region animation stuff
private float dragDistanceFactor = 50.0f;
public float DragDistanceFactor
{
set
{
if (value < 1.0f)
throw new ArgumentException("DragDistanceFactor must be greater than or equal to 1.0", "value");
dragDistanceFactor = value;
}
}
private float maxVelocity = 9000.0f;
public float MaxVelocity
{
set
{
if (value < 1.0f)
throw new ArgumentException("MaxVelocity must be greater than or equal to 1.0", "value");
maxVelocity = value;
}
}
private float deaccelerationFactor = 0.9000f;
public float DeAccelerationFactor
{
set
{
if (value <= 0.0f || value >= 1.0f)
throw new ArgumentException("DeaccelerationFactor must fall within exclusive range 0.0 < value < 1.0", "value");
deaccelerationFactor = value;
}
}
private float snapBackFactor = 0.2f;
public float SnapBackFactor
{
set
{
if (value <= 0.0f || value >= 1.0f)
throw new ArgumentException("SnapBackFactor must fall within exclusive range 0.0 < value < 1.0", "value");
snapBackFactor = value;
}
}
#endregion
public HorizontalScroller(Control control, Control root)
{
t.Interval = 50;
t.Enabled = true;
t.Tick += new EventHandler(t_Tick);
_ctl = control;
_ctl.Location = new Point(0, 0);
_ctl.MouseDown += new MouseEventHandler(_ctl_MouseDown);
_ctl.MouseMove += new MouseEventHandler(_ctl_MouseMove);
_ctl.MouseUp += new MouseEventHandler(_ctl_MouseUp);
_root = root;
}
void _ctl_MouseUp(object sender, MouseEventArgs e)
{
//if (e.Button == MouseButtons.Left)
{
velocity = Math.Min(Math.Max(dragDistanceFactor * draggedDistance, -maxVelocity), maxVelocity);
draggedDistance = 0;
Animate();
}
mouseIsDown = false;
}
void _ctl_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
Point absolutePoint = GetAbsolute(new Point(e.X, e.Y), _ctl, _root);
int delta = absolutePoint.X - previousPoint.X;
draggedDistance = delta;
Scroll(delta);
previousPoint = absolutePoint;
}
}
void _ctl_MouseDown(object sender, MouseEventArgs e)
{
mouseIsDown = true;
if (e.Button == MouseButtons.Left)
{
previousPoint = GetAbsolute(new Point(e.X, e.Y), _ctl, _root);
}
}
void t_Tick(object sender, EventArgs e)
{
Animate();
}
void Animate()
{
if (!mouseIsDown)
{
velocity *= deaccelerationFactor;
float elapsedTime = t.Interval / 1000.0f;
float deltaDistance = elapsedTime * velocity;
if (Math.Abs(deltaDistance) >= 1.0f)
{
Scroll((int)deltaDistance);
}
if (_ctl.Left != 0)
{
if (_ctl.Left > 0)
{
velocity = 0;
Scroll(-Math.Max(1, (int)(snapBackFactor * (float)(_ctl.Left))));
}
else
{
if (_ctl.Width > _root.ClientSize.Width)
{
int rightPosition = _ctl.Left + _ctl.Width;
if (rightPosition < _root.ClientSize.Width)
{
velocity = 0;
Scroll(Math.Max(1, (int)(snapBackFactor * (float)(_root.ClientSize.Width - rightPosition))));
}
}
else
{
velocity = 0;
Scroll(Math.Max(1, -((int)(snapBackFactor * (float)_ctl.Left))));
}
}
}
}
}
void Scroll(int offset)
{
if (_ctl != null) _ctl.Left += offset;
}
private Point GetAbsolute(Point point, Control sourceControl, Control rootControl)
{
Point tempPoint = new Point();
for (Control iterator = sourceControl; iterator != rootControl; iterator = iterator.Parent)
{
tempPoint.Offset(iterator.Left, iterator.Top);
}
tempPoint.Offset(point.X, point.Y);
return tempPoint;
}
}
}
}
I stipped his code and made a class version of his smooth scroller and modified to make a Horizontal and Vertical scroller
Did you do any updates to his code?

[Q] [.net cf]Loopback

Hey guys
I'm developing a little webserver for WM with the .net cf. it's easy and works fine as long as I don't try to access it from the same device it's running on. Nothing works: localhost,127.0.0.1 or even if I'm connected to a wifi network and I use this IP. Has anyone the solution for this issue?
ta you
a yeah I use the TcpListener-Class and I implemted some simple HTTP.
chabun
Code
Hey guys
Noone has an idea??
Here is the code which I use to setup the HttpListener and answer connections.
Code:
using System;
using System.Linq;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using StedySoft.SenseSDK;
using System.Threading;
using System.IO;
namespace WebServer
{
public partial class ServerForm : Form
{
IPEndPoint local;
TcpListener listener;
private volatile bool stop;
private volatile bool handled;
SensePanelItem state;
SensePanelTextboxItem response;
Thread serverThread;
public ServerForm(IPEndPoint local)
{
InitializeComponent();
this.local = local;
SetupList();
}
private void SetupList()
{
SensePanelDividerItem infos = new SensePanelDividerItem("infd", "Infos");
mainList.AddItem(infos);
mainList.AddItem(new SensePanelItem("Local-Endpoint") { PrimaryText = "Local-Endpoint", SecondaryText = local.ToString() });
mainList.AddItem(state = new SensePanelItem("Status") { PrimaryText = "Status", SecondaryText = "Wird gestartet..." });
mainList.AddItem(new SensePanelDividerItem("Response", "Response"));
mainList.AddItem(response = new SensePanelTextboxItem("body") { LabelText = "HTML-Body, welcher auf Requests gesendet wird.", Text = "<span style =\"color:red;font-size:30pt\">It works!!</span>" });
mainList.AddItem(new SensePanelDividerItem("Requests", "Requests"));
}
private void StartServer()
{
if (listener != null)
{
StopServer(true);
}
listener = new TcpListener(local.Port);
listener.Start();
serverThread = new Thread(listen);
serverThread.IsBackground = true;
stop = false;
serverThread.Start();
state.SecondaryText = "Gestartet...";
}
private void listen()
{
while (!stop)
{
while (listener.Pending())
{
handled = false;
Thread handlingThread = new Thread(handler);
handlingThread.Start();
while (!handled)
Thread.Sleep(50);
}
Thread.Sleep(200);
}
}
private void handler()
{
// Get the current connection
TcpClient client = (TcpClient)this.Invoke(new Func<TcpClient>(listener.AcceptTcpClient));
IPEndPoint remote = (IPEndPoint)client.Client.RemoteEndPoint;
handled = true;
NetworkStream stream = client.GetStream();
StreamReader reader = new StreamReader(stream);
ReadHttpRequest(reader);
StreamWriter writer = new StreamWriter(stream);
StringBuilder response = new StringBuilder(); ;
StartHTML(response);
response.AppendLine((string)this.Invoke(new Func<IPEndPoint, string>(GetResponse), remote));
EndHTML(response);
WriteHTTPResponse(writer, response.Length);
writer.WriteLine(response.ToString());
writer.Flush();
stream.Close();
client.Close();
}
private void WriteHTTPResponse(StreamWriter writer, int length)
{
writer.WriteLine("HTTP/1.1 200 OK");
writer.WriteLine("Date: " + DateTime.Now.ToString());
writer.WriteLine("Content-Length: "+ length.ToString());
writer.WriteLine("Connection: close");
writer.WriteLine("Content-Type: text/html; charset=utf-8");
writer.WriteLine();
}
private void ReadHttpRequest(StreamReader reader)
{
string buffer = null;
while (buffer != "")
buffer = reader.ReadLine();
}
int counter = 0;
private string GetResponse(IPEndPoint remote)
{
counter++;
mainList.AddItem(new SensePanelItem(counter.ToString()) { PrimaryText = remote.ToString(), SecondaryText = "Response:" + counter.ToString() });
return response.Text;
}
private void EndHTML(StringBuilder writer)
{
writer.AppendLine("</body>");
writer.AppendLine("</html>");
}
private void StartHTML(StringBuilder writer)
{
writer.AppendLine("<?xml version=\"1.0\"?>");
writer.AppendLine("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">");
writer.AppendLine("<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"de\" lang=\"de\">");
writer.AppendLine("<head>");
writer.AppendLine("<title>SmartWebServer</title>");
writer.AppendLine("<meta name=\"author\" content=\"Alexander Kayed\">");
writer.AppendLine("</head>");
writer.AppendLine("<body>");
}
private void StopServer(bool restart)
{
stop = true;
serverThread.Join();
if (restart)
StartServer();
}
private void ServerForm_Load(object sender, EventArgs e)
{
StartServer();
}
private void ServerForm_Closed(object sender, EventArgs e)
{
StopServer(false);
}
private void menuItem1_Click(object sender, EventArgs e)
{
this.Close();
}
}
}
The user can choose the IPEndPoint(constructor), which the server will be bound to, in a prevouis form:
Code:
foreach (IPAddress ip in Dns.GetHostEntry(Dns.GetHostName()).AddressList)
{
item = new SensePanelRadioItem(ip.ToString());
item.PrimaryText = ip.ToString();
item.SecondaryText = ip.AddressFamily.ToString();
item.Tag = ChoosedIp = ip;
item.OnStatusChanged += new SensePanelRadioItem.StatusEventHandler(item_OnStatusChanged);
IPList.AddItem(item);
}
So the user can choose between IPs I got from the DNS (e.g. 127.0.0.1, 192.168.0.1) and type a free (valid) port number (eg. 80, 8080, 8888)
Thanks for Your help!!
Still no answer...
I will post my experiences with this issue as long as I solved it - like small blog. Maybe some of you have the same problem...
I found another strange thing:
I'm able to connect to my Server from a TcpClient from another self-written App (own exectuable, different AppDomain):
Code:
void test()
{
Action<string> setText = new Action<string>(setTestText);
try
{
this.Invoke(setText, "Connect...");
TcpClient client = new TcpClient();
client.Connect(local);
this.Invoke(setText, "Connected...");
NetworkStream stream = client.GetStream();
StreamWriter writer = new StreamWriter(stream);
StreamReader reader = new StreamReader(stream);
writer.WriteLine();
writer.Flush();
this.Invoke(setText, "Read answer");
string buffer = reader.ReadToEnd();
this.Invoke(setText, "Test succeeded");
testing = false;
}
catch
{
this.Invoke(setText, "Test failed");
}
}
And I got a the right answer as well. It's strange, really strange that the browsers (IE,Opera etc.) can't loopback to it?

Need Developer Help - Form Refreshing

Hello,
i started to wrote my first WO7 applicatin.
I got following code:
Code:
private void BtnStart_Click(object sender, RoutedEventArgs e)
{
BtnStart.Content = "Calculating...";
for (int i = 0; i < Pb1.Maximum; i++)
{
...
}
...
}
My Problem is that the content of the Button doesn't change to "Calculating". Even my Progressbar:
Code:
private void PbStep()
{
if (Pb1.Value == Pb1.Maximum)
{
Pb1.Value = 0;
MessageBox.Show("Progressbar Overflow");
}
else
{
Pb1.Value = Pb1.Value + 1;
}
}
It is wrapped in s loop, and the bar begins with 0 and then switsch to 100%, but i cant see the steps between.
I think i need a refresh command. in visual basic it is Me.Update();.
I tried many codes from google, but nothing helped. I hope some1 can help me.
many thank
Try
Code:
Dispatcher.BeginInvoke(() =>
{
BtnStart.Content = "Calculating...";
});
i did already try this. but now when i press the button, while calculation nothing happens, and after the calculation is finished, the button content changes to "calculating" and don't changes back to "start".
so i put the code in both parts and now i got the same as before. the button did not change its content
Code:
private void BtnStart_Click(object sender, RoutedEventArgs e)
{
LblDuration.Text = "";
Dispatcher.BeginInvoke(() =>
{
BtnStart.Content = "Calculating...";
});
Pb1.Value = 0.0;
Pb1.Maximum = Max;
DateTime StartZeit = DateTime.Now;
for (int i = 0; i < Pb1.Maximum; i++)
{
PbStep();//Count Up PorgressBar
}
DateTime EndZeit = DateTime.Now;
TimeSpan GemesseneZeit = EndZeit - StartZeit;
LblDuration.Text = "Duration: " + GemesseneZeit.ToString();
Dispatcher.BeginInvoke(() =>
{
BtnStart.Content = "Start";
});
}
private void PbStep()
{
try
{
Pb1.Value = Pb1.Value + 1;
}
catch
{
Pb1.Value = 0;
MessageBox.Show("Progressbar Overflow");
}
}
But thank you for your help. any other ideas?
you really need to be looking at a background thread (background worker control may allow you do do this)
any tight loop like that will freeze the UI until the loop has finished
in the 'old days' a doevents within the loop itself would have been suffice but this is not good practice
HTH
Try this one, it does what you've trying to implement but using a correct way:
Code:
using System.Windows.Threading;
private void BtnStart_Click(object sender, RoutedEventArgs e)
{
BtnStart.Content = "Calculating...";
DispatcherTimer timer = new DispatcherTimer();
timer.Interval = TimeSpan.FromMilliseconds(100);
timer.Tick += (_, __) =>
{
// Here is replacement of your PbStep()
Pb1.Value++;
};
timer.Start();
}
i got it now this way:
Code:
private void BtnStart_Click(object sender, RoutedEventArgs e)
{
LblDuration.Text = "Duration: Calculating...";
BtnStart.Content = "Wait";
DateTime StartZeit = DateTime.Now;
DispatcherTimer timer = new DispatcherTimer();
timer.Interval = TimeSpan.FromMilliseconds(1);
timer.Tick += (_, __) =>
{
for (int i = 0; i < Pb1.Maximum; i++)
{
Pb1.Value++;
}
timer.Stop();
LblDuration.Text = "Duration: " + (DateTime.Now - StartZeit).ToString();
BtnStart.Content = "Start";
};
timer.Start();
}
It is half working. When i press Start, the button changes its content imediatly and after finishing the loop it return to its default content.
now i got 2 problems:
1. the progressbar isnt smooth jet
and the bigger one:
2. i wanted to create a benchmark programm an measure how long it takes to count a progressbar from 0 to 1million. now with the timer i dont have the real cpu speed because it is always waiting for the timer to tick. so the benchmark is sensless
@ cameronm:
I know the DoEvent command from other languages, but i wans able to use this in c#. i mainly programm in visual basic, cause this seems to be easy (In this case i would use Me.Update). I have heard from the Background worker, but never tried it. Maybe this can help.
I will do some google search and try to use the Background worker. I'll post again if i got new code
Thanks you all !
hello again
im now that far:
Code:
public partial class MainPage : PhoneApplicationPage
{
//Globale Variablen
private BackgroundWorker bw = new BackgroundWorker();
public int Max = 0;
// Konstruktor
public MainPage()
{
InitializeComponent();
Max = 500000;
bw.WorkerReportsProgress = true;
bw.WorkerSupportsCancellation = true;
bw.DoWork += new DoWorkEventHandler(bw_DoWork);
bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);
bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
}
private void BtnStart_Click(object sender, RoutedEventArgs e)
{
if (bw.IsBusy != true)
{
LblDuration.Text = "";
BtnStart.Content = "Calculating...";
Pb1.Value = 0.0;
Pb1.Maximum = Max;
bw.RunWorkerAsync();
}
}
private void BtnStop_Click(object sender, System.Windows.RoutedEventArgs e)
{
if (bw.WorkerSupportsCancellation == true)
{
bw.CancelAsync();
}
}
private void bw_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
DateTime StartZeit = DateTime.Now;
//Failure by any deklarion
//like int i = 0 or BtnStart.Content = "Calculating...";
for (int i = 0; i < Pb1.Maximum; i++)
{
if ((worker.CancellationPending == true)) //Abbruchbedingung
{
e.Cancel = true;
break;
}
else //Progressbedingung
{
PbStep();//Count Up PorgressBar
}
}
DateTime EndZeit = DateTime.Now;
TimeSpan GemesseneZeit = EndZeit - StartZeit;
LblDuration.Text = "Duration: " + GemesseneZeit.ToString();
BtnStart.Content = "Start";
}
private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if ((e.Cancelled == true))
{
this.LblStatus.Text = "Canceled!";
}
else if (!(e.Error == null))
{
this.LblStatus.Text = ("Error: " + e.Error.Message);
}
else
{
this.LblStatus.Text = "Done!";
}
}
private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
this.LblPercentage.Text = (e.ProgressPercentage.ToString() + "%");
}
private void PbStep()
{
try
{
Pb1.Value = Pb1.Value + 1;
}
catch
{
Pb1.Value = 0;
MessageBox.Show("Progressbar Overflow");
}
}
In the DoWork Function i receive an error when i try to set a variable like int i=0.
The Failure:UnauthorizedAccessException: Invalid cross-thread access
i followed this instruction: http://msdn.microsoft.com/en-us/library/cc221403(v=vs.95).aspx
but there they did the same. why did i have the error?
win98 said:
The Failure:UnauthorizedAccessException: Invalid cross-thread access
why did i have the error?
Click to expand...
Click to collapse
The exception you've got show exactly what's wrong: you are trying to access GUI thread variables from another (BackgroundWorker) thread.
Use Dispatcher.Invoke as I recommended to you a few posts above.
thank you sensboston. id dont understand why, because i just have one bgworker, but now it works
Code:
private void BtnStart_Click(object sender, RoutedEventArgs e)
{
if (bw.IsBusy != true)
{
LblDuration.Text = "";
BtnStart.Content = "Calculating...";
Pb1.Value = 0.0;
Pb1.Maximum = Max;
bw.RunWorkerAsync();
}
}
private void bw_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
DateTime StartZeit = DateTime.Now;
Dispatcher.BeginInvoke(() =>
{
LblDuration.Text = "";
BtnStart.Content = "Calculating...";
for (int i = 0; i < Pb1.Maximum; i++)
{
if ((worker.CancellationPending == true)) //Abbruchbedingung
{
e.Cancel = true;
break;
}
else //Progressbedingung
{
Pb1.Value = Pb1.Value + 1;
//PbStep();
}
}
DateTime EndZeit = DateTime.Now;
TimeSpan GemesseneZeit = EndZeit - StartZeit;
LblDuration.Text = "Duration: " + GemesseneZeit.ToString();
BtnStart.Content = "Start";
});
}
private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
this.LblPercentage.Text = (e.ProgressPercentage.ToString() + "%");
}
Just my progressbar isnt running fluently. still just 0% (before calc) or 100% (after calc) and no steps between
win98 said:
Just my progressbar isnt running fluently. still just 0% (before calc) or 100% (after calc) and no steps between
Click to expand...
Click to collapse
It's simple, dear Watson: your code updating progress bar too fast, without delays needed for GUI updates
sensboston said:
It's simple, dear Watson: your code updating progress bar too fast, without delays needed for GUI updates
Click to expand...
Click to collapse
yep agree with this .. what you are actually doing in the loop is not enough for you to acutally see the progressbar update .. fast little things these phones of ours
yeah, this was the first i tryed, before posting in this forum.
delay() did not work in c#.
Application.DoEvents() should work if i can believe google, but visual studio says there is no definition for doevents().
So i used
Code:
Pb1.Value++;
System.Threading.Thread.Sleep(1);
after each progressbar.value++, but this either didnt work...
what is the secret?
win98 said:
yeah, this was the first i tryed, before posting in this forum.
delay() did not work in c#.
Application.DoEvents() should work if i can believe google, but visual studio says there is no definition for doevents().
So i used
Code:
Pb1.Value++;
System.Threading.Thread.Sleep(1);
after each progressbar.value++, but this either didnt work...
what is the secret?
Click to expand...
Click to collapse
1 millisecond will not be enough to slow it down either
Maybe try 1000 instead ..
something else i thought of too ..
you may want to think about your design
If a progress bar is going to just flash up and complete as what you are doing is too fast .. you need to think 'is a progress bar the right control to use'
if you are going to increase the amount of work your background thread is going to do then I would say keep the progress bar
If the background thread is going to be this quick always .. then maybe a label saying 'please wait' ... and then hide the label when done .. or something similar
i tried with 1000 ms but this progress bar isnt running.
@cameronm: i want to create a "benchmark app" where the cpu counts the progressbar to 1million and measures the time. the time measuring is working correctly. i just want to get a nice GUI with a running bar, like it runs when you download and install apps from the market.
i was very long googling and found commands like progressbar.PerfomStep(); like described here http://www.java2s.com/Code/CSharp/GUI-Windows-Form/ProgressBarinC.htm
this is also c#, but i cant perfom this command. did i miss some assembly, headers or so? or is it because im doint a windows phone form and that there are less command than in a normal windows application?
You want to make a Benchmark app and you actually used :System.Threading.Thread.Sleep(*int)...!
This is not Benchmarking.
Background Worker like any other ThreadTypeClass should report it's progress via the BackgroundWorker_ProgressChanged_Event(..args).
Inside the Event either u PerformStep() either you implement your own code logic.
If even after this the worker fills instanly like "cameronm" said above then consider making the backgroundworker's Job a bit heavier or leave the progressBar and even the seperated background thread Idea cause it is not Needed.
yes, i am not luck with using a sleep command
PerformStep() is not accepted by the compiler
so you mean just counting up is to "easy". what progress could be "heavier". now i understand what cameronm meant^^
in the evening i will try more difficult calculations like sqare and multiplication of integers. would that be heavy enough?
Typing from LG quantum
Try this: make your calculations in a for loop 1-100..at each loop make progressbar.value++ .
You should be calling ReportProgress and then updating the Progress Bar in the Progress Changed function.
See: http://msdn.microsoft.com/en-us/library/cc221403(v=vs.95).aspx
@PG2G
the link you posted was exactly the source where i learned to implement the bw_worker. but with the command you told me i got an failure in the marked line (see source code comment). It says: InvalidOperationException: Operation has already been completed.
Code:
private void bw_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
double a, b, c;
DateTime StartZeit = DateTime.Now;
Dispatcher.BeginInvoke(() =>
{
LblDuration.Text = "";
BtnStart.Content = "Calculating...";
for (int i = 0; i < Pb1.Maximum/100; i++)
{
if ((worker.CancellationPending == true))
{
e.Cancel = true;
break;
}
else
{
for (int m = 0; m < 10; m++)
{
a = 3547.23; //double
b = 2354.15; //double
c = (a * b) * (a * a * b);
}
Pb1.Value++;//PbStep();
worker.ReportProgress((i * 10)); //Failure here//
}
}
DateTime EndZeit = DateTime.Now;
TimeSpan GemesseneZeit = EndZeit - StartZeit;
LblDuration.Text = "Duration: " + GemesseneZeit.ToString();
BtnStart.Content = "Start";
});
}
@Freeboss
i tried it with your loop and a double calculation but it didnt work...
im going crazy, in vb i can do this in 10 minutes^^

MAPIdotnet and binary message body

Best all,
A while ago I tried to make a simple application which can export all my smses and mmses to my local database server. It runs quite smoothly but I can't manage to get the correct mms body data. It seems that about 5% of the exported body data(for example a sent picture in jpeg format) is different from the original jpeg picture/body data: the exported picture data can't be viewed, it is corrupt.
I suspect the method of exporting the data must be changed from string to binary, but I don't know exactly how to proceed.
I'm using C# 2008 in combination with the MAPIdotnet library, and my target device is a HTC HD Mini with Windows Mobile 6.5 professional.
The part of my code where it's going wrong:
Code:
ASCIIEncoding asen = new ASCIIEncoding();
byte[] ba = asen.GetBytes(s);
bw.Write(ba);
bw.Close();
fs.Close();
if (messages[msgID].Body != null)
{
FileStream fs2 = File.Create("\\Opslagkaart\\Debug\\body_" + Convert.ToString(msgID) + ".dat");
BinaryWriter bw2 = new BinaryWriter(fs2);
System.Text.UnicodeEncoding enc = new System.Text.UnicodeEncoding();
byte[] file = enc.GetBytes(messages[msgID].Body);
//bw2.Write(messages[msgID].Body);
bw2.Write(file);
bw2.Close();
fs2.Close();
}
In combination with MAPIdotnet's code:
Code:
public string Body
{
get
{
IStreamChar s = (IStreamChar)this.msg.OpenProperty(cemapi.PropTags.PR_BODY, 0);
if (s == null)
return "";
IntPtr p = Marshal.AllocHGlobal(4);
char[] b = new char[3];
StringBuilder str = new StringBuilder();
int c, len = b.Length * 2;
do
{
s.Read(b, len, p);
c = Marshal.ReadInt32(p);
str.Append(new string(b, 0, c / 2));
}
while (c >= len);
Marshal.FreeHGlobal(p);
return str.ToString();
}
}
Can somebody give a hint of how to proceed?
Thanks,
I suddenly got some more inspiration and, with help from google, I've managed to correctly retrieve the binary jpeg attachments of two of my mmses.
The code part of my program:
Code:
//if (messages[msgID].BodyBinary.Length>0)
//{
FileStream fs2 = File.Create("\\Opslagkaart\\Debug\\body_" + Convert.ToString(msgID) + ".dat");
BinaryWriter bw2 = new BinaryWriter(fs2);
bw2.Write(messages[msgID].BodyBinary);
bw2.Close();
fs2.Close();
//}
The code part of the customized MAPIdotnet:
Code:
private static IntPtr ReadBuffer;
static int Read(OpenNETCF.Runtime.InteropServices.ComTypes.IStream strm, byte[] buffer)
{
if (ReadBuffer == IntPtr.Zero) ReadBuffer = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(int)));
try
{
strm.Read(buffer, buffer.Length, ReadBuffer);
}
catch (NullReferenceException e)
{
//do nothing
}
return Marshal.ReadInt32(ReadBuffer);
}
public byte[] BodyBinary
{
get
{
int buffsize = 1024*1024*2; /* If mms body is bigger than 2MB we have a problem here */
byte[] buffer = new byte[buffsize];
Read(this.msg.OpenProperty(cemapi.PropTags.PR_BODY, 0), buffer);
byte[] data = buffer;//ms.ToArray();
Marshal.FreeCoTaskMem(ReadBuffer);
return data;
}
}
But now ALL bodies are saved as 2MB files.. including the empty ones from for example a sms. And not all mms bodies are of the max size of 2mb. My carrier/phone supports up to 1MB. Perhaps I need to get some 'dynamic size' buffer instead of the fixed one. Does anyone have an idea on how to determine the size of the
this.msg.OpenProperty(cemapi.PropTags.PR_BODY, 0)
Click to expand...
Click to collapse
stream ?
I've solved all my problems by means of the following code (for mapidotnet):
Code:
private static IntPtr ReadBuffer;
static int Read(OpenNETCF.Runtime.InteropServices.ComTypes.IStream strm, byte[] buffer)
{
int returnvalue = 0;
if (ReadBuffer == IntPtr.Zero) ReadBuffer = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(int)));
try
{
strm.Read(buffer, buffer.Length, ReadBuffer);
returnvalue = Marshal.ReadInt32(ReadBuffer);
}
catch (NullReferenceException e)
{
returnvalue = 0;
}
return returnvalue;
}
public byte[] BodyBinary
{
get
{
int newdatasize = 0;
int buffsize = 1024*1024*3; /* If mms body is bigger than 3MB we have a problem here */
byte[] buffer = new byte[buffsize];
newdatasize = Read(this.msg.OpenProperty(cemapi.PropTags.PR_BODY, 0), buffer);
if (newdatasize < 0) { newdatasize = 0; }
byte[] data = new byte[newdatasize];
Buffer.BlockCopy(buffer, 0, data, 0, newdatasize);
Marshal.FreeCoTaskMem(ReadBuffer);
return data;
}
}
Now all is working fine and the exported files are of their own real size. I'm sure the above code can be optimized but it's working good now.

[Q] How to read store.vol file Windows phone 7

Hello!
I have file store.vol copy from Windows phone device(HTC HD7). I use EDB API to read it.
My problem: I could not open store.vol file. ERROR_BAD_FORMAT.
How can I open this file.
Thanks!!!
My code:
Code:
#include "stdafx.h"
#include "Winphone7_Lib.h"
#include "clsReadEDB.h"
#include <iosfwd>
#define EDB
extern "C"
{
#include <windbase_edb.h>
}
// clsReadEDB
IMPLEMENT_DYNAMIC(clsReadEDB, CWnd)
clsReadEDB::clsReadEDB()
{
}
void clsReadEDB::readFile(char* path)
{
CEGUID guid;
CEVOLUMEOPTIONS cevo = {0};
cevo.wVersion = 1;
CEOIDINFOEX oidInfo = {0};
wchar_t buff[250];
HANDLE hSes, hBD, hBDS;
BOOL rez;
rez = CeMountDBVolEx(&guid, L"store.vol", &cevo,OPEN_EXISTING);
if (rez == FALSE) {
}
DWORD dw = GetLastError();
hBD = CeFindFirstDatabaseEx(&guid, 0);
if (hBD != INVALID_HANDLE_VALUE)
{
oidInfo.wVersion = CEOIDINFOEX_VERSION;
oidInfo.wObjType = OBJTYPE_DATABASE;
//creare sesiune
hSes = CeCreateSession(&guid);
if (hSes == INVALID_HANDLE_VALUE) {/* error */}
CEOID oidBD = CeFindNextDatabaseEx(hBD, &guid);
while (oidBD != 0)
{
//obtain database information
rez = CeOidGetInfoEx2(&guid, oidBD, &oidInfo);
if (rez != TRUE) {/* error */}
//open database
hBDS = CeOpenDatabaseInSession(hSes, &guid, &oidBD,
oidInfo.infDatabase.szDbaseName, NULL, CEDB_AUTOINCREMENT, NULL);
if (hBDS == INVALID_HANDLE_VALUE) {/* error */}
PCEPROPVAL pInreg = NULL;
PBYTE pBuffInreg = NULL;//memory is allocated by function
WORD wProp;//number of properties
DWORD dwLgInreg;// record lengths
//memory is allocatd by function
CEOID ceoid = CeReadRecordPropsEx(hBDS, CEDB_ALLOWREALLOC, &wProp, NULL,
&(LPBYTE)pBuffInreg, &dwLgInreg, NULL);
int k = 0;
while(ceoid != 0)
{
pInreg = (PCEPROPVAL)pBuffInreg;
//for each field
for (int i = 0; i < wProp; i++)
{
switch(LOWORD(pInreg->propid))
{
case CEVT_LPWSTR:
//process string values
break;
//integers
case CEVT_I2:
case CEVT_I4:
case CEVT_UI2:
case CEVT_UI4:
case CEVT_BLOB:
case CEVT_BOOL:
//process integer values
break;
case CEVT_R8:
//process floating point values
break;
default:
//other types
break;
}
OutputDebugString(buff);
//next field
pInreg++;
}
LocalFree(pBuffInreg);
//next record
ceoid = CeReadRecordPropsEx(hBDS, CEDB_ALLOWREALLOC, &wProp, NULL,
&(LPBYTE)pBuffInreg, &dwLgInreg, NULL);
k++;
}
CloseHandle(hBDS);
//next database
oidBD = CeFindNextDatabaseEx(hBD, &guid);
}
CloseHandle(hBD);
CloseHandle(hSes);
}
CeUnmountDBVol(&guid);
}
clsReadEDB::~clsReadEDB()
{
}

Categories

Resources