Hello everybody. I have an UC that raises errors when certain conditions are met. It works fine if there is only one instance of the UC, otherwise there is trouble. I'm sending attached the project. Remember it's not finished, so if you want to play with it, only the "bold", "italics" and "underlined" buttons are enabled. And I still haven't implemented context sensitivity, i. e. if you select a bold part the button doesn't automatically show as selected. To reproduce my problems do the following. First of all download the project and copy the bitmaps to the c:\ directory. Compile the ocx. Then:
1) First scenario:
a) Open a standard EXE project. Form1 is added by default.
b) Add the ocx to the project components
c) Insert an instance of the ocx into Form1
d) Add a usercontrol to the project (click Project -> Add User Control)
e) Insert an instance of my ocx into the usercontrol.
Problems:
a) you'll see that the error is raised. However I verified it to be raised on the resize event, and not on the InitProperties event as it should be according to my code.
b) Close the new UC and launch the project. The following error occurs:
"License information for this component not found. You do not have an appropriate license to use this functionality in the design environment"
2) Second scenario:
a) Open a standard EXE project. Form1 is added by default.
b) Add the ocx to the project components
c) Insert an instance of the ocx into Form1
d) Write the following code into Form1:
Code:
Private Sub Form_Load()
Dim a As VBControlExtender
Set a = Controls.Add("xxx.usercontrol1", "ctl") 'write the name of the ocx project in place of the xxx
End Sub
e) Launch the project
f) Launch the project again.
Problems:
a) When you launch the project for the first time, the error that should be raised by my code is not raised. Instead you'll get "Automation error", then "Can not call friend function on object which is not an instance of defining class", then again "Automation error"
b) The second time you launch the project you get "Automation error", then the error from my code, then again "Automation error". Then the application doesn't terminate regularly, and when you try closing it from the IDE, a crash occurs.
I'm at a total loss with these problems. Please help me. Thank you.
Last edited by dichelson; Jun 19th, 2009 at 04:09 PM.
I realized that my project couldn't be opened correctly. I'm sending attached the revised version. Plus, I updated the first post, to make it clear that the UC needs to be compiled into an ocx first, and to clarify the meaning of "add a usercontrol". Remember to download all the bitmaps into the c:\ directory before even opening the IDE for the first time, or the project won't work.
Maybe my directions are not clear enough. I'll give you more detailed directions then.
1) Download the RTB2.zip file
2) Extract all the .bmp files into your local c:\ directory, leaving names unchanged
3) Create directory RTB on the desktop
4) Extract all the remaining files into RTB
5) Open the IDE
6) Click File -> Open project
7) Browse to RTB
8) Double click Group1.vbg
9) click on Usercontrol1 (code) titlebar
10) Click on Project -> Project2 properties
11) Type MyCtl into the Project Name field
12) Click OK
13) Click File -> Make MyCtl.ocx
14) Select your favorite directory
15) Click OK
16) Exit the IDE
17) Reopen the IDE
18) Open a standard EXE project. Form1 is added by default
19) Click Project -> Components and check MyCtl
20) Click OK
21) You'll see a new icon in the toolbox. Click on it, then click on form1 and drag the mouse to create a rectangle. You'll get an instance of my control on form1
22) Click Project -> Add User Control. If a dialog box shows up, click on Open
23) Insert an instance of my ocx into the usercontrol exactly the same way you did above for form1
Problems:
a) you'll see that the error "This control can only have a form as its parent" is raised. However I verified it to be raised on the resize event, and not on the InitProperties event as it should be according to my code.
b) Close the usercontrol designer window and click on Run -> Start. The following error occurs:
"License information for this component not found. You do not have an appropriate license to use this functionality in the design environment"
24) Exit the IDE
25) Reopen the IDE
26) Open a standard EXE project. Form1 is added by default
27) Click Project -> Components and check MyCtl
28) Click OK
29) Insert an instance of MyCtl into Form1 (see step 21)
30) Write the following code into Form1:
Code:
Private Sub Form_Load()
Dim a As VBControlExtender
Set a = Controls.Add("MyCtl.usercontrol1", "ctl")
End Sub
31) Launch the project
32) Launch the project again.
Problems:
a) When you launch the project for the first time, the error that should be raised by my code ("This control cannot be loaded dynamically") is not raised. Instead you'll get "Automation error", then "Can not call friend function on object which is not an instance of defining class", then again "Automation error"
b) The second time you launch the project you get "Automation error", then the error from my code, then again "Automation error". Then the application doesn't terminate regularly, and when you try closing it from the IDE, a crash occurs.
Problems:
a) you'll see that the error "This control can only have a form as its parent" is raised. However I verified it to be raised on the resize event, and not on the InitProperties event as it should be according to my code.
b) Close the usercontrol designer window and click on Run -> Start. The following error occurs:
"License information for this component not found. You do not have an appropriate license to use this functionality in the design environment"
a) Only guesses here. Trying to raise an error during InitProperties is interferring somehow. However, I doubt it is being raised during resize because the code is in the InitProperites. I am not sure how you verified this in a compiled control. Like I said, I doubt it, but if you are convinced, you might want to try logging data to a file during the events. Using modal message boxes should not be used.
b) Licensing is the issue. You'd have to read up on licensing to try to understand it. From what I gather, the RTB is in your compiled control, but because the RTB is licensed (assumption based on the error), you can distribute the RTB (though possibly illegally inside your usercontrol: read links below) because the licensing information is compiled into your ocx when you created myCtl. So far so good. Now when you tried to add your ocx to another ocx, you get the "License information..." error because of the way licensing works. In order to add myCtl, which contains a licensed RTB, to another ocx, your ocx must also be licensed. To test this, in myCtl project properties check the box "Required License Key", rem out the error raising, then recompile as myCtl2, try again.
I haven't looked at your other set of "problems" yet, but you might want to look at the above, do some more research. My guess is that the 2 problems are related. The Friend issue and crashing are related to your subclassing. Your subclass routine tries to call a Friend property. Really, you should be crashing on the first launch, but the way VB reuses memory and delay loads/unloads dlls/ocxs, when you crash can't really be predicted.
By the way, this statement part:
If Not TypeOf UserControl.Parent Is Form Or TypeOf UserControl.Parent Is MDIForm
I think you may mean this:
If Not (TypeOf UserControl.Parent Is Form Or TypeOf UserControl.Parent Is MDIForm)
Last edited by LaVolpe; Jun 22nd, 2009 at 12:03 AM.
Insomnia is just a byproduct of, "It can't be done"
a) Only guesses here. Trying to raise an error during InitProperties is interferring somehow. However, I doubt it is being raised during resize because the code is in the InitProperites. I am not sure how you verified this in a compiled control. Like I said, I doubt it, but if you are convinced, you might want to try logging data to a file during the events. Using modal message boxes should not be used.
b) Licensing is the issue. You'd have to read up on licensing to try to understand it. From what I gather, the RTB is in your compiled control, but because the RTB is licensed (assumption based on the error), you can distribute the RTB (though possibly illegally inside your usercontrol: read links below) because the licensing information is compiled into your ocx when you created myCtl. So far so good. Now when you tried to add your ocx to another ocx, you get the "License information..." error because of the way licensing works. In order to add myCtl, which contains a licensed RTB, to another ocx, your ocx must also be licensed. To test this, in myCtl project properties check the box "Required License Key", rem out the error raising, then recompile as myCtl2, try again.
I haven't looked at your other set of "problems" yet, but you might want to look at the above, do some more research. My guess is that the 2 problems are related. The Friend issue and crashing are related to your subclassing. Your subclass routine tries to call a Friend property. Really, you should be crashing on the first launch, but the way VB reuses memory and delay loads/unloads dlls/ocxs, when you crash can't really be predicted.
By the way, this statement part:
If Not TypeOf UserControl.Parent Is Form Or TypeOf UserControl.Parent Is MDIForm
I think you may mean this:
If Not (TypeOf UserControl.Parent Is Form Or TypeOf UserControl.Parent Is MDIForm)
1) I added messageboxes to the various events and found that InitProperties fires, then Resize fires, then the error is raised. I can try logging the events to a file, as you said, and see what happens.
2) Concerning the licensing, no error occurs when I add my ocx to a usercontrol without having another instance of my ocx opened, as long as I rem out my own error message. So I think licensing in itself is not the problem here, although there is some devilish interplay between the two instances involved.
3) No crash occurs normally. Crashes only occur when the control is added dynamically, and only if there is another instance of the control already present. Plus, no crashes occur if I rem out the error message. Seems like only in this case doesn't it like the Friend functions. In the project I posted, there are multiple instances of the control in various forms, and everything works fine.
4) No, If Not TypeOf UserControl.Parent Is Form Or TypeOf UserControl.Parent Is MDIForm is correct. With this statement I mean that the error should be raised either when the parent is not a form, or when the parent is an MDI form.
Last edited by dichelson; Jun 22nd, 2009 at 12:23 AM.
I'll take a look later regarding the subclassing crash.
But I beg to differ on the Form/MDI statement.
Using simple numbers as an example, and I think you will see what I was trying to describe.
Code:
Dim I As Integer
' set i=1 to represent Parent is Form, set i=2 to represent Parent is MDI
' set I=3 to represent something else
I = 2
If Not I=1 Or I=2 Then MsgBox "Invalid Parent"
' now try it this way, which is what I think you want
' set I = 1, then I=2, then I=3
If Not (I=1 Or I=2) Then MsgBox "Invalid Parent"
The 1st IF statement is not what you want because if parent was MDI, you get an invalid parent. I am assuming MDI is a valid parent.
Insomnia is just a byproduct of, "It can't be done"
Also, concerning licensing, I forgot to say that if I rem out my error message and do the same as above, i. e. two instances of the uc, one in form1 and the other one in usercontrol1, no error occurs when I launch the project. It seems like my error messages are the only cause of my problems. Plus, I forgot to say, I found out that if I do the same with a blank uc, i. e. raising the error in the initProperties event and placing one instance into form1, and another one into UserControl1, the same error about licensing occurs. There is no inner licensed control involved in this case.
Ok then, the fact that MDI was being checked is what threw me.
I guess this would work just as well?
If Not TypeOf UserControl.Parent Is Form Then
Out of curiosity, why limit it to a form, why couldn't someone host your ocx in a picturebox or frame for example? I admit I didn't study your code, if the answer is in there.
Insomnia is just a byproduct of, "It can't be done"
1) I can't simply state If Not TypeOf Usercontrol.Parent Is Form, b/c in case the parent is an MDI, then TypeOf Usercontrol.Parent Is Form, plus it is MDIForm.
2) I wrote my code in such a way that the subclasser browses through the Parentforms collection in order to find the correct PrevProc, and more generally, to find which control is associated with the hwnd it received. Every time the ReadProperties event fires, the parent form of the control is added to the collection. I know I could have done it by creating a control collection. That would have been more general. I just didn't think about it (actually this is my first "serious" ocx), and now I don't want to change the subclasser, koz it's been a pain for me to build it. Still, "parent" is not the same as "container", and the user can place my uc inside a picturebox or a frame, if they like. However, this control is not intended to be used inside Office or IE, for example. MDI forms might equally work, didn't check, but I don't want to fuss about it. It doesn't make much sense to insert an RTB directly into an MDI. Instead, you're allowed to place it inside an MDI child form, if you wish.