-
Dec 14th, 2017, 07:55 AM
#1
Get output location path from a usercontrol
Ok ... If I have a usercontrol that I am making, is there a way to get the current build output path from within the control, for the assembly that it is inserted onto?
Hope that makes sense :P
Thanks in advance,
Kris Bennett
-
Dec 14th, 2017, 01:30 PM
#2
Re: Get output location path from a usercontrol
I think that information can only be present if debug information is generated for the assembly, which isn't done in a release build.
What are you trying to accomplish? That information won't be relevant once the code is deployed.
This answer is wrong. You should be using TableAdapter and Dictionaries instead.
-
Dec 14th, 2017, 04:41 PM
#3
Re: Get output location path from a usercontrol
Basically I want to get the filename of the .exe ... or .dll for the thing that the control is inserted onto ...
or be able to access its last built System.Reflection.Assembly...
.. and, yes, I know that this would only be updated when the project is built ... but I am OK with that...
I want to make a UI editor that shows a list of types that are accessible from the assembly
Thanks,
Kris
-
Dec 14th, 2017, 06:28 PM
#4
Re: Get output location path from a usercontrol
Assembly.GetEntryAssembly will generally give you an Assembly object for the EXE that was originally run. GetCallingAssembly would allow you to get an Assembly object representing the direct caller of certain code in your UC, so that would allow you to differentiate between the original EXE and a DLL that might use your UC.
-
Dec 14th, 2017, 06:44 PM
#5
Re: Get output location path from a usercontrol
Here is example I to get a list of all the monsters defined in DemonArena:-
vbnet Code:
'
Dim asm As Assembly = Assembly.GetExecutingAssembly()
For Each t As Type In asm.GetTypes
If t.GetInterface("IDemon") IsNot Nothing AndAlso Not t.IsAbstract Then
Dim mi As New ToolStripMenuItem
mi.Text = t.Name
mi.Tag = t
AddHandler mi.Click, AddressOf EH_MenuItemClick
MenuStrip1.Items.Add(mi)
End If
Next
The above code looks for all non-abstract types in the executing assembly that implements the IDemon interface.
Here's the code with only the bits relevant to your question:-
vbnet Code:
'
Dim asm As Assembly = Assembly.GetExecutingAssembly()
For Each t As Type In asm.GetTypes
Next
The above enumerates all types in the assembly. You can use the properties of type t to filter out the types you're not interested in.
-
Dec 14th, 2017, 06:55 PM
#6
Re: Get output location path from a usercontrol
Here's another example that enumerates all controls from every assembly that has been loaded.
vbnet Code:
' 'Enumerate all loaded assemblies For Each a As Assembly In AppDomain.CurrentDomain.GetAssemblies() 'Enumerate all types in the assembly For Each t As Type In a.GetTypes.Where(Function(t1) t1.IsSubclassOf(GetType(Control))) Debug.WriteLine(t.Name) Next Next
Note that the above will enumerate ALL loaded assemblies, even the standard assemblies like System.Core, and not just the assemblies created by you in your solution.
-
Dec 15th, 2017, 07:08 AM
#7
Re: Get output location path from a usercontrol
Originally Posted by jmcilhinney
Assembly.GetEntryAssembly will generally give you an Assembly object for the EXE that was originally run. GetCallingAssembly would allow you to get an Assembly object representing the direct caller of certain code in your UC, so that would allow you to differentiate between the original EXE and a DLL that might use your UC.
Thanks , but I already know this jmcilhinney and Niya ... I should of probably said I want this at design time though
... that method is not possible to get the assembly that the control is sitting on in design time.
Any other ideas?
Thanks,
Kris
-
Dec 15th, 2017, 09:41 AM
#8
Re: Get output location path from a usercontrol
The designer runs the same code from the same assemblies so there shouldn't be a reason reflection doesn't work. In fact, a lot of designer functionality is dependent on reflection. You're probably doing something wrong.
I still don't get what you're trying to do. Are you looking for the assembly where the Control is defined? Are you looking for the assembly where the Control is being used? Could you clarify?
I suspect the problem is that you're simply looking in the wrong assemblies for whatever it is you want.
-
Dec 15th, 2017, 09:55 AM
#9
Re: Get output location path from a usercontrol
To clarify, you're saying that you want your compiled control to be able to determine, at design time, where the compiled EXE will be saved when it's used in a project, correct? I'm curious to know what use that would be.
Last edited by jmcilhinney; Dec 15th, 2017 at 09:59 AM.
-
Dec 16th, 2017, 06:47 PM
#10
Re: Get output location path from a usercontrol
Originally Posted by jmcilhinney
To clarify, you're saying that you want your compiled control to be able to determine, at design time, where the compiled EXE will be saved when it's used in a project, correct? I'm curious to know what use that would be.
What I want to achieve:
...This should list the types available to the assembly, that the user control is inserted on ONLY
Ok ... if I have the following project structure:
Application - Project that opens form that is contained in FormHolder
FormHolder - Holds a form that contains the usercontrol in ControlHolder (This assembly has a form that the user control is inserted onto)
ControlHolder - Holds the usercontrol
These are the results at runtime - bold is the one that I need:
GetCallingAssembly: System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
GetEntryAssembly: Application, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
GetExecutingAssembly: ControlHolder, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
Parent?.GetType.Assembly: FormHolder, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
... but I require this at design time ... at design time these are the results:
GetCallingAssembly: System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
GetEntryAssembly: Nothing
GetExecutingAssembly: ControlHolder, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
Parent?.GetType.Assembly: System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
As stated I am making a UIEditor for a usercontrol so that the user can select a Type... Property:
VB.Net Code:
<Editor(GetType(TypeTypeEditor), GetType(UITypeEditor))> Public Property DataType As Type
UIEditor is filled with:
VB.Net Code:
Private Class ClassItem Public ReadOnly Property ClassType As Type Public Sub New(ClassType As Type) Me.ClassType = ClassType End Sub Public Overrides Function ToString() As String Return ClassType.FullName End Function End Class
From the following method:
VB.Net Code:
Dim AssembliesToSearch = {BaseAssembly}.Union(BaseAssembly.GetReferencedAssemblies.Select(Function(x) System.Reflection.Assembly.Load(x.FullName))) For Each a In AssembliesToSearch For Each item In From xItem In a.GetTypes() Where xItem.IsAbstract = False AndAlso xItem.IsVisible = True List.Add(New ClassItem(item)) Next Next lb.Items.AddRange(List.OrderBy(Function(x) x.ToString).ToArray)
When the item is selected it selects the ClassItem.ClassType .. so the Type
So I need BaseAssembly filled with the assembly that the control is inserted on ...
Now I am sure that the assembly isn't necessary going to be built so will prob have to access it by filename (and only fill the list if it exists) to load the assembly from the designer... so will need the last built location.
Thanks in advance,
Kris
EDIT:
Also just noticed that even the executing assembly is not the one that was built when building the project ... but a temp one ... in my case in:
%AppData%\..\Local\Microsoft\VisualStudio\14.0\ProjectAssemblies\tasg1zl001\ControlHolder.dll
... strange ... I mean you have to build your project to have controls show in designers ... why not just use their built location??!
Last edited by i00; Dec 17th, 2017 at 12:10 AM.
-
Dec 16th, 2017, 09:59 PM
#11
Re: Get output location path from a usercontrol
What do you mean by "holds the control". Understanding what you mean by this is the key to everything.
-
Dec 17th, 2017, 12:08 AM
#12
Re: Get output location path from a usercontrol
Originally Posted by Niya
What do you mean by "holds the control". Understanding what you mean by this is the key to everything.
The assembly that you insert the user control onto... controls parent assembly
Kris
-
Dec 17th, 2017, 12:32 PM
#13
Re: Get output location path from a usercontrol
Originally Posted by i00
The assembly that you insert the user control onto... controls parent assembly
Kris
Err....I still don't know what you mean. How does one insert a control into an assembly?
An assembly can either contain control types or they can have code that references control types either from themselves or other assemblies. Those are the only two relationships that are possible between objects and assemblies.
Assemblies are just a collection of types and resources. Types are classes that can contain data and/or executable code. The classes can be controls, or any other type of object.
-
Dec 17th, 2017, 01:20 PM
#14
Re: Get output location path from a usercontrol
I feel like I typed a longish answer to this and now I don't see it, so now I'm worried that answer went to a different thread.
The angle of the answer was "It might not be possible, but you need to use a debugger to find out. You have to use the debugger, because you're going to have to reverse-engineer some things that aren't documented, and I'm only comfortable talking about what is documented."
This answer is wrong. You should be using TableAdapter and Dictionaries instead.
-
Dec 17th, 2017, 06:11 PM
#15
Re: Get output location path from a usercontrol
Originally Posted by Niya
Err....I still don't know what you mean. How does one insert a control into an assembly?
An assembly can either contain control types or they can have code that references control types either from themselves or other assemblies. Those are the only two relationships that are possible between objects and assemblies.
Assemblies are just a collection of types and resources. Types are classes that can contain data and/or executable code. The classes can be controls, or any other type of object.
The assembly for the controls parent...
At runtime you can get this by going (within the control):
Me.Parent.Assembly
Thanks,
Kris
-
Dec 17th, 2017, 08:48 PM
#16
Re: Get output location path from a usercontrol
Originally Posted by i00
The assembly for the controls parent...
At runtime you can get this by going (within the control):
Me.Parent.Assembly
Thanks,
Kris
You mean like this:-
vbnet Code:
' Private Function GetControlParentAssembly(ByVal c As Control) As Assembly If c.Parent IsNot Nothing Then Return c.Parent.GetType.Assembly End If Return Nothing End Function
Or if you want to do it from within a Control:-
vbnet Code:
Imports System.Reflection Public Class MyCustomControl Inherits Control Private Function GetParentAssembly() As Assembly If Me.Parent IsNot Nothing Then Return Me.Parent.GetType.Assembly End If Return Nothing End Function End Class
-
Dec 18th, 2017, 08:20 AM
#17
Re: Get output location path from a usercontrol
Originally Posted by Niya
You mean like this:-
Yes ... but, as mentioned, that method only works correctly at runtime .
Kris
-
Dec 18th, 2017, 01:38 PM
#18
Re: Get output location path from a usercontrol
I'm not blowing smoke in #14.
Sometimes the thing we want to do is not possible. Design-time is NOT run-time.
This answer is wrong. You should be using TableAdapter and Dictionaries instead.
-
Dec 18th, 2017, 05:02 PM
#19
Re: Get output location path from a usercontrol
Originally Posted by Sitten Spynne
I'm not blowing smoke in #14.
Sometimes the thing we want to do is not possible. Design-time is NOT run-time.
Actually you're wrong in this case. The designer works by executing code. Many things that are possible at runtime are also possible at design time.
Originally Posted by i00
Yes ... but, as mentioned, that method only works correctly at runtime .
Kris
That's strange. I got it to work in the designer with no problems:-
Here's the code for the control:-
vbnet Code:
Imports System.Reflection Public Class MyCustomControl Inherits Control Protected Overrides Sub OnPaint(e As System.Windows.Forms.PaintEventArgs) MyBase.OnPaint(e) Dim asm As Assembly = GetControlParentAssembly(Me) If asm IsNot Nothing Then e.Graphics.DrawString(asm.FullName, Me.Font, Brushes.Black, New PointF(2, 2)) End If ControlPaint.DrawBorder(e.Graphics, Me.ClientRectangle, Color.Black, ButtonBorderStyle.Solid) End Sub Private Function GetControlParentAssembly(ByVal c As Control) As Assembly If c.Parent IsNot Nothing Then Return c.Parent.GetType.Assembly End If Return Nothing End Function End Class
-
Dec 18th, 2017, 06:15 PM
#20
Re: Get output location path from a usercontrol
Originally Posted by Niya
Actually you're wrong in this case. The designer works by executing code. Many things that are possible at runtime are also possible at design time.
That's strange. I got it to work in the designer with no problems:-
Here's the code for the control:-
I demonstrated that in #10 .. yes technically it works ... as in doesn't crash ... but an instance of Windows.Forms is used to parent (box) the control for the designer... at runtime this will be the assembly that the control is inserted onto not Windows.Forms ... that is not what I want as mentioned in #17.
Kris
-
Dec 18th, 2017, 06:50 PM
#21
Re: Get output location path from a usercontrol
Originally Posted by i00
I demonstrated that in #10 .. yes technically it works ... as in doesn't crash ... but an instance of Windows.Forms is used to parent (box) the control for the designer... at runtime this will be the assembly that the control is inserted onto not Windows.Forms ... that is not what I want as mentioned in #17.
Kris
Well that certainly is weird. At this point you need to debug that code when it runs at design time. Single step through it and see what is actually happening line by line. That's what I do when I face problems like this. It sounds like you have a lot of complicated stuff going on in your classes. You may have made a mistake somewhere in your code that results in the different run time behavior.
-
Dec 19th, 2017, 02:23 AM
#22
Re: Get output location path from a usercontrol
It's not weird, it's just wrong to assume the designer works by running the .exe. I kind of did this as my job for a long time.
The designer is a process that hosts the form. That means things like GetEntryAssembly() aren't going to return the same thing as they would at Runtime. Probably the most reliable thing here will be to look at a StackTrace from a breakpoint while in the designer and manually find the frame that represents the boundary. Once you see it a couple of times you get the hang of it, but it's a little different depending on exactly what's going on in your program.
To get the right kind of breakpoint, you need 2 copies of Visual Studio open with your project. Use one to attach to the other Visual Studio. It got a little more complex at some point because they separated the designer into a different process. You might have to hunt that one down. When you get it set up right, you can debug your control in the designer. That's the perfect time to investigate the StackTrace.
This answer is wrong. You should be using TableAdapter and Dictionaries instead.
-
Dec 19th, 2017, 01:05 PM
#23
Re: Get output location path from a usercontrol
Here's the kind of quick example you get if you spend half an hour in the debugger:
I made a project that has a ClassLibrary1 that contains a custom control. There's a Windows Forms application that hosts the control. The control's constructor prints a stack trace and some information about the static assemblies you can reference easily. Here's what happens.
Runtime
Call stack:
Code:
at ClassLibrary1.Class1..ctor()
at WindowsApp43.Form1.InitializeComponent()
at WindowsApp43.Form1..ctor()
at System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean noCheck, Boolean& canBeCached, RuntimeMethodHandleInternal& ctor, Boolean& bNeedSecurityCheck)
at System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark)
at System.RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark)
at System.Activator.CreateInstance[T]()
at WindowsApp43.My.MyProject.MyForms.Create__Instance__[T](T Instance)
at WindowsApp43.My.MyProject.MyForms.get_Form1()
at WindowsApp43.My.MyApplication.OnCreateMainForm()
at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.OnRun()
at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.DoApplicationModel()
at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.Run(String[] commandLine)
at WindowsApp43.My.MyApplication.Main(String[] Args)
Pretty sensible, Main creates the Application context, which starts creating the form, which has to create the control.
Assemblies:
The "entry" assembly is WindowsApp43, the .exe. The "executing" assembly is ClassLibrary1, the DLL.
Design-time
Call stack:
Code:
at ClassLibrary1.Class1..ctor()
at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)
at System.Reflection.RuntimeConstructorInfo.Invoke(BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at System.SecurityUtils.SecureConstructorInvoke(Type type, Type[] argTypes, Object[] args, Boolean allowNonPublic, BindingFlags extraFlags)
at System.ComponentModel.ReflectTypeDescriptionProvider.CreateInstance(IServiceProvider provider, Type objectType, Type[] argTypes, Object[] args)
at System.ComponentModel.TypeDescriptor.TypeDescriptionNode.CreateInstance(IServiceProvider provider, Type objectType, Type[] argTypes, Object[] args)
at Microsoft.VisualStudio.Design.MultiTargetingProvider.CreateInstance(IServiceProvider provider, Type objectType, Type[] argTypes, Object[] args)
at System.ComponentModel.TypeDescriptor.TypeDescriptionNode.CreateInstance(IServiceProvider provider, Type objectType, Type[] argTypes, Object[] args)
at System.ComponentModel.TypeDescriptionProvider.CreateInstance(IServiceProvider provider, Type objectType, Type[] argTypes, Object[] args)
at System.ComponentModel.TypeDescriptor.TypeDescriptionNode.CreateInstance(IServiceProvider provider, Type objectType, Type[] argTypes, Object[] args)
at System.ComponentModel.DelegatingTypeDescriptionProvider.CreateInstance(IServiceProvider provider, Type objectType, Type[] argTypes, Object[] args)
at System.ComponentModel.TypeDescriptor.TypeDescriptionNode.CreateInstance(IServiceProvider provider, Type objectType, Type[] argTypes, Object[] args)
at System.ComponentModel.DelegatingTypeDescriptionProvider.CreateInstance(IServiceProvider provider, Type objectType, Type[] argTypes, Object[] args)
at System.ComponentModel.TypeDescriptor.TypeDescriptionNode.CreateInstance(IServiceProvider provider, Type objectType, Type[] argTypes, Object[] args)
at System.ComponentModel.TypeDescriptor.CreateInstance(IServiceProvider provider, Type objectType, Type[] argTypes, Object[] args)
at System.ComponentModel.Design.DesignSurface.CreateInstance(Type type)
at Microsoft.VisualStudio.Design.VSDesignSurface.CreateInstance(Type type)
at System.ComponentModel.Design.DesignerHost.System.ComponentModel.Design.IDesignerHost.CreateComponent(Type componentType, String name)
at System.ComponentModel.Design.Serialization.DesignerSerializationManager.CreateInstance(Type type, ICollection arguments, String name, Boolean addToContainer)
at System.ComponentModel.Design.Serialization.DesignerSerializationManager.System.ComponentModel.Design.Serialization.IDesignerSerializationManager.CreateInstance(Type type, ICollection arguments, String name, Boolean addToContainer)
at System.ComponentModel.Design.Serialization.CodeDomSerializerBase.DeserializeInstance(IDesignerSerializationManager manager, Type type, Object[] parameters, String name, Boolean addToContainer)
at System.ComponentModel.Design.Serialization.ComponentCodeDomSerializer.DeserializeInstance(IDesignerSerializationManager manager, Type type, Object[] parameters, String name, Boolean addToContainer)
at System.ComponentModel.Design.Serialization.CodeDomSerializerBase.DeserializeExpression(IDesignerSerializationManager manager, String name, CodeExpression expression)
at System.ComponentModel.Design.Serialization.CodeDomSerializer.DeserializeStatementToInstance(IDesignerSerializationManager manager, CodeStatement statement)
at System.ComponentModel.Design.Serialization.CodeDomSerializer.Deserialize(IDesignerSerializationManager manager, Object codeObject)
at System.Windows.Forms.Design.ControlCodeDomSerializer.Deserialize(IDesignerSerializationManager manager, Object codeObject)
at System.ComponentModel.Design.Serialization.TypeCodeDomSerializer.DeserializeName(IDesignerSerializationManager manager, String name, CodeStatementCollection statements)
at System.ComponentModel.Design.Serialization.TypeCodeDomSerializer.Deserialize(IDesignerSerializationManager manager, CodeTypeDeclaration declaration)
at System.ComponentModel.Design.Serialization.CodeDomDesignerLoader.PerformLoad(IDesignerSerializationManager manager)
at Microsoft.VisualStudio.Design.Serialization.CodeDom.VSCodeDomDesignerLoader.PerformLoad(IDesignerSerializationManager serializationManager)
at System.ComponentModel.Design.Serialization.BasicDesignerLoader.BeginLoad(IDesignerLoaderHost host)
at System.ComponentModel.Design.DesignerHost.BeginLoad(DesignerLoader loader)
at System.ComponentModel.Design.DesignSurface.BeginLoad(DesignerLoader loader)
at Microsoft.VisualStudio.Design.DesignerService.Microsoft.VisualStudio.Designer.Interfaces.IVSMDDesignerService.CreateDesigner(Object provider, Object designerLoader)
at Microsoft.VisualStudio.LanguageServices.Implementation.AbstractEditorFactory.CreateEditorInstance(UInt32 grfCreateDoc, String pszMkDocument, String pszPhysicalView, IVsHierarchy vsHierarchy, UInt32 itemid, IntPtr punkDocDataExisting, IntPtr& ppunkDocView, IntPtr& ppunkDocData, String& pbstrEditorCaption, Guid& pguidCmdUI, Int32& pgrfCDW)
at Microsoft.VisualStudio.Shell.Interop.IVsUIHierarchy.ExecCommand(UInt32 itemid, Guid& pguidCmdGroup, UInt32 nCmdID, UInt32 nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut)
at Microsoft.Internal.VisualStudio.PlatformUI.HierarchyUtilities.<>c__DisplayClass35_0.<ExecHierParentChain>b__1()
at Microsoft.VisualStudio.ErrorHandler.CallWithCOMConvention(Func`1 method, Boolean reportError, Boolean setShellErrorInfo)
at Microsoft.Internal.VisualStudio.PlatformUI.HierarchyUtilities.ExecHierParentChain(IVsHierarchyItemManager manager, IVsUIHierarchy lpUIHCmd, IVsUIHierarchy lpUIHCurrent, UInt32 itemidCurrent, Guid& pguidCmdGroupRef, UInt32 nCmdID, UInt32 nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut)
at Microsoft.VisualStudio.PlatformUI.HierarchyItem.HierarchyInvocationController.Invoke(IEnumerable`1 items, InputSource inputSource, Boolean preview)
at Microsoft.Internal.VisualStudio.PlatformUI.InvocationController.Invoke(IEnumerable`1 items, InputSource inputSource, Boolean preview, Func`2 getController)
at Microsoft.Internal.VisualStudio.PlatformUI.InvocationController.Invoke(IEnumerable`1 items, InputSource inputSource, Boolean preview)
at Microsoft.Internal.VisualStudio.PlatformUI.PivotTreeViewItem.InvokeItem(InputDevice sourceDevice)
at Microsoft.Internal.VisualStudio.PlatformUI.PivotTreeViewItem.OnMouseLeftButtonDown(MouseButtonEventArgs e)
at System.Windows.UIElement.OnMouseLeftButtonDownThunk(Object sender, MouseButtonEventArgs e)
at System.Windows.Input.MouseButtonEventArgs.InvokeEventHandler(Delegate genericHandler, Object genericTarget)
at System.Windows.RoutedEventArgs.InvokeHandler(Delegate handler, Object target)
at System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs)
at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
at System.Windows.UIElement.ReRaiseEventAs(DependencyObject sender, RoutedEventArgs args, RoutedEvent newEvent)
at System.Windows.UIElement.OnMouseDownThunk(Object sender, MouseButtonEventArgs e)
at System.Windows.Input.MouseButtonEventArgs.InvokeEventHandler(Delegate genericHandler, Object genericTarget)
at System.Windows.RoutedEventArgs.InvokeHandler(Delegate handler, Object target)
at System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs)
at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
at System.Windows.UIElement.RaiseEventImpl(DependencyObject sender, RoutedEventArgs args)
at System.Windows.UIElement.RaiseTrustedEvent(RoutedEventArgs args)
at System.Windows.UIElement.RaiseEvent(RoutedEventArgs args, Boolean trusted)
at System.Windows.Input.InputManager.ProcessStagingArea()
at System.Windows.Input.InputManager.ProcessInput(InputEventArgs input)
at System.Windows.Input.InputProviderSite.ReportInput(InputReport inputReport)
at System.Windows.Interop.HwndMouseInputProvider.ReportInput(IntPtr hwnd, InputMode mode, Int32 timestamp, RawMouseActions actions, Int32 x, Int32 y, Int32 wheel)
at System.Windows.Interop.HwndMouseInputProvider.FilterMessage(IntPtr hwnd, WindowMessage msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
at System.Windows.Interop.HwndSource.InputFilterMessage(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)
at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)
at System.Windows.Threading.Dispatcher.LegacyInvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Int32 numArgs)
at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)
You might notice this is a little different. I can see from this call stack a ton of WPF frames that are devenv.exe itself, and by the time we get to the layers with TypeDescriptor we're in WinForms Designer land. You know what I don't see in this call stack? Anything related to WindowsApp43, the .exe file. Interesting.
The Entry assembly is Nothing. Visual Studio is apparently either not directly a .NET application or something else fishy. The Executing assembly is ClassLibrary1, the DLL.
Conclusion
Runtime is not design-time. "Common sense" doesn't apply.
I vaguely remember knowing that the Form you see on the designer isn't even a real form, it's all some kind of pseudo-form that just happens to have the same properties as a form. I didn't feel like digging in the debugger to verify that, it's only about 10 minutes more work but I got the payload I wanted.
If you have the ExecutingAssembly for the control, you can use the CodeBase property to get an idea of the path. But in my test project that's not useful, because the control is in a class library that isn't the same assembly as the executable, which means it's in a different location. I double-checked. It's in that AppData directory as indicated, and ONLY the DLL is there. That's because the designer doesn't rely on "all the DLLs are in the same directory", it manually loads what it needs.
So I don't have conclusive information that makes me believe you can get from the control's assembly to the executable's assembly. And I have reason to believe even if you could get the exectuable's assembly, its location at design-time does not simulate the run-time deployment environment.
MAYBE there's some way to get from a custom designer into the VS automation system. From there you could probably suss out a lot more. That would be an awful lot to go over and it'd take me days to get that headspace back.
This answer is wrong. You should be using TableAdapter and Dictionaries instead.
-
Dec 19th, 2017, 03:46 PM
#24
Re: Get output location path from a usercontrol
I wish this question had come up when I was deep in development of custom controls. I came across problems like this all the time and was able to solve most of them. I would have probably been able to figure this out too. As of now, I haven't done anything serious with regards to control development in a couple years. However, custom controls was always my kinda thing, even from VB6. I always loved doing them and although I'm contemplating leaving WinForms behind one day, it's likely I'll dive back into control development sometime before that.
Being so long from it, my memory of really deep technical specifics has faded somewhat but something in me believes what i00 wants is possible. Based on my own experience solving tricky problems like this, I would say he might need to shuffle around some stuff in his code. I had to do a lot of refactoring myself in order to "trick" things into working but this is very grueling nearly every time. It involved a lot of trial and error and a lot of late nights hunting down obscure documentation.
-
Dec 19th, 2017, 04:24 PM
#25
Re: Get output location path from a usercontrol
Yeah I hear you, the design-time side of things was always kind of shaky in WinForms because it had "hundreds" of interested people instead of "millions" like run-time documentation. Part of the reason I only put a debugger to it today is because when you told me I was wrong in #14, my memory's just foggy enough I assumed you'd done the debugger work and I was wrong. Turns out we're both wandering around in a kind of fog!
The worst was WPF design time. You can't even turn that stuff up via Google search anymore. I could only get to it via a link I bookmarked. That's a whole different story, though.
Heck, I got surprised in this project because I thought I'd use the DesignMode property to make some code only run in design time. For some reason, that property's False when my code runs. This is EXACTLY how I remember working in the designer felt all the time.
I really don't know how to proceed because the next steps are crazy things that would take quite a bit of research for me to even start prototyping. Usually a rule of thumb I had for accepting/rejecting a feature was to hunt around and see if someone big like Telerik had a similar feature at design-time. If I thought it was impossible, and no one else had a feature like it, I had a strong case for rejection. Every now and then they had it, and it meant I had to figure out what the heck they did. Sometimes that involved ILDASM. Usually that revealed a trick I'd have never figured out on my own, and that they probably found by accident.
This answer is wrong. You should be using TableAdapter and Dictionaries instead.
-
Dec 19th, 2017, 09:42 PM
#26
Re: Get output location path from a usercontrol
Originally Posted by Sitten Spynne
Part of the reason I only put a debugger to it today is because when you told me I was wrong in #14, my memory's just foggy enough I assumed you'd done the debugger work and I was wrong.
I also did this kinda thing a lot in VB6. One of the biggest shocks I got when I started doing custom controls in .Net was how much different the design time environment was. The degree of influence you had over the design time environment was simply astonishing. What I found particularly interesting was how this influence was expressed. You simply wrote code. All the Visual Studio designers were just classes, no different on any technical level to any of the classes you would use or write for your run time functionality. This is why I said that run time and design time weren't that different. I was actually making a comparison to my experience in VB6 where run time behavior and design time behavior were truly different.
VB6 designers were just this huge black box. As far as I could tell their inner workings were fundamentally different from the run time environment. I could be wrong, but it certainly felt that way. You could access it's functionality through some end points like PropertyBags and what not but the designer wasn't exposed in terms of normal program elements like classes and interfaces the way .Net designers were.
To put it simply, .Net designers are normal .Net classes that help you build other .Net classes. VB6 designers are programs that help you build something resembling classes inside which you would place your executable code. In hindsight, it is quite weird.
From a completely objective point of view, you are correct. Design time and run time are two different things but I was being very subjective. My apologies. I should have been clearer in expressing my thoughts.
Last edited by Niya; Dec 19th, 2017 at 09:52 PM.
-
Dec 21st, 2017, 09:16 PM
#27
Re: Get output location path from a usercontrol
Originally Posted by Sitten Spynne
in #14, my memory's just foggy enough I assumed you'd done the debugger work and I was wrong. Turns out we're both wandering around in a kind of fog!
Wow ... well until now I didn't even know you can debug the designer stuff thanks for that ... kudos given ... will save me A LOT of time
-
Dec 21st, 2017, 09:27 PM
#28
Re: Get output location path from a usercontrol
Originally Posted by Sitten Spynne
Usually a rule of thumb I had for accepting/rejecting a feature was to hunt around and see if someone big like Telerik had a similar feature at design-time. If I thought it was impossible, and no one else had a feature like it, I had a strong case for rejection.
I think something like this should be possible ...
The UITypeEditor on the BindingSource.Datasource property seems to do some reflection stuff based on the reference tree from the assembly that the UC is on when you select Object in it
Kris
-
Dec 22nd, 2017, 01:09 PM
#29
Re: Get output location path from a usercontrol
Originally Posted by i00
Wow ... well until now I didn't even know you can debug the designer stuff thanks for that ... kudos given ... will save me A LOT of time
Well that's what I meant when I said this:-
Originally Posted by Niya
Well that certainly is weird. At this point you need to debug that code when it runs at design time.
I assumed you knew what I was talking about. My bad.
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|