Detect Document Reload has occured on server - c#

I have an winform/OCX that consumes a qlikview document. We have gotten a patch from QV so that RefreshDocument works in the OCX as the RefreshDocument does in QV application. But the Application shows a nice enabled button when the document has been reload on the server.
Does anyone know what needs to be done to detect that. Either in C# or in macro code or ManagementAPI ?
This is the ReloadDocument Code.
private void button2_Click(object sender, EventArgs e)
{
var myBloodybookmarkHack = "dynaBookmark" + Guid.NewGuid().ToString().Replace("-","");
axQlikOCX1.ActiveDocument.CreateUserBookmark(myBloodybookmarkHack, true);
//axQlikOCX1.OpenDocument(#"qvp://qvSeverName/path/MyDocument.qvw?bookmark=Server\dynaBookmarkb5aa82ae467540fdb0d18bb499044ed9");
axQlikOCX1.RefreshDocument();
axQlikOCX1.ActiveDocument.RecallUserBookmark(myBloodybookmarkHack);
axQlikOCX1.ActiveDocument.RemoveUserBookmark(myBloodybookmarkHack);
}
By suppressing the paint event I get this to run pretty ok. Next patch will include that it keeps the selections (Will be fixed in 11.2 servicerelease 6).
You need to detect if CreateUserBookmark was successfull or not and not restore the bookmark if the creation failed.
This code works in QV 11.2 serviceRelease 5.

The filesystem reads a new modified time when the qvw file is rewritten after load. Assuming the data portion of this application is not broken out from the QVW file. Likely, you could come very close to accomplishing this by checking for new timestamps. Alternatively, if logging is enabled in the qvw document you could log read the text file* that QlikView generates to accomplish the same thing.
*The text file writes are delayed sometimes so your file might be refreshed a little bit before the log states that it is.

We ended up using the QV Management api to get the last task reload time
Download the Qv management api demo from QV
This code shows you how to get tasks on a document. Through that you get when "last document reload task" was finished.
private DateTime GetLastDocumentRun(string documentName)
{
string QMS = "http://MyQlikviewserver:4799/QMS/Service";
var client = new QMSClient("BasicHttpBinding_IQMS", QMS);
string key = client.GetTimeLimitedServiceKey();
ServiceKeyClientMessageInspector.ServiceKey = key;
var taskStatusFilter = new TaskStatusFilter();
var clientTaskStatuses = client.GetTaskStatuses(taskStatusFilter, TaskStatusScope.All);
foreach (var taskStatus in clientTaskStatuses)
{
Trace.WriteLine(taskStatus.General.TaskName);
if (taskStatus.General.TaskName.ToLower().Contains(documentName.ToLower()))
{
string fin = taskStatus.Extended.FinishedTime + "";
DateTime finishedTime;
if (DateTime.TryParse(fin, out finishedTime))
return finishedTime;
Logger.ErrMessage("QvManagementApi.GetLastDocumentRun",new Exception("Task finished time did not return a valid datetime value:" + fin));
return DateTime.MinValue;
}
}
return DateTime.MinValue;
}
This is slow, so you should run on a different thread.
Also this does not show if the task is successfully reloaded. We haven't fix that yet but on taskStatus.Extended you have the last log, which you can text parse to get if it was successfully reloaded or not.

If I understand correctly you want to know if a document has finished reloading on a QlikView server right?
I've you OCX application has a constant connection, you could evaluate the ReloadTime() function in the document which would tell you when the document was last reloaded. If you listen for the function and issuing a DocumentRefresh while doing this, then you would get a changed timestamp once the newly reloaded document becomes avaible on the server.
The code your posting, does not reload a QlikView document. At least not in QlikView lingo, it just open the documents on the server.
Please elaborate if I misunderstand you.
Regards Torber

Related

UIAutomation throws AccessViolationException on Windows 11

