I'm trying to split some prior crafted code into a DLL. It's a simple logger system.
There are a few things that need to be shared with the main form in the project, so I set them up as a shared variable, but I don't use shared stuff often, and I worry it will cause variable conflicts regarding scope. I figured I would make a post here about it and see if someone can explain what I don't fully understand.
Since this is a logger it will be used a couple of places. Other DLLs that need logging may reference it through a instanced object and project reference. My main form will also have an instanced object and a reference to the logger libary.
Since one of my properties is a connection string and it's shared, does this mean that a instance of my logger class inside a DLL will have the same shared values as a instance on my main UI form? Or will the fact that the instance is inside of a DLL provide the scope boundary I need? I'm hoping it does..
I mainly worry that I might want to log using two different connection strings down the road.
(I hope my question makes sense. If it doesn't, post comments and I'll try to clarify.)
No, the fact that the instance is in a DLL does not provide the scope boundary you need. If the class or members in the DLL were declared static they would be shared and you could run into problems. So, just don't declare them static and be sure to create new instances of the object(s) when you consume them and you should be ok.
Related
I've been battling with AS3 for a little while now, and I'm working on a simple application using only actionscript and the FlashDevelop/flex-compiler combo. I've hit a bit of a wall in my fledgling OOP understanding, and I'm wondering whether someone might be able to point me in the right direction. I have genuinely read several books, and spent many hours reading online tutorials etc, but something's just not clicking!
What's baffling me is this: When something is declared 'public', according to what I read, it is therefore available anywhere in the application (and should therfore be used with care!) However, when I try to use public properties and methods in my program, they most definitely are not available anywhere other than from the class/object that instantiated them.
This leads me to conclude that even if objects (of different class) are instantiated from the same (say 'main') class, they are not able to communicate with each other at all, even through public members.
If so, then fair enough, but I've honestly not seen this explained properly anywhere. More to the point, how do different objects communicate with other then? and what does Public actually mean then, if it only works through a direct composition hierarchy? If one has to write applications based only on communication from composer class to it's own objects (and presumably use events for, er, everything else?) - isn't this incredibly restrictive?
I'm sure this is basic OOP stuff, so my apologies in advance!
Any quick tips or links would be massively appreciated.
There are different topics you are covering in your question. Let me clarify:
What does the modifier public mean?
How can instances of the same class communicate to each other?
--
1.
In OOP you organize your code with objects. An object needs to be instantiated to provide its functionality. The place where you instantiate the object can be considered as the "context". In Flash the context might be the first frame, in a pure AS3 movie, it might be the main class, in Flex it could be the main mxml file. In fact, the context is always an object, too. Class modifier of your object public class MyClass tells your context whether it is allowed to instantiate the object or not. If set to internal, the context must live in the same directory as the class of the object. Otherwise it is not allowed to create a new object of the class. Private or protected are not valid class modifiers. Public class ... means that any context may create an object of that class. Next: Not only instantiation is controlled by these modifiers but also the visibility of a type. If set to internal, you cannot use an expression like var obj : InternalType in a context that does not live in the same directory as Internal type.
What about methods and properties? Even if your context is allowed to access a type, certain properties and methods might be restricted internal/protected/private var/method and you perhaps are not able to invoke them.
Why we're having such restrictions? Answer is simple: Differnent developers may develop different parts of the same software. These parts should communicate only over defined interfaces. These interfaces should be as small as possible. The developer therefore declares as much code as possible to be hidden from outside and only the necessary types and properties publicly available.
Don't mix up with modifiers and global properties. The modifier only tells you if a context is allowed to see a type or method. The global variable is available throughout the code. So even if a class is declared to be public, instances of that class do not know each other by default. You can let them know by:
storing the instances in global variables
providing setter such as set obj1(obj1 : OBJ1) : void where each object needs to store the reference in an instance variable
passing the object as method arguments: doSomething(obj1 : OBJ1)
Hope this helps you to more understand OOP. I am happy to answer your follow up questions.
Jens
#Jens answer (disclaimer: I skimmed) appears to be completely correct.
However, I'm not sure it answers your question very directly, so I'll add a bit here.
A public property is a property of that class instance that is available for other objects to use(function: call, variable: access, etc). However, to use them you must have a reference (like a very basic pointer, if that helps?) to that object instance. The object that instantiates (creates, new ...) that object can take that reference by assigning it to a variable of that class type.
// Reference is now stored in 's'
public ExampleClass s = new ExampleClass();
If you'd like to, you do have the option of making a static property, which is available just by knowing the class name. That property will be shared by all instances of that class, and any external class can refer to it (assuming it's public static) by referring to the class name.
A public property is referred to by the reference you stored.
//public property access
s.foo
s.bar(var)
A static property is referred to by the class name.
//static property access
ExampleClass.foo
ExampleClass.bar(var)
Once you've created the instance, and stored the reference, to an object, you can pass it around as you'd like. The below object of type OtherExampleClass would receive the reference to 's' in its constructor, and would have to store it in a local variable of its own to keep the reference.
public OtherExampleClass s2 = new OtherExampleClass(s);
I have written some code in VB that verifies that a particular port in the Windows Firewall is open, and opens one otherwise. The code uses references to three COM DLLs. I wrote a WindowsFirewall class, which Imports the primary namespace defined by the DLLs. Within members of the WindowsFirewall class I construct some of the types defined by the DLLs referenced. The following code isn't the entire class, but demonstrates what I am doing.
Imports NetFwTypeLib
Public Class WindowsFirewall
Public Shared Function IsFirewallEnabled as Boolean
Dim icfMgr As INetFwMgr
icfMgr = CType(System.Activator.CreateInstance(Type.GetTypeFromProgID("HNetCfg.FwMgr")), INetFwMgr)
Dim profile As INetFwProfile
profile = icfMgr.LocalPolicy.CurrentProfile
Dim fIsFirewallEnabled as Boolean
fIsFirewallEnabled = profile.FirewallEnabled
return fIsFirewallEnabled
End Function
End Class
I do not reference COM DLLs very often. I have read that unmanaged code may not be cleaned up by the garbage collector and I would like to know how to make sure that I have not introduced any memory leaks. Please tell me (a) if I have introduced a memory leak, and (b) how I may clean it up.
(My theory is that the icfMgr and profile objects do allocate memory that remains unreleased until after the application closes. I am hopeful that setting their references equal to nothing will mark them for garbage collection, since I can find no other way to dispose of them. Neither one implements IDisposable, and neither contains a Finalize method. I suspect they may not even be relevant here, and that both of those methods of releasing memory only apply to .Net types.)
Not sure what to recommend here. There is most definitely no memory leak here, the garbage collector releases COM reference counts. COM objects are not disposable but you can release them early with Marshal.ReleaseComObject(). The trouble with doing this explicitly is that it is normally very hard to track interface references.
In your code snippet for example, calling ReleaseComObject on the icfMgr won't have any effect. There's a hidden reference through the LocalPolicy member that will keep the interface reference alive. You'd have to call ReleaseComObject on that hidden reference as well.
I would not recommend making this a practice at all. Getting it wrong produces hard to diagnose failure, you're essentially back to the bad old days of explicit memory management. But it is somewhat manageable in your specific example.
You are exactly right: unmanaged code cannot be managed and thus needs to be managed by hand: disposed of. However, this greatly depends on what you are doing, but in many cases, it is sufficient to wrap the object instantiation around a Using-block. This only works if you use an object that implements IDisposable.
However, the way you currently create an instance of a COM object, you will not have the possibility to clean up easily. It depends on the object. When it doesn't need cleaning up (check the destructor of FwMgr), it doesn't need disposing either. However, most COM objects do need disposal.
So, how to add the IDisposable interface to a COM object that doesn't natively support it? It's a bit of work to do so manually, but you should create a wrapper .NET assembly. Luckily, the work has been taken out of our hands and Microsoft has created some tools and guidelines.
Some of this information is covered here too. You may want to also look up WeakReference as an alternative.
Note that COM and .NET do not talk well together, but they do talk. An excellent reference is .NET and COM The Complete Interoperability Guide by Don Box, SAMS Publishing.
EDIT:
In answer to your "memory leak" question: it is impossible to tell whether you introduced a memory leak, and how big it is. It depends on how often you call your COM object. Call it once per running process? Don't worry too much. Call it hundredths of times in an inner loop? Be very careful. Want to know for sure? Lookup the original documentation or source: if it releases handles, memory or other resources when it is destructed, then yes, you introduced a leak.
I have a Util module in my VB.NET program that has project-wide methods such as logging and property parsing. The general practice where I work seems to be to call these methods directly without prefixing them with Util. When I was new to VB, it took me a while to figure out where these methods/functions were coming from. As I use my own Util methods now, I can't help thinking that it's a lot clearer and more understandable to add Util. before each method call (you know immediately that it's user-defined but not within the current class, and where to find it), and is hardly even longer. What's the general practice when calling procedures/functions of VB modules? Should we prefix them with the module name or not?
Intellisense (and "Goto Definition") should make it trivial to find where things are located, but I always preface the calls with a better namespace, just for clarity of reading. Then it's clear that it's a custom function, and not something built in or local to the class you're working with.
Maybe there's a subtle difference I'm missing, but I tend to use shared classes instead of modules for any code that's common and self-contained - it just seems easier to keep track of for me, and it would also enforce your rule of prefacing it, since you can't just call it from everywhere without giving a namespace to call it from.
I usually put the complete namespace for a shared function, for readibility.
Call MyNameSpace.Utils.MySharedFunction()
Util is such a generic name.
Example from the .Net framework. You have System.Web.HttpUtility.UrlEncode(...). Usually you refer to this as HttpUtility.UrlEncode since you have an import statement at the top.
The name of the class which has the static utility methods should be readable and explainable. That is good practice. If you have good class names they might just as well reside in a Utils namespace, but the class name should not be Utils.
Put all your logging in a Logger class. All your string handing in a StringUtils class etc. And try to keep the class names as specific as possible, and I'd rather have more classes with fewer functions than the other way around.
I have a VB6 DLL embedded in some ASP pages. The DLL hits a Codebase database, an obsure and obsolete database engine (a dialect/variation on dBase) that virtually no-one has even heard of. It takes Codebase nearly a second to initialise a new connection, which is unacceptably slow and so I've created a connection pool, managed by a VB class. The single instance of this class is created at the start of a VB module, i.e.:
Private m_codebaseManager As New CodebaseManager
My problem is that periodically the class initialization method is called again completely wrecking my pooling class and I've no idea why. Terminate does not fire and there's no sign of any crash occurring, so why on earth is initialize called? My understanding is that data in non-class modules persists for the lifetime of the DLL. Is that correct and if not, under what circumstances does a module 'restart'?
I would recommend removing the "New" from the variable declaration. Declaring a variable "As New" causes it to be checked every time it is referenced, and if set to Nothing a new instance of your CodebaseManager will be created.
A better solution would be to declare your variable like this:
Private m_codebaseManager As CodebaseManager
and then explicitly set it to a new instance when your application starts:
Set m_codebaseManager = New CodebaseManager
This means you can be sure you won't be creating any unintentional new instances of CodebaseManager. You'll probably then still have a bug but at least it will be an "Object or with block variable not set" error which you should be able to easily fix.
My understanding is that data in non-class modules persists for the lifetime of the DLL. Is that correct and if not, under what circumstances does a module 'restart'?
Sort of. Global state (module public/private vars) are apartment specific and is stored in TLS slots. VB6 supports apartment threading only, so each thread gets a "fresh" copy of the global state. Because ASP environment is multi-threaded so each thread gets a separate DB connection "pool".
If you need a real global state you have to use Application object to store it. If you put apartment threaded objects there (like VB6 ones) these can serialize you multi-threaded ASP environment and degrade performance. Use ADO objects or Dictionary objects or anything you are certain is free threaded.
Btw, you can let COM+ do the object/connection pooling for you. If OLEDB provider is a better one it can do connection pooling internally too (SQLOLEDB for MSSQL is an example).
But it's a DLL and not an ActiveX exe, so there's no Main() function and nowhere for the 'Set m_codebaseManager = New CodebaseManager' line to go except in global scope.
Is there possible to create a COM-instance in it's own, dedicated, host-process?
I guess some background is needed.
We have an end-user client which has it's central logical components inside an singleton-COM object. (Not propper singleton, but it uses global variables internally, so it would fail.) So that there should be only one instance per exe-file. Convenient while making the client.
However, I should now make a "client-simulator" to test the server-side. I therefore which to make 20 instances of the client-component.
If I could make each instance instanciate in its own exe-host, then the singleton-issue would be handled.
Regards
Leif
I have been struggling with this problem for a few days. I finally found a solution that works. My COM object is written using ATL, so my code snippet will be geared toward that, but the technical solution should be clear. It all hinges on how the class objects are registered. The REGCLS_SINGLEUSE flag is the key. I now have separate processes for each object instance.
In the ATL module, override the RegisterClassObjects() function as follows:
HRESULT RegisterClassObjects(DWORD dwClsContext, DWORD dwFlags) throw()
{
return base::RegisterClassObjects(CLSCTX_LOCAL_SERVER, REGCLS_SUSPENDED | REGCLS_SINGLEUSE);
}
From MSDN regarding REGCLS_SINGLEUSE:
REGCLS_SINGLEUSE
After an application is connected to a class object with
CoGetClassObject, the class object is removed from public view so that
no other applications can connect to it. This value is commonly used
for single document interface (SDI) applications. Specifying this
value does not affect the responsibility of the object application to
call CoRevokeClassObject; it must always call CoRevokeClassObject when
it is finished with an object class.
My theory is that because the registration was removed from public view, it causes a new process to be created for the subsequent instantiations.
This other question mentioned a description of how to use DLLHost as a surrogate process:
http://support.microsoft.com/kb/198891
I've never tried this myself, and I don't know off-hand if you can specify flags for the factories (which control if surrogates can be reused for multiple objects), but maybe you can tweak that via DCOMCNFG or OLEVIEW.
My COM days are long gone, but as far as I remember, there's no built-in way to do that.
It might be easier to rewrite your code so it supports multiple instances than to go the one-process-per-instance route with COM, but here's what you could do:
Use thread-local storage for your global variables and write another CoClass, where each instance owns its own thread through which accesses to the class with the global variables are marshaled. This would at least allow you to avoid the performance impact of DCOM.
Write your own out-of-process exe server (similar to windows' DllHost.exe) to host your COM instances. This requires IPC (Inter-Process Communication), so you either have to code something yourself that marshals calls to the external process or use DCOM (presuming your COM object implements IDispatch)