I need to read a text value from other window and query that value to another application (my question will be around the 1st task)…so,
I’m “spying” other window (some 3rd party application we use in connection with our product) and waiting for “accept” button to be clicked to read a value from a text box. This other application, the dialog box, has multiple text boxes and command buttons.
I made a mouse hook and I’m activating it upon this application appearance. I‘m reading all mouse moves inside this window rectangle; texts, captions, child windows IDs, rectangles, grab left/right/middle/wheel clicks. I can grab the “accept” button click; I CAN SEE the button caption and I can read that window, get the text and determine what button is clicked, etc. Now…
I can read ALL EDIT class values, get their window handles, rectangles, etc., BUT I CANNOT IDENTIFY THEM AS UNIQUE items within the class collection: I need specifically read my desired text box value. Fortunately the text box I’m interested in is ALWAYS COMES FIRST IN MY LOOP when I’m reading texts from EDIT class loop. However I would like to be more specific; making sure that I’m reading the text box with the NAME. I know. During the development I could read that NAME and hard code it in the program. My a suspicion is that control name is not saved in the binary code. My understanding is that control ID, windows handle are created upon windows creation and have absolutely no reference to control name (say: txtOrderNumber). If for buttons I can be specific because of button captions (so, I can determine what button is clicked) I’m locked with EDIT class items and thrown to lucky 1st guess when reading the value.
My question is:
How I can get a control name from another window, for this task I’m interested to know about EDIT class instance names.
Here are some codes (shortened) from the project:
Dim hWnd As IntPtr = FindWindow(Nothing, _windowText)
'API: FindWindowEx
'API: SendMessage
'API: GetClassName
'API: GetWindowTextLength
'API: GetWindowText
'API: WM_GETTEXT
Public Shared Function GetClassValues(_controlClass As String, _hWindow As IntPtr) As List(Of String)
Dim cl As New List(Of String)
'First control handle in that class
Dim hc As IntPtr = FindWindowEx(_hWindow, IntPtr.Zero, _controlClass, vbNullString)
Do
Dim sv As String = GetWindowValue(hc)
cl.Add(sv)
'Next control (after hc) handle
hc = FindWindowEx(_hWindow, hc, _controlClass, vbNullString)
Loop Until hc = 0
Return cl
End Function
Public Shared Function GetWindowValue(_hWindow As IntPtr) As String
If _hWindow = IntPtr.Zero Then Return String.Empty
Dim sz As Integer = 256
Dim bf As IntPtr = Marshal.AllocHGlobal(sz)
Dim pt As IntPtr = SendMessage(_hWindow, WM_GETTEXT, sz, bf)
Dim rs As String = Marshal.PtrToStringUni(bf)
Marshal.Release(bf)
Return rs.Trim
End Function
Public Shared Function GetWindowClassName(_hWindow As IntPtr) As String
Dim ln As Integer = 256
Dim sb As New System.Text.StringBuilder("", ln)
GetClassName(_hWindow, sb, ln)
Return sb.ToString()
End Function
Public Shared Function GetWindowText(_hWindow As IntPtr) As String
Dim ln As Integer
If _hWindow.ToInt32 <= 0 Then Return String.Empty
ln = GetWindowTextLength(_hWindow)
If ln = 0 Then Return String.Empty
Dim sb As New System.Text.StringBuilder("", ln + 1)
GetWindowText(_hWindow, sb, sb.Capacity)
Return sb.ToString()
End Function
I've looked at GetWindowLong and GetDlgCtrlID API and have tried most of the flags with no success so far...
Any tip, clue, direction is appreciated.
Thank you
I made a global mouse hook, this is not a problem and, GetWindowText and WM_GETTEXT works fine. As a matter of fact the program works fine and functional at this point.
Upon detecting a target window I save child window handles in a list collection using EnumChildWindows API and filtering EDIT class windows only (used in connection with modified version of GetClassValues function posted above. The argument for this function is the first EDIT class window handle). Anyway, the way how I arbitrary access my desired text box is to use the saved list for this class windows and access by list index. As I mentioned earlier, fortunately, windows CREATES THIS CHILD windows in consistent order. So, in my case this EDIT class window, the text box “object”, is always the 1st in the list though there are many in the main window.
I would like to get that the text box “object” name, say “txtAccountNumber” as I mentioned earlier…
Related
good afternoon,
I have an access with a subform (sub_frm_robo2) that has a specific column (CD_SENHA).
In the Form Load event I put the code: (Me.sub_frm_robo2.Form! SENHA.InputMask = "Password")
and I am trying to create a condition that at the moment this Column
(CD_SENHA) receives focus (Me.sub_frm_robo2.Form!SENHA.SetFocus),
the data mask be removed (Me.sub_frm_robo2.Form!SENHA.InputMask = "")
and when the focus changes to the next column return the data mask to the initial format (Me.sub_frm_robo2.Form! PASSWORD = "Password")
Below some images to better exemplify
Before Focus
With Focus
After Focus
I think the code would look something like this
Do While Me.sub_frm_robo2.SetFocus = True
If Me.sub_frm_robo2.Form!SENHA.SetFocus Then
Me.sub_frm_robo2.Form!SENHA.InputMask = ""
End If
Next
Can you help me?
Well, I did not have any help here but I managed to resolve after a few attempts and errors, just to code a code in the event of each column of the subformaluario to make it work. Good luck to everyone
Private Sub CNPJ_AF_GotFocus()
Me.Form!SENHA.InputMask = "Password"
End Sub
Private Sub SENHA_GotFocus()
Me.Form!SENHA.InputMask = ""
End Sub
I'm Having a problem regarding to the autocomplete textbox. First I already made the autocomplete textbox work with mysql database as custom source but the default textfilter of autocomplete is "start with" not "contains". I want to change the textfilter to "contains", so that when I search any part of the string, the whole name which contains the searched word will appear in the autocomplete suggestions.
Can anyone help me fix my code?
This is the code i've done so far:
txtSearch.AutoCompleteMode = AutoCompleteMode.SuggestAppend
txtSearch.AutoCompleteSource = AutoCompleteSource.CustomSource
Dim DataCollection As New AutoCompleteStringCollection()
Dim query As String
sqlcon = New MySqlConnection
sqlcon.ConnectionString =
"server=localhost;userid=root;password=root;database=svfmemberlistdb"
Try
sqlcon.Open()
query = " SELECT Name FROM svfmemberlistdb.svfmemberlist "
sqlcmd = New MySqlCommand(query, sqlcon)
sqladr.SelectCommand = sqlcmd
sqladr.Fill(ds)
sqladr.Dispose()
sqlcon.Close()
For Each row As DataRow In ds.Tables(0).Rows
If row.ToString.Contains(txtSearch.Text) Then
DataCollection.Add(row(0).ToString())
End If
Next
Catch ex As Exception
End Try
txtSearch.AutoCompleteCustomSource = DataCollection
I quote here Mitja Bonca's answer on MSDN.
In this case, autocompletemode will just not do. Its code is not meant
for something like it.
You will have to do your own code, to do the filtering on each letter
press.
So I would suggest not to use autocompletemode, and get all the data
(names) into dataTable. When user presses some button ("1" for
example), you start with your filtering, by creating new Datatable
(leave the main one untached - so you can return back to all data when
clearing comboBox by backspace), with Copy() method - to create a full
copy of original one, and use Select method to do the filteing.
This should look something like by using % simbol on both sides of a
string - to filter inbetween - this is what you want!
DataTable AllNames = new DataTable();
//fill it up and leave it untouched!
//to filter comboBox with names that contains pressed characters do in
private void comboBox1_KeyPress(object sender, KeyPressEventArgs e)
{
string name = string.Format("{0}{1}", comboBox1.Text, e.KeyChar.ToString()); //join previous text and new pressed char
DataRow[] rows = table.Select(string.Format("FieldName LIKE '%{0}%'", name));
DataTable filteredTable = AllNames.Clone();
foreach(DataRow r in rows)
filteredTable.ImportRow(r);
comboBox1.DataSource = null;
comboBox1.DataSource = filteredTable.DefaultView;
comboBox1.DisplayMember = "FieldName";
}
Reference
EDIT: This is of course a c# answer not VB.NET but it might be helpful to get the concept.
I created a custom color palette for my charts using a technique described on TechNet.
I also have a series of drill-through column charts, where you click on one column and it passes a parameter through to the next chart and so on, giving the appearance of drill-down.
My graphs consist of 3 types of labor, and have three colors on the main chart. When I drill down to the next chart, some of the categories do not have all three types of labor that the main one has. So the first color in the palette is assigned to the series, even though it was the second color on the previous chart. I'd like to avoid this, if possible.
So a data value is green on the first chart (2nd in the color order) and yellow on the next chart (1st in the color order). How do I make the graphs "remember" the total number of series groups that were in the first chart?
This is Reporting Services 2005.
You cannot fix this using custom colour palettes.
What you can do is assign the labour type a colour in the database (using HEX is easiest). Then pass that in in your data set. Then set the color property to you hex value.
Unfortunately this is not possible. I've been looking for this for quite some time...
I was able to solve this because I was using a custom color palette, implemented as a hash table. I basically serialized this information and passed it to a hidden parameter on the subreport and then reinflated the data structure.
It's not perfect, but it works for now.
' Define some globals, including the color palette '
Private colorPalette As String() = _
{"#FFF8A3", "#A9CC8F", "#B2C8D9", "#BEA37A", "#F3AA79", "#B5B5A9", "#E6A5A4", _
"#F8D753", "#5C9746", "#3E75A7", "#7A653E", "#E1662A", "#74796F", "#C4384F", _
"#F0B400", "#1E6C0B", "#00488C", "#332600", "#D84000", "#434C43", "#B30023"}
' color palette pulled from SAP guidelines '
' http://www.sapdesignguild.org/resources/diagram_guidelines/color_palettes.html '
Private count As Integer = 0
Private colorMapping As New System.Collections.Hashtable()
' Create a custom color palette '
Public Function GetColor(ByVal groupingValue As String) As String
If colorMapping.ContainsKey(groupingValue) Then
Return colorMapping(groupingValue)
End If
Dim c As String = colorPalette(count Mod colorPalette.Length)
count = count + 1
colorMapping.Add(groupingValue, c)
Return c
End Function
' In custom actions of the data value, set the results of this '
' function to the mapping parameter in the next report '
Public Function PassColorMapping() As String
If colorMapping.Count = 0 Then
Return Nothing
End If
Try
' convert the hashtable to an array so it can be serialized '
Dim objHash As Object()() = ToJaggedArray(colorMapping)
' serialize the colorMapping variable '
Dim outStream As New System.IO.StringWriter()
Dim s As New System.Xml.Serialization.XmlSerializer(GetType(Object()()))
s.Serialize(outStream, objHash)
' move on to the next report '
Return outStream.ToString()
Catch ex As Exception
MsgBox(ex.Message)
End Try
End Function
I ran into an issue where I couldn't find the equivalent of the onLoad event for the report. Since I wasn't sure where to put this inflate code, I stuck it in the background color of the plot area. Hence I always return "WhiteSmoke". I'll change this if I can find the right place to put it.
' Call this function when the report loads to get the series groups '
' that have already been loaded into the custom color palette '
' Pass in the parameter used to store the color mapping '
Public Function InflateParamMapping(ByVal paramMapping As Parameter) As String
Try
If paramMapping.Value Is Nothing Then
Return "WhiteSmoke"
ElseIf colorMapping.Count = 0 Then
Dim pXmlized As String = paramMapping.Value
' deserialize the mapping parameter '
Dim s As New System.Xml.Serialization.XmlSerializer(GetType(Object()()))
' get the jagged array and convert to hashtable '
Dim objHash As Object()() = DirectCast(s.Deserialize(New System.IO.StringReader(pXmlized)), Object()())
' stick the result in the global colorMapping hashtable '
colorMapping = ToHashTable(objHash)
count = colorMapping.Count
End If
Catch ex As Exception
' MsgBox(ex.Message) '
End Try
Return "WhiteSmoke"
End Function
ToJaggedArray() and ToHashTable() are helper functions because a HashTable is not serializable since they implement an IDictionary. I was in a hurry so I just converted them to an array right quick. Code comes from the Collection Serialization in ASP.NET Web
Services article written by Mark Richman. I converted the code from C# to VB.NET to use in the report.
Public Function ToJaggedArray(ByVal ht As System.Collections.HashTable) As Object()()
Dim oo As Object()() = New Object(ht.Count - 1)() {}
Dim i As Integer = 0
For EAch key As Object in ht.Keys
oo(i) = New Object() {key, ht(key)}
i += 1
Next
Return oo
End Function
Public Function ToHashTable(ByVal oo As Object()()) As System.Collections.HashTable
Dim ht As New System.Collections.HashTable(oo.Length)
For Each pair As Object() In oo
Dim key As Object = pair(0)
Dim value As Object = pair(1)
ht(key) = value
Next
Return ht
End Function
Now in the report itself you need to do a couple things.
Add a reference to System.Xml in Report Properties in both reports.
In the Actions of your parent report, set the Parameter containing your data structure to =Code.PassColorMapping()
In the Plot Area section of your report, put this expression for the background: =Code.InflateParamMapping(Parameters!colorMapping)
And of course, in the Fill for your data Series Style on both charts put this expression: =Code.GetColor(Fields!Type.Value)
You can continue doing this for as many subreports as you want - I currently have 3 levels of drill-through and it works fine.
I solved that extremely easy.
In my parent report I have lets say 12 series fields, each one getting their own color in a chart, on my child report I just keep all series on the chart, for instance going from a column chart to a line chart using drill down, but I control the visibility of them...
So in the child report in Series Properties -> Visibility I just add an expression:
=(Fields!ContentType.Value <> Parameters!ContentType.Value)
This way the report only keeps the visibility of the clicked value and hides all the others and the colors remains the same :)
Is there a way in arcobjects to get a unique id for a layer? If you do a search by layer name there could be possible duplicates.
If there isn't a property is there a way to generate an id?
I tried using the GetHash() but that didn't stay consistent.
There is an ArcObjects Interface present for setting or getting an Id for a layer.
You should look at ILayerDescriptor:ID,
http://resources.esri.com/help/9.3/ArcGISDesktop/ArcObjects/esriCarto/ILayerDescriptor_ID.htm
Here is a VBA Snippet which shows how it can be used:
Public Sub layerInfo()
Dim app As IApplication '
Set app = Application
Dim mxDoc As IMxDocument
Set mxDoc = app.Document
Dim myMap As IMap
Set myMap = mxDoc.ActiveView
Dim mapServer As IMxdServer
Set mapServer = New MxdServer
'''Point to your .mxd...
mapServer.Start ("D:\Test.mxd")
Dim myArray As IArray
Set myArray = mapServer.LayerDescriptors(myMap.Name)
MsgBox myArray.Count
Dim x As ILayerDescriptor
Dim intX As Integer
intX = 0
For intX = 0 To myArray.Count - 1
Set x = myArray.Element(intX)
MsgBox x.ID
MsgBox x.Name
Next
End Sub
It isn't pretty, but in the past I've appended a guid in the layer description. Something like this:
<LAYER guid='a9843c88-3caa-4953-ad96-ca9990b410e9' revision='1' />
I've got a DLL floating around that would slam these xml frags into each layer of an MXD (with enough cr/lf in front to scroll the xml fragment out of the layer description in ArcMap Layer Prop dialog) .
There's a help file in the 7z file (documentation is sparse because I'm doing other things):
http://code.google.com/p/umbriel/downloads/list
I like the idea of using a GUID. This can then be stored in the ModelName property which is a tool for developers of custom objects to use to guarantee the names of objects independent of the true name or alias name.
There are more details and sample code at http://geographika.co.uk/?p=58
Easy. A side effect of using COM and because how the vtables are laid out, is that you can use the memory address of the layer itself as your unique identifier. Inside the implementation of many ESRI GeoDatabase and Carto code itself, this trick is being used all over the place.
Here's my problem. I am passing in a parameter let say it's called ShapesSelected.
ShapeSelected = ",Square, Triangle, Circle,".
The problem is ShapeSelected could be any of the the shapes so it is never static.
Base on this parameter I want to add 3 column to the right of a table in the report. Is this possible? I've starting coding it in Custom Code in Report Properties but I am stuck as in how to add the column.
Public Function GetReportShapes( ByVal ShapesSelected As String )
Dim Shapes() As String
Dim result As String
Dim i As Integer
Entities = Split(ShapesSelected ,", ")
For i = 0 To UBound ( Shapes)
Select case Shapes(i)
case "Square": 'add Square Column here
case "Rectangle": add Rectange Column here
case "Triangle": add Triangle Column here
End Select
Next i
End Function
Thus rendering the columns like this:
Square Triangle Circle
Add all the columns you need and use the hidden or visible property (I forget which) with vb expressions to turn them on and off.