The issue:
We have an application written in C# that uses UIAutomation to get the current text (either selected or the word behind the carret) in other applications (Word, OpenOffice, Notepad, etc.).
All is working great on Windows 10, even up to 21H2, last update check done today.
But we had several clients informing us that the application is closing abruptly on Windows 11.
After some debugging I've seen some System.AccessViolationException thrown when trying to use the TextPatternRange.GetText() method:
System.AccessViolationException: 'Attempted to read or write protected memory. This is often an indication that other memory is corrupt.'
What we've tried so far:
Setting uiaccess=true in manifest and signing the app : as mentionned here https://social.msdn.microsoft.com/Forums/windowsdesktop/en-US/350ceab8-436b-4ef1-8512-3fee4b470c0a/problem-with-manifest-and-uiaccess-set-to-true?forum=windowsgeneraldevelopmentissues => no changes (app is in C:\Program Files\
In addition to the above, I did try to set the level to "requireAdministrator" in the manifest, no changes either
As I've seen that it may come from a bug in Windows 11 (https://forum.emclient.com/t/emclient-9-0-1317-0-up-to-9-0-1361-0-password-correction-crashes-the-app/79904), I tried to install the 22H2 Preview release, still no changes.
Reproductible example
In order to be able to isolate the issue (and check it was not something else in our app that was causing the exception) I quickly made the following test (based on : How to get selected text of currently focused window? validated answer)
private void btnRefresh_Click(object sender, RoutedEventArgs e)
{
var p = Process.GetProcessesByName("notepad").FirstOrDefault();
var root = AutomationElement.FromHandle(p.MainWindowHandle);
var documentControl = new
PropertyCondition(AutomationElement.ControlTypeProperty,
ControlType.Document);
var textPatternAvailable = new PropertyCondition(AutomationElement.IsTextPatternAvailableProperty, true);
var findControl = new AndCondition(documentControl, textPatternAvailable);
var targetDocument = root.FindFirst(TreeScope.Descendants, findControl);
var textPattern = targetDocument.GetCurrentPattern(TextPattern.Pattern) as TextPattern;
string text = "";
foreach (var selection in textPattern.GetSelection())
{
text += selection.GetText(255);
Console.WriteLine($"Selection: \"{selection.GetText(255)}\"");
}
lblFocusedProcess.Content = p.ProcessName;
lblSelectedText.Content = text;
}
When pressing a button, this method is called and the results displayed in labels.
The method uses UIAutomation to get the notepad process and extract the selected text.
This works well in Windows 10 with latest update, crashes immediately on Windows 11 with the AccessViolationException.
On Windows 10 it works even without the uiaccess=true setting in the manifest.
Questions/Next steps
Do anyone know/has a clue about what can cause this?
Is Windows 11 way more regarding towards UIAutomation?
On my side I'll probably open an issue by Microsoft.
And one track we might follow is getting an EV and sign the app itself and the installer as it'll also enhance the installation process, removing the big red warnings. But as this is an app distributed for free we had not done it as it was working without it.
I'll also continue testing with the reproductible code and update this question should anything new appear.
I posted the same question on MSDN forums and got this answer:
https://learn.microsoft.com/en-us/answers/questions/915789/uiautomation-throws-accessviolationexception-on-wi.html
Using IUIautomation instead of System.Windows.Automation works on Windows 11.
So I'm marking this as solved but if anyone has another idea or knows what happens you're welcome to comment!

Is there any documentation for the WebView2 DevToolsProtocolHelper

Has anyone seen any documentation on the WebView2 DevToolsProtocolHelper?
In another question I asked (How do I programmatically add a file to a fileupload control from a windows form to a webpage) it was suggested that I download and use the Microsoft.Web.WebView2.DevToolsProtocolExtensions. At first it seemed like it was going to be very straight forward to use but not so much.
Win forms App using c# and webview2
DevToolsProtocolHelper helper = webView21.CoreWebView2.GetDevToolsProtocolHelper()
Task<DOM.Node> t = helper.DOM.GetDocumentAsync();
Task<int> querySelectorResponse = helper.DOM.QuerySelectorAsync(t.Result.NodeId, "#fileupload");
_ = helper.DOM.SetFileInputFilesAsync(new string[] { filename }, querySelectorResponse.Result);
These 4 lines of code should get the document and search for the node fileupload. I get nothing but errors and I have not seen any real examples or documentation on this.
Any help would be greatly appreciated.
**** UPDATE *****
DevToolsProtocolHelper helper = webView21.CoreWebView2.GetDevToolsProtocolHelper();
DOM dom = helper.DOM;
DOM.Node t = await dom.GetDocumentAsync(-1,true);
int querySelectorResponse = await dom.QuerySelectorAsync(t.NodeId, "#fileupload");
_ = helper.DOM.SetFileInputFilesAsync(new string[] { filename }, t.NodeId);
Here is the latest version of my code and it seems I have made progress. When I used CEFSHARP, the IDs I got back from Document and the #fileUpload were always the same and it worked in uploading the file.
With this code above, I am getting IDs but they are always different and I am not getting the file to upload.
Another update, when I run this code (from a button click on the winform) a second time, I do get the proper ID (504) for the int querySelectorResponse = await dom.QuerySelectorAsync(t.NodeId, "#fileupload") line of code. Again, still not getting the file to upload to the page.
Again, any help would be greatly appreciated
The GetDevToolsProtocolHelper documentation is the 'How to' article on Using Chromium DevTools Protocol in WebView2.
Separately, you cannot use Task.Result with WebView2 tasks which I see you doing in the above code. WebView2 can only be used from the UI thread its created on and requires that UI thread to communicate task completions. You should be able to use await instead.

