I assume this topic is about using your control with ActiveX controls via and OLE scripted interface? I just posted a previous message on this topic. Clarification would be great!
Printable View
My first message was held for moderation as a new member but don't see it here.
Krool,
I have used your OCX with VB6 on XP, Win7 and Win10 with .exe based forms. I'm unable to get it to work with ActiveX forms (.dll) I'm scripting via Script BASIC. Does your OCX work in this environment?
Thanks for the reply!
Would you happen to know who that user was? It's critiacl I get AxtiveX forms themed and using current common controls.
Krool,
Is source available for your enhanced common controls OCX project? The Script BASIC project would like to join in and expand on your work.
Here is a VB6 / COM ext. project for Script BASIC one of our developers contributed.
VB6 IDE/Debugger for embedded Script BASIC engine
John
Thanks Krool!
I have sent Thierry76 a PM letting him know what I'm up to.
Is source available for your enhanced common controls OCX project?
Resolving the issue of using your OCX replacement is going to be difficult if not impossible otherwise.
The reason I asked was this forum policy.
COM and ActiveX Policy Regarding Attachments
Great work,
Only problem is the casual crashes on the IDE, (because of the hooks overuse i assume)
and the annoying windows crashing message when user closes the form, (when compiled).
which makes it rather impossible to relay on commercial use, but for private use its rather good.
By the way, if you're using VB6 on a 64bit system, be advised that WoW64 will make it difficult for you to place the .tlb file on C:\Windows\System and reference it to your project from there.
so just reference it to current file location (may it be even your desktop) regardless where it is, it will work just as good, even if not placed in C:\Windows\System.
Hey Krool, again, fantastic work, very impressive. A comment. For me, when using this, I'd never consider using the OCX version. The most compelling reason (for me) to use your work would be to create EXE's that had no dependencies (other than the core dependencies built into all later versions of Windows). What's cool about that is that it obviates any need to even think about the SxS stuff. I've long dreamed of a way to have my OCX dependencies wrapped into the EXE upon compiling and have them treated as overlays (similar to a class for form). And your work comes dangerously close to doing precisely that.
I guess, for me, if I'm going to use the OCX, I'll just stick with dependencies to all the other OCX files that your code does away with.
A question: I taken a bit of a look at your work, and again, it's truly cool. But I haven't studied it in detail. Is it possible to, say, peel off one control and use just it? (Say pulling out the CTL/CTX as well as its BAS module?) I didn't really figure out if it was that well compartmentalized or not.
You take care,
Elroy
:eek:Quote:
Originally Posted by Krool
I'm curious how others are tweaking your control for their needs?
Krool,
Could this be the reason your OCX enhancements aren't taking effect?
Code:Private Declare Function ShowWindow Lib "user32" (ByVal hwnd As Long, ByVal nCmdShow As Long) As Long
'this will show a non-modal form and return a reference to its
'form object which is a COM object that can be manipulated from the script
Public Function LaunchUI() As Long
Set f = New Form1
ShowWindow f.hwnd, 1 'this gets around can not display non modal form from dll thing..
LaunchUI = ObjPtr(f)
End Function
Damn. Ask about source or ActiveX DLL forms and you would think I just farted in the room. :rolleyes:
Hope this thread gets rolling again!
Your first question I don't really understand - because on page 1, post #1 of this thread
there's all the Sources for the (admittedly non-ocx)-version...
That Krool prefers to do community-development on only the "Exe-Version" of his
sources is understandable.
He considers that the "leading source" - and derives/updates the OCX-version
(from time to time) from these newest sources.
Having both projects in the wild would be confusing and messsing up communication...
And that your second question is not answered, is because it's becoming a bit OffTopic IMO.
Your line:
ShowWindow f.hwnd, 1 'this gets around can not display non modal form from dll thing..
can very well cause misbehaviour with the COM-based OCX-Control-siting mechanism,
when you avoid the intrinsic Form.Show method of the vbRuntime.
If I understand you correctly, you are searching for a nice COM-Dll-encapsulation of a
broad set of Controls - if possible containing also a small (also COM-Dll-based) Form-Engine,
which is able to show all kind of TopLevel-Forms (no matter if modal or non-modal).
Well - such a thing exists in vbRichClient5 (other than VB6's intrinsic Form-Engine, fully Unicode-capable).
Here's a small example for how you would use it with VBScript (if that's any help) -
and perhaps we should continue the discussion in the SubForum 'VBScript' or 'Other Basic-Dialects'
when you have further questions...
This part is only a preamble for VBScripts on 64Bit Win-Installations, to restart themselves
in the 32-Bit ScriptingHost-Process (first snippet of e.g. a "TestRC5Binding.vbs" - file)
Now the Form-Engine and Widgets-Code, making use of VBScripts Event-Binding redirection-mechanismCode:With CreateObject("WScript.Shell") 'this block auto-reshells a script to the 32Bit-WSH-version on Win64 (if needed)
WS32on64 = .ExpandEnvironmentStrings("%SYSTEMROOT%\SysWOW64\wscript.exe")
If StrComp(WScript.FullName, WS32on64, vbTextCompare) then 'So, when the Paths' differ, we...
If CreateObject("Scripting.FileSystemObject").FileExists(WS32on64) Then '...check if the target is there at all...
.Run """" & WS32on64 & """ """ & WScript.ScriptFullName & """", 1, False '...and re-launch the script to it!
WScript.Quit
End If
End If
End With
(second part of "TestRC5Binding.vbs"):
So - in case your Scripting-Language supports COM in quite a similar way as VBScript, youCode:'*** Cairo-Widgets-GUI per vbScript... Author: Olaf Schmidt (July 2013) ***
Set New_c = CreateObject("vbRichClient5.cConstructor") 'Main-RC5-Constructor
Set Cairo = New_c.Cairo 'ensure the global Cairo-Namespace-Entrypoint
Set Form = Cairo.WidgetForms.Create(2, "MouseWheel to change Zoom", , 640, 480)
WScript.ConnectObject Form, "Form_" '<-EventSink-Prefix and -Binding
Form.Show
Cairo.WidgetForms.EnterMessageLoop 'here we enter the message-pump
Sub Form_Load()
Form.Widgets.Add(CreateObject("vbWidgets.cwButton"),"btnHello").Caption = "Hello World"
Form.Widgets.Add New cwMyWidget, "MyWidget1", 10, 10, 111, 88
Form.Widgets.Add New cwMyWidget, "MyWidget2", 99, 77, 111, 88
End Sub
Sub Form_Resize()
x = (Form.ScaleWidth / Form.WidgetRoot.Zoom - 99) / 2
y = (Form.ScaleHeight / Form.WidgetRoot.Zoom - 33) / 2
Form.Widgets("btnHello").Widget.Move x, y, 99, 33
End Sub
Sub Form_MouseWheel(MouseKeys, Rotation, Xpos, Ypos)
Zoom = Form.WidgetRoot.Zoom + 0.1 * Sgn(Rotation)
If Zoom < 0.5 Then Zoom = 0.5 Else If Zoom > 2 Then Zoom = 2
Form.WidgetRoot.Zoom = Zoom
Form_Resize
Form.WidgetRoot.Refresh
End Sub
Sub Form_BubblingEvent(Sender, EventName, P1, P2, P3, P4, P5, P6, P7)
If Sender.Widget.Key = "btnHello" And EventName = "Click" Then MsgBox "Hello World!"
If TypeName(Sender) = "cwMyWidget" Then
Select Case EventName
Case "W_Paint": Sender.Paint P1, P4, P5 're-route to the Class
Case "W_MouseEnter", "W_MouseLeave": Sender.Widget.Refresh
End Select
End If
End Sub
Class cwMyWidget 'a small minimum-encapsulation for a cairo-Widget-Class
Private W 'our class-internal Cairo.WidgetBase
'below are the two Properties, any cwClass needs to implement
Property Get Widget(): Set Widget = W: End Property
Property Get Widgets(): Set Widgets = W.Widgets: End Property
Private Sub Class_Initialize()
Set W = Cairo.WidgetBase 'instantiate the internal W-WidgetBase
W.BackColor = vbYellow: W.ForeColor = vbRed: W.Alpha = 0.6
W.FontName = "Arial": W.FontSize = 12
W.Moveable = True
End Sub
Sub Paint(ByVal CC, ByVal dx, ByVal dy)
CC.RoundedRect 0, 0, dx, dy, 7, True
CC.SetSourceColor (IIf(W.MouseOver, W.HoverColor, W.BackColor)), W.Alpha
CC.Fill True '<- don't close the path yet
CC.SetSourceColor IIf(W.Focused, W.FocusColor, W.BorderColor), W.Alpha
CC.Stroke
'draw some centered Text, using the current W.Font...Props and W.ForeColor
W.SelectFontSettingsInto(CC)
S = "Hello World" & vbCrLf & "Cur.-Zoom: " & FormatPercent(W.Zoom)
CC.DrawText 0, 0, dx, dy, CStr(S), False, 2, 4, True
End Sub
End Class
Function IIf(Cond, ResultIfTrue, ResultIfFalse) 'add missing IIf to VBScript
If Cond Then IIf = ResultIfTrue Else IIf = ResultIfFalse
End Function
can write full-blown Win-Applications with it - also note, that this approach contains a fully working
Control/Widget-Engine - so you could define your own Controls entirely in the Scripting-Language,
as shown with the small Class cwMyWidget above.
As said - better to continue in a new thread in case you see value in trying a few things with that approach
(which IMO is a better suited companion for Scripting - since as a Framework it contains "everything" -
not just Controls).
Olaf
*** moved ***
Duplicate post ???
Would appreciate, when a moderator could move the last postings (from #496 onward) into a
new thread in e.g.: http://www.vbforums.com/forumdisplay.php?16-Other-BASIC
... to continue the Discussion about "COM-Bindings to ScriptBasic" there...
Olaf
a little bit a problem on the DateTimePicker control, when CustomFormat = "dd/MM/yyyy hh:mm:ss" the time cannot be edited on the control.
also on the Microsoft version you can edit each part of the date/time and move with the right/left key to the next part.
Krool,
Please excuse my ignorance as I just became aware of your library. I'm sensing the OCX version is not offered with source but there is another fork that does include source? Please clear this up for me to stop the confusion.Quote:
For commercial use I would rely on the OCX version, as it is IDE safe.
Why is this so confusing. Do only special members get to view source? Is your OCX a wrapper for the obvious that I seemed to have missed?Quote:
Originally Posted by Elroy
At the bottom of the first post there is a download link for the source code.
Thank You !!!Quote:
At the bottom of the first post there is a download link for the source code.
Sorry Krool for causing a stir about nothing. The thread and the project evolution took me a while to comprehend.
Actually I cannot replicate your problem. However, I fixed another issue with the CustomFormat property. In fact that the CustomFormat property takes now only visible effect when the Format property is set to 'Custom'.
Can you describe your problem in more detail? (e.g. with a demo project or so)
@Krool: I'm hoisting your UnsignedAdd implementation right away -- it's a one liner *and* it's faster than anything I've seen/produced :-))
The thing is we recently switched to set link=/largeaddressaware before compiling our apps and under stress my pointer arithmetic failed spectacularly with "overflow" errors near 2GB boundary.
Tell me you just used UnsignedAdd in you code out of habit and largeaddressaware flag was not something you were actively aware of? I can't think of any other case UnsignedAdd is needed for pointer arithmetic.
cheers,
</wqw>
As some senior programmers mentioned in other thread (http://www.vbforums.com/showthread.p...=1#post4782515),Owner-drawn textbox has some issues on Kazakh keyboard. In Kazakh IME and type "asdf 890" in a TextBox, textbox show "фыва ???" instead of right "фыва үұқ". I think you have way to solve it.
I don't have this problem. Do you have any code in the LostFocus event? Maybe something like this, or similar?
This will cause the time to be erased. Please check.Code:DTPicker1.Value = Int(DTPicker1.Value)
I also get only "фыва ???". Also in the RichTextBox control. Don't know how to fix this. You can help?
Quote:
As some senior programmers mentioned in other thread (http://www.vbforums.com/showthread.p...5),Owner-drawn textbox has some issues on Kazakh keyboard. In Kazakh IME and type "asdf 890" in a TextBox, textbox show "фыва ???" instead of right "фыва үұқ". I think you have way to solve it.
Talent @tannerhelland has worked out solution in his PhotoDemon project. Please contact him on https://github.com/tannerhelland/PhotoDemonQuote:
I also get only "фыва ???". Also in the RichTextBox control. Don't know how to fix this. You can help?
He's a member on the forum:
http://www.vbforums.com/member.php?205967-Tanner_H
Hi Krool. I'll do my best to explain the "фыва ???" problem, and two possible solutions for it. (I'm not sure I understand all the details of why the problem occurs, but maybe someone smarter than me can correct any mistakes.)
Key events don't arrive directly at a control. They are first translated by the application's central message pump, using a series of functions: TranslateAccelerator, then TranslateMessage, and finally DispatchMessage. Multiple functions are necessary because the message loop needs to check for accelerator key combinations. If it finds one, it will send a WM_COMMAND or WM_SYSCOMMAND message to the parent window (instead of a WM_CHAR to the child window), so the parent can raise a menu or perform some other hotkey action.
In VB, this is a problem for a Unicode window created by CreateWindowExW, because even though the child window is Unicode-aware, the main VB message pump isn't. So Unicode character keypresses are converted to ANSI by the application's central TranslateMessageA/DispatchMessageA functions.
Pasting Unicode text into an edit box or RTB bypasses this problem, so there is no trouble pasting Kazakh text directly into an edit box. IMEs can also bypass this problem, because they may perform the WM_KEYDOWN -> WM_CHAR conversion for you, bypassing VB's TranslateMessage entirely. So Chinese input can work on the text box, for example, while a standard keypress from a Kazakh keyboard fails.
To my knowledge, this is why the problem occurs. I can think of two possible solutions (but maybe there are more...?).
The solution I use is to subclass WM_KEYDOWN (which you do already, to raise KeyDown events). Inside the WM_KEYDOWN message, you must perform your own translation from the virtual keycode into a Unicode character. ToUnicode is the API that handles this. Once ToUnicode has given you the correct Unicode character value, you can dispatch it manually to the edit box by sending your own WM_CHAR message, and supplying the Unicode value you obtained.
The second solution you could try is overriding the main VB message pump's -A functions with the -W equivalents. In the thread Jonney linked, vbForums user wqweto describes his efforts to do this. The advantage of this approach is not needing to manually generate your own Unicode characters for every Unicode-aware control that accepts key input. However, I don't know if there are other side-effects with overriding VB's main functions this way. (Windows should automatically convert Unicode messages sent to ANSI windows, but it's always hard to know side-effects with VB due to the way it custom handles some messages but not others.)
I hope this information helps. You are welcome to look at or use my implementation if it's helpful. It's BSD licensed and you can find it here. The relevant window proc is the last function in the class. I don't implement IOLEInPlaceActiveObject so there is some extra hooking code involved, but hopefully the ToUnicode stuff is not too hard to pick out.
I would be hesitant to Hook the keyboard when there is another option.
A Vb6 solution for this problem was first published on 9/22/2000 in book "Internationalization with Visual Basic" by Michael Kaplan.
I had to modify the code slightly on 02-July-2005 to handle surrogate pairs (single keystroke generates 2 Unicode characters).
This technique can be applied to both TextBox and RichEdit controls.
Assuming the control is already subclassed, as would usually be the case for a control created with API CreatWindowExW:
Code:Private Declare Function ToUnicodeEx Lib "user32" (ByVal uVirtKey As Long, ByVal uScanCode As Long, lpKeyState As Byte, ByVal pwszBuff As Long, ByVal cchBuff As Long, ByVal wFlags As Long, ByVal dwhkl As Long) As Long
Private Declare Function lstrlenW Lib "kernel32" (ByVal lpString As Long) As Long
Private Declare Function CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (dest As Any, Src As Any, ByVal cb As Long) As Long
Private m_KeyCodeCached As Long
'Cache the wParam in WM_KEYDOWN:
m_KeyCodeCached = wParam And &HFFFF&
'Then, during WM_CHAR we get the Unicode character(s) by calling:
Dim sChar As String
sChar = ToCharacterEx(wParam, m_KeyCodeCached, 0&)
If Len(sChar) Then 'assign first Unicode character to wParam
wParam = AscW(sChar)
End If
'Again, in WM_CHAR, if there is a second character (Unicode surrogate pair) set m_KeyCodeCached as follows:
If Len(sChar) > 1 Then 'In this case a second WM_CHAR will be generated
m_KeyCodeCached = AscW(Mid$(sChar, 2, 1))
End If
'Everything else is handled in WM_IME_CHAR or WM_IME_ENDCOMPOSITION.
'And finally the Function ToCharacterEx:
Private Function ToCharacterEx(ByVal KeyAscii As Long, _
ByVal KeyCode As KeyCodeConstants, ByVal hKL As Long) As String
Dim stBuff As String
Dim cch As Long
Dim cpg As Long
Dim lPtr As Long
Dim rgvkc(0 To 255) As Byte
stBuff = String$(32, vbNullChar)
Call GetKeyboardState(rgvkc(0))
lPtr = StrPtr(stBuff)
cch = ToUnicodeEx(KeyCode, 0, rgvkc(0), lPtr, Len(stBuff), 0, hKL)
ToCharacterEx = PtrToStrW(lPtr)
If Not IsUnicode(ToCharacterEx) Then 'This may not be necessary
ToCharacterEx = ChrW$(KeyAscii)
End If
End Function
'And Function PtrToStrW:
'Dereference Unicode string pointer
Private Function PtrToStrW(ByVal lpsz As Long) As String
Dim lLen As Long
If lpsz Then
lLen = lstrlenW(ByVal lpsz)
PtrToStrW = Space$(lLen)
CopyMemory ByVal StrPtr(PtrToStrW), ByVal lpsz, lLen * 2
End If
End Function
Private Function IsUnicode(s As String) As Boolean
Dim i As Long
Dim bLen As Long
Dim Map() As Byte
If LenB(s) Then
Map = s
bLen = UBound(Map)
For i = 1 To bLen Step 2 'Analise HighByte only.
If (Map(i) > 0) Then
IsUnicode = True
Exit Function
End If
Next
End If
End Function
Thanks, DrUnicode. I apologize for being unclear in my previous post - hooks shouldn't be required for Krool (or anyone else). I only mentioned hooks in reference to my sample code, if anyone decided to look at it. I use hooks to solve a different problem, so some of my ToUnicode setup is handled outside the subclassing procedure, and I didn't want that to confuse anyone.
But your sample code is much more concise, so I definitely recommend referring to it instead of mine!
Do you know if your sample code has trouble handling dead characters? I ask because Michael Kaplan did a great series on ToUnicode years after publishing his VB book, and he describes the extra steps required to work around ToUnicode's handling of dead keys. (Relevant link: http://www.siao2.com/2005/01/19/355870.aspx) There still seems to be a lot of confusion on this point (e.g. StackOverflow is full of questions on the topic), so I thought I'd mention it.
No. All I can say is that I haven't had any support calls with IME complaints after fixing the surrogate issue in 2005.Quote:
Do you know if your sample code has trouble handling dead characters?
Here's a shorter (and faster!) equivalent:
Code:Private Declare Function SysReAllocString Lib "oleaut32.dll" (ByVal pBSTR As Long, Optional ByVal pszStrPtr As Long) As Long
'Returns a copy of a null-terminated Unicode string (LPWSTR/LPCWSTR)
Private Function GetStrFromPtr(ByVal Ptr As Long) As String
SysReAllocString VarPtr(GetStrFromPtr), Ptr
End Function
So Krool, in a nutshell, here's how you can fix the problem with Kazakh (and other) keyboards:
1) Use DrUnicode's suggested code to capture the Unicode chars.
2) DrUnicode's code needs one fix, if I may. The return value of ToUnicode is important. I recommend reading the full MSDN page for the function, but basically, the return code tells you the number of valid characters in the string that ToUnicode returns. (It can also return 0 if no characters were generated, or -1 if a dead key was pressed.) Anyway, if the return value is 1 or higher, you must use the return value to trim the string, because "the buffer may contain more characters than the return value specifies. When this happens, any extra characters are invalid and should be ignored."
3) After getting DrUnicode's fix working, you'll need to make sure dead keys still work. Load up the US International keyboard and try a few keypresses:
` + a should give you à
~ + n should give you ñ
' + e should give you é
...etc. This should be checked because ToUnicode has some known issues with eating dead key presses when it's invoked.
4) If dead keys still work - great! If not, let us know and hopefully we can sort it out.
Typing "Tilde+a" and "Grave+a" I get this in Notepad and UniTextBox.
Notepad:
~a`a U.S. Normal
ãà U.S. International
UniTextBox:
~a`a U.S. Normal
ãà U.S. International
Looks good here.
Let`s wait for Krool to implement this and see if the results are the same.
I found the solution again...
The system return always unicode last pressed as 94, or 0x5E, for dead keys... as Reserved (look here http://msdn.microsoft.com/en-us/libr...v=vs.85).aspx)
so in a keydown event we get that...
a 94 or -1 means...skip that....
DrUnicode Thank you very much, for the excellent tasks you have for us...So now a simple upgrade " And I<>94 " to glist and the Textviewer can work with french keyboard (For greek keyboard that 94 keycode never produced...so there is a deeper layer for keyboard works I think...and I don't know...why???)Code:I = GetLastKeyPressed
If I <> -1 And I <> 94 Then UKEY$ = ChrW(I) Else UKEY$ = ""
@ DrUnicode, your solution mightbe the best I guess. However, with your method I was able to fix the kazakh issue. But not the pair issue (dead key first), e.g. ^ + o = ô
You said you got it to work. Can you provide a full test sample. At best into my TextBox. Thanks