I have a form with a progress bar and a button that uploads an xml to a server.
While the button is pressed a new thread is created that creates a socket and then it sends the data to the server in chunks and in the meanwhile it updates the progress bar.
Now, when the upload button is pressed for a second time i get an access violation and in the debugger the address of the Progress Bar object is NULL.
I can't figure out why the Progress Bar is getting freed so if anyone has any idea i would be grateful.
P.S. The target OS is windows
P.S.2 If the same code runs on the main thread without the usage of a thread then i don't seem to have this issue and even if i skip the usage of the progress bar in overall in the thread it is set to null again after the first push of the upload button.
The thread Constructor:
__fastcall UploadRouteThread::UploadRouteThread(bool CreateSuspended) : TThread(CreateSuspended)
{
this->OnTerminate = OnTerminateHandler;
ioHandlerStack = new TIdIOHandlerStack();
tcpClient = new TIdTCPClient();
tcpClient->ReadTimeout = -1;
tcpClient->UseNagle = true;
tcpClient->IOHandler = ioHandlerStack;
tcpClient->OnConnected = OnConnectedHandler;
}
The OnTerminate handler:
void __fastcall UploadRouteThread::OnTerminateHandler(TObject *Sender)
{
TabbedwithNavigationForm->UploadButton->Text = "Upload";
TabbedwithNavigationForm->UploadButton->Enabled = false;
TabbedwithNavigationForm->ProgressBar->Visible = false;
tcpClient->DisconnectNotifyPeer();
ShowMessage("Data uploaded.");
delete ioHandlerStack;
delete tcpClient;
TabbedwithNavigationForm->OptionButton->Enabled = true;
TabbedwithNavigationForm->RetrieveRoutesButton->Enabled = true;
TabbedwithNavigationForm->TrackButton->Enabled = true;
TabbedwithNavigationForm->MediaButton->Enabled = true;
}
The Execute method:
void __fastcall UploadRouteThread::Execute()
{
FreeOnTerminate = true;
tcpClient->Connect();
}
Two supplumentary functions:
void __fastcall UploadRouteThread::SetHostPort(UnicodeString host, unsigned short port)
{
tcpClient->Host = host;
tcpClient->Port = port;
}
void __fastcall UploadRouteThread::SetXML(AnsiString xmlString)
{
this->xmlString = xmlString;
}
The OnConnect Handler:
void __fastcall UploadRouteThread::OnConnectedHandler(TObject *Sender)
{
NextPacketSize nps;
TIdBytes bytes;
int chunks;
int bytesLength;
nps.PacketID = BasicPacket::DATA_UPLOAD;
nps.size = xmlString.Length();
tcpClient->IOHandler->WriteDirect(RawToBytes(&nps, sizeof(nps)), sizeof(NextPacketSize));
bytes = RawToBytes(xmlString.c_str(), xmlString.Length());
bytesLength = bytes.get_length();
chunks = ceil(float(bytesLength) / 256.0);
int previousSizeSent(0);
for(int i = 1; i <= chunks; i++)
{
if(Terminated)
break;
int bytesToSend = 256;
TByteDynArray byteDynArray;
if((bytesToSend > bytesLength))
{
bytesToSend = bytesLength;
}
byteDynArray = bytes.CopyRange(previousSizeSent, bytesToSend);
tcpClient->IOHandler->WriteDirect(ToBytes(byteDynArray, byteDynArray.get_length(), 0),
byteDynArray.get_length());
sent = (float(i) / float(chunks)) * 100;
TThread::Synchronize(this, UpdateProgressBarInternal);
previousSizeSent += bytesToSend;
bytesLength -= bytesToSend;
}
}
And the Update method for the progress bar:
void __fastcall UploadRouteThread::UpdateProgressBarInternal()
{
if(!TabbedwithNavigationForm->ProgressBar->Visible)
{
TabbedwithNavigationForm->ProgressBar->Visible = true;
TabbedwithNavigationForm->ProgressBar->Max = 100;
}
TabbedwithNavigationForm->ProgressBar->Value = sent;
}
I don't see anything in this code that would cause the ProgressBar pointer to become NULL. So either you are corrupting memory, or something else in other code not shown here is the culprit. Either way, to troubleshoot this you can run your app in the IDE debugger and set a Data Breakpoint on the ProgressBar variable before you run your thread for the first time. If something changes the value of that pointer, the breakpoint will be hit, and you can look at the call stack to figure out what is happening.
With that said, your thread is not very well organized. And there is a much simpler way to handle the chunking - let Indy do it for you. It has an OnWork event that you can use for your ProgressBar updates.
Try something more like this:
__fastcall UploadRouteThread::UploadRouteThread(String host, TIdPort port, AnsiString xmlString)
: TThread(false)
{
this->FreeOnTerminate = true;
this->OnTerminate = OnTerminateHandler;
this->xmlString = xmlString;
tcpClient = new TIdTCPClient();
tcpClient->Host = host;
tcpClient->Port = port;
tcpClient->UseNagle = true;
tcpClient->OnWork = OnWorkHandler;
}
__fastcall UploadRouteThread::~UploadRouteThread()
{
delete tcpClient;
}
void __fastcall UploadRouteThread::OnTerminateHandler(TObject *Sender)
{
TabbedwithNavigationForm->UploadButton->Text = "Upload";
TabbedwithNavigationForm->UploadButton->Enabled = false;
TabbedwithNavigationForm->ProgressBar->Visible = false;
if (FatalException)
ShowMessage("Data not uploaded.");
else
ShowMessage("Data uploaded.");
TabbedwithNavigationForm->OptionButton->Enabled = true;
TabbedwithNavigationForm->RetrieveRoutesButton->Enabled = true;
TabbedwithNavigationForm->TrackButton->Enabled = true;
TabbedwithNavigationForm->MediaButton->Enabled = true;
}
void __fastcall UploadRouteThread::OnWorkHandler(TObject *ASender, TWorkMode AWorkMode, __int64 AWorkCount)
{
if (Terminated)
Sysutils::Abort();
sent = (double(AWorkCount) * 100.0) / xmlString.Length();
// consider using TThread::Queue() instead so that you don't block
// the upload waiting for the UI to be updated...
TThread::Synchronize(this, &UpdateProgressBarInternal);
}
void __fastcall UploadRouteThread::Execute()
{
tcpClient->Connect();
try
{
NextPacketSize nps;
nps.PacketID = BasicPacket::DATA_UPLOAD;
nps.size = xmlString.Length();
tcpClient->IOHandler->Write(RawToBytes(&nps, sizeof(nps)));
tcpClient->BeginWork(wmWrite, xmlString.Length());
tcpClient->IOHandler->Write(RawToBytes(xmlString.c_str(), xmlString.Length()));
tcpClient->EndWork(wmWrite);
/* alternatively:
TIdMemoryBufferStream *strm = new TIdMemoryBufferStream(xmlString.c_str(), xmlString.Length());
try
{
// optional
tcpClient->IOHandler->SendBufferSize = 256;
// this calls (Begin|End)Work() internally...
tcpClient->IOHandler->Write(strm, 0, false);
}
__finally
{
delete strm;
}
*/
}
__finally
{
tcpClient->Disconnect();
}
}
void __fastcall UploadRouteThread::UpdateProgressBarInternal()
{
if (!TabbedwithNavigationForm->ProgressBar->Visible)
{
TabbedwithNavigationForm->ProgressBar->Visible = true;
TabbedwithNavigationForm->ProgressBar->Max = 100;
}
TabbedwithNavigationForm->ProgressBar->Value = sent;
}
Related
I created a widget, added some Sprites and made some animation. I want to add some user interaction but handelEvent method is not working. I already set userInteractionEnabled to true.
I tried debugging and place a breakpoint inside the handleEvent method but it didn't stop when I touched the screen.
class MainSceneBackgroundNode extends NodeWithSize {
Sprite _logo;
RepeatedImage _background;
GuyImage _guy;
int _i = 0;
int _j = 0;
int _dir = -1;
MainSceneBackgroundNode() : super(new Size(2560.0, 1440.0)) {
userInteractionEnabled = true;
handleMultiplePointers = false;
// Add background
_background = new RepeatedImage(_imageMap["assets/background.png"]);
addChild(_background);
_guy = new GuyImage();
addChild(_guy);
_logo = new Sprite.fromImage(_imageMap["assets/logo.gif"]);
_logo.pivot = Offset.zero;
_logo.size = new Size(912, 486);
_logo.position = new Offset(824, 10);
addChild(_logo);
}
#override
bool handleEvent(SpriteBoxEvent event) {
if (event.type == PointerDownEvent) {
if (event.boxPosition.dx < 1280) {
_dir = -1;
} else {
_dir = 1;
}
}
return true;
}
...
}
Any suggestion will be appreciated. I don't know what else to do.
Thanks in Advance.
I am developing a POS application in windows 8.1 (Universal App).
Order receipt will be printed from the application and even I am able to do so.
Printer - EPSON TM-U220D
Input - A grid is being created pragmatically with dynamic content within the ViewModel. So this grid is the input for printer
Output - In the print preview (Attahced pic 1) all looks good but when the receipt is actually printed then content is cut off from the end (Attahced pic 2)
PIC 1
PIC 2
Observations -
If I print a normal text file manually using print command (Right click file and then print), then all content is printed perfectly.
If I print that SAME content, from the application, by creating Dynamic grid, then with Small font size print is good but with bit bigger font size content again cuts off.
Tried -
Optimized the code for Creating Gird, by specifying height
Questions-
If preview is all good then why not output
Did anyone tried using ePOS-Print_SDK_141020E for Windows Store app?
Generate Dynamic Grid Code
private void AddRows(Grid grid, int count)
{
for (int i = 0; i < count; i++)
{
RowDefinition row = new RowDefinition();
row.Height = GridLength.Auto;
grid.RowDefinitions.Add(row);
}
}
private void AddColumns(Grid grid, int count)
{
for (int i = 0; i < count; i++)
{
grid.ColumnDefinitions.Add(new ColumnDefinition());
}
}
private TextBlock CreateTextBlock(string text, Color color, FontWeight fw, double fs = 10, int thick = 5)
{
if (color == null) color = Colors.Black;
TextBlock txtBlock1 = new TextBlock();
txtBlock1.Text = text;
txtBlock1.FontSize = fs;
txtBlock1.FontWeight = fw;
txtBlock1.Foreground = new SolidColorBrush(color);
txtBlock1.VerticalAlignment = VerticalAlignment.Center;
txtBlock1.Margin = new Thickness(thick);
return txtBlock1;
}
private async Task<Grid> CreateDynamicWPFGrid()
{
Grid ParentGrid = new Grid();
AddRows(ParentGrid, 8);
/* Start First Grid*/
Grid DynamicGrid = new Grid();
DynamicGrid.Width = 230;
DynamicGrid.HorizontalAlignment = HorizontalAlignment.Left;
DynamicGrid.VerticalAlignment = VerticalAlignment.Top;
DynamicGrid.Margin = new Thickness(24, 0, 0, 0);
AddColumns(DynamicGrid, 2);
AddRows(DynamicGrid, 3);
TextBlock txtBlock1 = CreateTextBlock(DateTime.Now.ToString("M/d/yy"), Colors.Black, FontWeights.Normal);
Grid.SetRow(txtBlock1, 0);
Grid.SetColumn(txtBlock1, 1);
.
.
.
.
Return ParentGrid;
}
Printer Events Code
//Register Print Contract
async Task RegisterPrintContract()
{
PrintManager manager = PrintManager.GetForCurrentView();
manager.PrintTaskRequested += OnPrintTaskRequested;
await PrintManager.ShowPrintUIAsync();
}
//Unregister Print Contract
void UnregisterPrintContract()
{
PrintManager printMan = PrintManager.GetForCurrentView();
printMan.PrintTaskRequested -= OnPrintTaskRequested;
}
void OnPrintTaskRequested(PrintManager sender, PrintTaskRequestedEventArgs args)
{
// If I need to be asynchronous, I can get a deferral. I don't *need*
// to do this here, I'm just faking it.
var deferral = args.Request.GetDeferral();
PrintTask printTask = args.Request.CreatePrintTask("My Print Job", OnPrintTaskSourceRequestedHandler);
printTask.Completed += OnPrintTaskCompleted;
deferral.Complete();
}
void OnPrintTaskCompleted(PrintTask sender, PrintTaskCompletedEventArgs args)
{
// TODO: Tidy up.
this._document = null;
this._pages = null;
}
async void OnPrintTaskSourceRequestedHandler(PrintTaskSourceRequestedArgs args)
{
var deferral = args.GetDeferral();
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
() =>
{
this._document = new PrintDocument();
this._document.Paginate += OnPaginate;
this._document.GetPreviewPage += OnGetPreviewPage;
this._document.AddPages += OnAddPages;
// Tell the caller about it.
args.SetSource(this._document.DocumentSource);
});
deferral.Complete();
}
void OnAddPages(object sender, AddPagesEventArgs e)
{
// Loop over all of the preview pages and add each one to add each page to be printied
// We should have all pages ready at this point...
foreach (var page in this._pages)
{
//this._pages[page.Key]
this._document.AddPage(this._pages[page.Key]);
}
PrintDocument printDoc = (PrintDocument)sender;
// Indicate that all of the print pages have been provided
printDoc.AddPagesComplete();
}
async void OnGetPreviewPage(object sender, GetPreviewPageEventArgs e)
{
Grid x = await CreateDynamicWPFGrid();
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
() =>
{
// NB: assuming it's ok to keep all these pages in
// memory. might not be the right thing to do
// of course.
if (this._pages == null)
{
this._pages = new Dictionary<int, UIElement>();
}
if (!this._pages.ContainsKey(e.PageNumber))
{
this._pages[e.PageNumber] = x;
}
if (this._document == null)
this._document = new PrintDocument();
this._document.SetPreviewPage(e.PageNumber, this._pages[e.PageNumber]);
}
);
}
async void OnPaginate(object sender, PaginateEventArgs e)
{
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
() =>
{
// I have one page and that's *FINAL* !
this._document.SetPreviewPageCount(e.CurrentPreviewPageNumber, PreviewPageCountType.Final);
});
}
I have written an indy http server, I want to serve file download with resume support. When I use IDM to download file, the download is single threaded:
Note that the Resume capability is Yes, but When I pause and resume the download, It starts form beginning.
My Indy Http Server is as:
void __fastcall TfrmMain::httpServerCommandGet(TIdContext *AContext,
TIdHTTPRequestInfo *ARequestInfo, TIdHTTPResponseInfo *AResponseInfo)
{
Beep(1000, 100);
string fileName = ExtractFileDir(Application->ExeName) + ARequestInfo->Document;
fileName = fileName.replace("/", "\\");
TFileStream *stream = new TFileStream(fileName, fmOpenRead | fmShareDenyNone);
int start = 0, end = 0;
string range = ARequestInfo->Range;
if(!range.empty())
{
int dash_pos = range.find("-");
start = range.substr(0, dash_pos).intValue();
end = range.substr(dash_pos + 1).intValue();
if(end == 0) // Endless Range: start-
end = stream->Size;
}
else
{
start = 0;
end = stream->Size;
}
OutputDebugStringW(string("ctx=[] start=[] end=[]") <<
IntToHex((int)AContext, 8) << start << end);
stream->Seek((__int64)start, soBeginning);
AResponseInfo->ContentStream = stream;
AResponseInfo->FreeContentStream = true;
AResponseInfo->ContentLength = stream->Size;
if(!range.empty())
{
AResponseInfo->ContentRangeStart = start;
AResponseInfo->ContentRangeEnd = end;
AResponseInfo->ResponseNo = 206;
AResponseInfo->ContentRangeInstanceLength = end + 1;
AResponseInfo->ContentLength = end - start + 1;
AResponseInfo->AcceptRanges = "bytes";
}
AResponseInfo->WriteHeader();
AResponseInfo->WriteContent();
}
any help would be appreciated.
The IdCustomHTTPServer unit has a TIdHTTPRangeStream helper class for this very purpose.
If the client requests a ranged download, create an instance of TIdHTTPRangeStream and pass it your intended TStream and the client's requested range, then assign it as the ContentStream to be sent. TIdHTTPRangeStream also has a ResponseCode property that you need to assign to the response's ResponseNo property.
For example:
void __fastcall TfrmMain::httpServerCommandGet(TIdContext *AContext, TIdHTTPRequestInfo *ARequestInfo, TIdHTTPResponseInfo *AResponseInfo)
{
// create file stream ...
// THTTPServer parses the ranges for you
if (ARequestInfo->Ranges->Count > 0)
{
if (ARequestInfo->Ranges->Count > 1)
{
AResponseInfo->ResponseNo = 416;
return;
}
TIdEntityRange *range = ARequestInfo->Ranges->Range[0];
TIdHTTPRangeStream *rstream = new TIdHTTPRangeStream(stream, range->StartPos, range->EndPos, true);
AResponseInfo->ResponseNo = rstream->ResponseCode;
AResponseInfo->ContentRangeStart = rstream->RangeStart;
AResponseInfo->ContentRangeEnd = rstream->RangeEnd;
AResponseInfo->ContentStream = rstream;
AResponseInfo->AcceptRanges = "bytes";
}
else
{
AResponseInfo->ContentStream = stream;
}
// no need to seek the target stream manually
// no need to set the ContentLength manually
// no need to call WriteHeader() and WriteContent() manually
//
// TIdHTTPServer handles all that for you internally!
}
I have the following code which is used to Push and Pend from a queue. The caller code has multiple MsgQ objects. It is possible that the Push and the Pend functions are waiting on the _notFull->wait() and the _notEmpty->wait() conditional waits. These waits are protected by the _mut mutex. The notFull and the notEmpty waits operate on the empty and full variables.
When the destructor is called, the _deleteQueue is called internally, from which I would like to signal to the waiting threads to cleanup and stop waiting for a signal to come. Once that is done, I delete my objects. However, in the _deleteQueue function, when I attempt to do _mut->acquire(), I am unable to acquire the mutex. Even if I ignore the acquire, I am unable to broadcast to these waiting threads. Where am I going wrong?
Thanks,
Vikram.
MsgQ::~MsgQ()
{
_deleteQueue();
delete _mut;_mut=NULL;
delete _notFull;_notFull=NULL;
delete _notEmpty;_notEmpty=NULL;
delete _PostMutex; _PostMutex = NULL;
delete _PendMutex; _PendMutex = NULL;
delete _PostInProgressMutex; _PostInProgressMutex = NULL;
delete _PendInProgressMutex; _PendInProgressMutex = NULL;
delete _DisconnectMutex; _DisconnectMutex = NULL;
free( _ptrQueue ); _ptrQueue = NULL;
}
int MsgQ::Post(Message* msg)
{
_PostMutex->acquire();
_postInProgress++;
_PostMutex->release();
if (msg)
msg->print();
_mut->acquire();
while (full)
{
_notFull->wait();
}
if (!_disconnectInProgress)
_queuePush(msg);
_mut->release();
_PostMutex->acquire();
_postInProgress--;
if (_postInProgress==0)
{
_PostInProgressMutex->signal();
}
_PostMutex->release();
return _notEmpty->signal();
}
int MsgQ::Pend(Message*& msg)
{
_PendMutex->acquire();
_pendInProgress++;
_PendMutex->release();
_mut->acquire();
while (empty)
_notEmpty->wait();
if (!_disconnectInProgress)
{
_queuePop(msg);
}
_mut->release();
_PendMutex->acquire();
_pendInProgress--;
if (_pendInProgress == 0)
{
_PendInProgressMutex->signal();
}
_PendMutex->release();
return _notFull->signal();
}
void MsgQ::_deleteQueue ()
{
_PostMutex->acquire();
if (_postInProgress != 0)
{
_PostMutex->release();
TRACE("Acquiring Mutex.");
_mut->acquire();
full = 0;
_notFull->broadcast();
_mut->release();
_PostInProgressMutex->wait();
}
else
{
_PostMutex->release();
}
_PendMutex->acquire();
if (_pendInProgress != 0)
{
_PendMutex->release();
TRACE("Acquiring Mutex.");
_mut->acquire();
empty = 0;
_notEmpty->broadcast();
_mut->release();
_PendInProgressMutex->wait();
}
else
{
_PendMutex->release();
}
}
void MsgQ::_initQueue()
{
_ptrQueue = (Message **)(malloc (size * sizeof (Message*)));
if (_ptrQueue == NULL)
{
cout << "queue could not be created!" << endl;
}
else
{
for (int i = 0; i < size; i++)
*(_ptrQueue + i) = NULL;
empty = 1;
full = 0;
head = 0;
tail = 0;
try{
_mut = new ACE_Mutex() ;
_notFull = new ACE_Condition<ACE_Mutex>(*_mut);
_notEmpty = new ACE_Condition<ACE_Mutex>(*_mut);
_PostMutex = new ACE_Mutex();
_PendMutex = new ACE_Mutex();
_PostInProgressMutex = new ACE_Condition<ACE_Mutex>(*_PostMutex);
_PendInProgressMutex = new ACE_Condition<ACE_Mutex>(*_PendMutex);
_DisconnectMutex = new ACE_Mutex();
_postInProgress = 0;
_pendInProgress = 0;
_disconnectInProgress = false;
}catch(...){
cout << "you should not be here" << endl;
}
}
}
There seem to be many problems with the code so I would suggest reworking it:
You have a potential for deadlock because you are acquiring _mut before you go into a wait condition in both Post and Pend functions.
Instead of using acquire and release on a ACE_Mutex I would suggest looking at using ACE_Guard class which can acquire mutex when created and release it when destroyed.
Why not use ACE_Message_Queue instead of creating your own?
I have made an 3D Game with DirectX9.0.
I want to load resources in background mode by use thread.
Here is my code.
----------------Attakc.h---------------------------
#define AFXBEGINTHREAD(pfnThreadProc,pParam) AfxBeginThread(pfnThreadProc, pParam, THREAD_PRIORITY_NORMAL,0,CREATE_SUSPENDED,NULL)
CWinThread* g_pThread = NULL;
volatile bool g_bExitThread = true;
CCriticalSection g_csExitThread;
----------------Attakc.cpp---------------------------
...
case WM_START:
if(wParam >= 0 && wParam < 18)
{
g_csExitThread.Lock();
g_bExitThread = false;
g_csExitThread.Unlock();
g_pThread = AFXBEGINTHREAD(ThreadFunc,0);
if(NULL == g_pThread)
{
MessageBoxW(0,L"Failed to Create Thread",0,0);
}
g_pThread->m_bAutoDelete = TRUE;
g_pThread->ResumeThread();
wParamTemp = wParam;
lParamTemp = lParam;
uMsgTemp = uMsg;
}
....
UINT ThreadFunc(LPVOID lpParam)
{
while(true)
{
Sleep(1);
g_csExitThread.Lock();
if(true == g_bExitThread)
{
g_csExitThread.Unlock();
break;
}
else
{
g_csExitThread.Unlock();
g_pApp->GotoHole(wParamTemp, lParamTemp);
g_bExitThread = true;
g_pApp->m_nRenderMode = RENDERMODE_SCENE;
g_pApp->StartFlyOver();
g_pApp->m_flyOver.bFirstTime = TRUE;
g_pApp->m_uiLoadingMenu.m_bStart = FALSE;
g_pApp->m_uiLoadingMenu.nTime = 0;
g_pApp->m_uiLoadingMenu.count = 0;
}
}
return 0L;
}
Then, When I run this project, E_OUTOFMEMORY error appear.(D3DXCreateTextureFromFile)
I think it belong about the thread's synchronization.
I have no experience to load resource by use thread.
Please help me.
Did you used D3DCREATE_MULTITHREADED flag when initializing d3d?