how to get real time log via perforce api similar to p4v log

I am facing issue with perforce api (.net), as i am unable to pull sync logs in real time.
- What am I trying to do
I am trying to pull real time logs as Sync is triggered using the
Perforce.P4.Client.SyncFiles() command. Similar to the P4V GUI Logs, which update when we try to sync any files.
- What is happening now
As the output is generated only after the command is done execution its not something intended for.
Also tried looking into Perforce.P4.P4Server.RunCommand() which does provide detailed report but only after the execution of the command.
Looked into this
Reason is -
I am trying to add a status update to the Tool i am working on which shows which Perforce file is currently being sync'd.
Please advise. Thanks in Advance.
-Bharath
In the C++ client API (which is what P4V is built on), the client receives an OutputInfo callback (or OutputStat in tagged mode) for each file as it begins syncing.
Looking over the .NET documentation I think the equivalents are the P4CallBacks.InfoResultsDelegate and P4CallBacks.TaggedOutputDelegate which handle events like P4Server.InfoResultsReceived etc.
I ended up with the same issue, and I struggled quite a bit to get it to work, so I will share the solution I found:
First, you should use the P4Server class instead of the Perforce.P4.Connection. They are two classes doing more or less the same thing, but when I tried using the P4.Connection.TaggedOutputReceived events, I simply got nothing back. So instead I tried with the P4Server.TaggedOutputReceived, and there, finally, I got the TaggedOutput just like I wanted.
So, here is a small example:
P4Server p4Server = new P4Server(cwdPath); //In my case I use P4Config, so no need to set user or to login, but you can do all that with the p4Server here.
p4Server.TaggedOutputReceived += P4ServerTaggedOutputEvent;
p4Server.ErrorReceived += P4ServerErrorReceived;
bool syncSuccess=false;
try
{
P4Command syncCommand = new P4Command(p4Server, "sync", true, syncPath + "\\...");
P4CommandResult rslt = syncCommand.Run();
syncSuccess=true;
//Here you can read the content of the P4CommandResult
//But it will only be accessible when the command is finished.
}
catch (P4Exception ex) //Will be caught only when the command has failed
{
Console.WriteLine("P4Command failed: " + ex.Message);
}
And the method to handle the error messages or the taggedOutput:
private void P4ServerErrorReceived(uint cmdId, int severity, int errorNumber, string data)
{
Console.WriteLine("P4ServerErrorReceived:" + data);
}
private void P4ServerTaggedOutputEvent(uint cmdId, int ObjId, TaggedObject Obj)
{
Console.WriteLine("P4ServerTaggedOutputEvent:" + Obj["clientFile"]); //Write the synced file name.
//Note that I used this only for a 'Sync' command, for other commands, I guess there might not be any Obj["clientFile"], so you should check for that.
}

Error while executing script for a TableObject located at the PageFooter section

We have a report that displays at the PageFooter which payment way the customer used to pay an order, in that area we have three other TableObjects that are working correctly, but there's one that executes a script to build manually the TableObject, the problem we located is when it executes that script it fails showing the message StackOverflowException in System.Drawing.dll
The message on top means the report generation is executing.
The script that I located it fails is this one, if this script is not executing the report displays correctly but without the information we want to display in that TableObject
private void TableModalidadPago_ManualBuild(object sender, EventArgs e)
{
// get the data source by its name
DataSourceBase rowData = Report.GetDataSource("DOCUMENTO_MODALIDAD_PAGO");
// init the data source
rowData.Init();
if (rowData.RowCount == 0)
{
TableModalidadPago.Visible = false;
return;
}
// print the first table row - it is a header
TableModalidadPago.PrintRow(0);
TableModalidadPago.PrintColumns();
TableModalidadPago.PrintRow(1);
TableModalidadPago.PrintColumns();
// now enumerate the data source and print the table body
while (rowData.HasMoreRows)
{
// print the table body
TableModalidadPago.PrintRow(2);
TableModalidadPago.PrintColumns();
// go next data source row
rowData.Next();
}
TableModalidadPago.CanBreak = false;
TableModalidadPago.CanGrow = true;
}
It fails at line
TableModalidadPago.PrintRow(0);
And if I put the TableObject in other section that is not the PageFooter it works perfectly.
Anyone knows if there's any restriction to execute code at PageFooter or if there's any error at the provided script?
I already posted this information in FastReports forum but still no answer(Link)
Edit: I also created a ticket in FastReports Support centre and still no answer...
Edit2: 24/06/2016 today I saw they published a new version of the FastReports.Net (2016.3 previous was 2016.2) and I downloaded and install it, after cleaning up my project and tried again, the error still ocurring, with this new version the program just unexplectly closes and doesn't display any error message, I updated my ticket with support center
Thanks.
The stack overflow error suggests that the while loop may be infinite. Could it actually be failing at the line
TableModalidadPago.PrintRow(2);
Perhaps you need to remove rows from rowData object once you've printed them?

Download file to client PC and post back to page

I have a web page which returns a set of results which you can then ask for in a .csv format.
As the creation of the file is quite lengthy (at times up to 30 minutes), I have added some JavaScript that adds a class to a div so that it covers the screen, to tell users that the report is being created and to be patient.
After the file has been created and downloaded I would like the div to then return to its original state of not being there (so to speak).
Here is what I currently have.
JavaScript
function skm_LockScreen() {
var lock = document.getElementById('ctl00_ContentPlaceHolder1_skm_LockPane');
var lock2 = document.getElementById('ctl00_ContentPlaceHolder1_pleaseWait');
if (lock)
lock.className = 'LockOn';
if (lock2)
lock2.className = 'WaitingOn';
}
function skm_UnLockScreen() {
var lock = document.getElementById('ctl00_ContentPlaceHolder1_skm_LockPane');
var lock2 = document.getElementById('ctl00_ContentPlaceHolder1_pleaseWait');
if (lock)
lock.className = 'LockOff';
if (lock2)
lock2.className = 'WaitingOff';
}
Button
<asp:Button ID="LatestReportButton" runat="server" CssClass="standardButton" Text="Latest Quote Report" Width="140px"
OnClick="ReportButton_Click" CommandArgument="2" OnClientClick="skm_LockScreen()" />
Code behind
protected void ReportButton_Click(object sender, EventArgs e)
{
Page.ClientScript.RegisterStartupScript(base.GetType(), "unlock", "<script type=\"text/javascript\">skm_UnLockScreen();</script>");
try
{
//Start creating the file
using (StreamWriter sw = new StreamWriter(tempDest + "\\" + csvGuid + ".csv", true))
{
//Code to create the file goes
}
}
catch
{
}
Response.AddHeader("Content-disposition", "attachment; filename=report.csv");
Response.ContentType = "application/octet-stream";
Response.WriteFile("CreatedReport.csv");
Response.End();
}
The issue I'm having is that the JavaScript is never written back to the page because of the Response.End();
I've already done it as two buttons, one to create the report the other to download it, but my company would prefer it to be all in one.
Any suggestions?
Given the length of time needed to generate the report, the method you're proposing contains a number of inherent risks, each of which will cause the report creation to fail:
the user may accidentally close the browser / tab;
the browser / tab might crash;
timeouts may occur on the web server.
I would tackle this problem in a different way. In the first instance, I would look to see if the report generation can be optimized - "30 minutes" rings alarm bells immediately. Assuming database(s) are involved at some point, I would investigate the following as a minimum:
Are database indexes being used, or used correctly?
Do the report generation queries contain inefficient operations (CURSORs, for example)?
Do the execution plans reveal any other flaws in the report generation process?
If this isn't a option (let's assume you can't modify the DBs for whatever reason), I would still consider a totally different approach to generating the report, whereby the report creation logic is moved outside of the web application into, say, a console app.
For this, you would need to define:
a way to pass the report's parameters to the report generation app;
a way to identify the user that requested the report (ideally login credentials, or Windows identity);
a way to notify the user when the report is ready (email, on-screen message);
a directory on the server where the reports will be saved and downloaded from;
a separate page from which the user can download the report.
A couple of database tables should be sufficient to log this information.

Categories