|
Hi,
I seem to be having a weird problem with threads in C#.
I've been using this to create threads and call methods like so:
Thread queryThread = new Thread( new ThreadStart( QueryThread ) );
queryThread.Start();
However when I try to call methods with any parameters such as queryServerRange(1,2)
with the following code:
Thread queryRangeThread = new Thread( new ThreadStart( queryServerRange(0, int.Parse(servers.Count.ToString())) ));
queryRangeThread.Start();
the compiler throws a fit and refuses to compile with the message:
"Method Name Expected". Only if I call a method without passing parameters does it not complain.
Any ideas what I am doing wrong?
Thanks,
Peter
|
|
|
|
|
Hi Peter,
As far as I know, the function name that you use to construct the Threadstart must return void and take no parameters.
The work-around I've used (and please tell me if this is bad!!!) is to create a class, stuff the "parameters" into properties on the class and then call a method on the class to do the work...for example:
<br />
public class WorkAround{<br />
public int iParameter1;<br />
public int iParameter2;<br />
public WordAround (int P1,int P2){<br />
this.iParameter1 = P1;<br />
this.iParameter2 = P2;<br />
<br />
}<br />
public void DoWork(){<br />
}<br />
}<br />
<br />
...<br />
<br />
WorkAround WA=new WorkAround (0,int.Parse(servers.Count.ToString())) ; <br />
Thread queryRangeThread = new Thread( new ThreadStart( WA.DoWork ));<br />
queryRangeThread.Start();<br />
<br />
I'm sure I've made a mistake or two above...but you get the idea: stuff your parameters into properties on a class you define and then call a method on the class the conforms to that requirements of ThreadStart()
Hope this helps,
Bill
|
|
|
|
|
That usage is not supported. See http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/html/cpconcreatingthreads.asp for an example of the suggested way to pass data to and from threads.
|
|
|
|
|
In addition to Bill's recommendation (a good one), you can also use a worker thread, part of a thread pool so that the threads in your application don't get wildly out of the control (a thread pool has a max number of threads that can run concurrently, along with some other advantages). For more information, see the documentation for the ThreadPool class in the .NET Framework SDK, specifically the ThreadPool.QueueUserWorkItem . You can pass an object (which can be anything, including an array of other objects) to the delegate.
The method Bill mentions gives you a little more OO control, though, since you can set up and use such an object in a separate step, although the advantages of a ThreadPool can be nice, too. Just depends on what you need.
Microsoft MVP, Visual C#
My Articles
|
|
|
|
|
Thanks for all the advice guys; I gave it a lot of thought I came up with a slightly different solution; since all the threads do the same task, just on different keys in the hashtable - I've set it so each thread has a number and from that number the thread figures out which keys its supposed to be handling.
Thanks,
Peter
|
|
|
|
|
Hi guys,
When i want to reference one com object in my project i can see 3 or 4 object with the same name and version but different path, ( it 's for tlb file) is there any way i can clean my registry content up for those library, for example is there any method like this RemoveRegistry(GUID ClassGUID) then it removes all of the registry content for that library.
thanx in advance
|
|
|
|
|
The reason you see multiple typelib references is because they are using different GUIDs, so even if such a function existed (which it doesn't, but it isn't hard to create) it would be effective because each typelib is registering with a different GUID (otherwise you wouldn't see multiple references).
Remove them manually by searching for your typelib using regedit.exe.
The thing to do is eliminate the problem. You MUST use hard-coded GUIDs using the GuidAttribute for all classes and interfaces that are exposed as COM objects and interfaces. The GUID on the interface should NEVER change. If you need a new interface, implement the previous version of the interface and create a new one (like IMyInterface2), giving it a new GUID. The class GUID should typically not change.
To solve your immediately problem, you should also use an assembly-level GuidAttribute for your assembly, which is used as the typelib ID when a typelib is generated:
[assembly: Guid("cac7a0f0-c3a7-4039-abd7-1bc55b924bd7")] (Generate your own, though)
When you register your class using regasm.exe /tlb <filename> now, the typelib will always have the same GUID and only the last path you registered will exist in the registry.
You should read those links I gave a while back discussing exposing .NET controls as COM objects. It does discuss this as well.
Microsoft MVP, Visual C#
My Articles
|
|
|
|
|
We have a legacy java application that changes the time/date stamp on a file to let our main application know that it needs to be updated. Unfortunately, Java seems to be locking the file down because I cant get the file watcher event to fire off. Now I know the file watcher is working correctly because we also have a vb6, and a c# application that changes the time/date stamp on the same file, and for those changes the file watcher event is firing. I was wondering if anyone had any suggestions on what I could possibly do. Checking the Java code, its seems that there arent any streams that arent getting closed, its just a simple File.setLastModified() method call.
Thanks,
Ryan
|
|
|
|
|
There wouldn't be any streams to close since the date is a file system attribute, not part of the file stream.
Since this is an instance method, is the instance of the File class being destroyed and garbage collected?
Microsoft MVP, Visual C#
My Articles
|
|
|
|
|
The File class is being set to null in the finally clause of the method.
|
|
|
|
|
Hi,
Can anyone tell me why I am getting this error?
See the end of this message for details on invoking <br />
just-in-time (JIT) debugging instead of this dialog box.<br />
<br />
************** Exception Text **************<br />
System.Web.Services.Protocols.SoapException: Server was unable to process request. --> A generic error occurred in GDI+.<br />
at System.Web.Services.Protocols.SoapHttpClientProtocol.ReadResponse(SoapClientMessage message, WebResponse response, Stream responseStream)<br />
at System.Web.Services.Protocols.SoapHttpClientProtocol.Invoke(String methodName, Object[] parameters)<br />
at Mugshot_grabber2.desktop5130.mgupload.upload(String user, String password, Byte[] imgBuffer) in C:\Documents and Settings\Peter Greenall\Desktop\Mugshot_grabber3\Web References\desktop5130\Reference.cs:line 59<br />
at Mugshot_grabber2.Form1.captureTimer_Tick(Object sender, EventArgs e) in c:\documents and settings\peter greenall\desktop\mugshot_grabber3\form1.cs:line 631<br />
at System.Windows.Forms.Timer.OnTick(EventArgs e)<br />
at System.Windows.Forms.Timer.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr idEvent, IntPtr dwTime)<br />
<br />
<br />
************** Loaded Assemblies **************<br />
mscorlib<br />
Assembly Version: 1.0.3300.0<br />
Win32 Version: 1.0.3705.288<br />
CodeBase: file:----------------------------------------<br />
Mugshot_grabber2<br />
Assembly Version: 1.0.1496.30186<br />
Win32 Version: 1.0.1496.30186<br />
CodeBase: file:----------------------------------------<br />
System.Windows.Forms<br />
Assembly Version: 1.0.3300.0<br />
Win32 Version: 1.0.3705.288<br />
CodeBase: file:----------------------------------------<br />
System<br />
Assembly Version: 1.0.3300.0<br />
Win32 Version: 1.0.3705.288<br />
CodeBase: file:----------------------------------------<br />
System.Drawing<br />
Assembly Version: 1.0.3300.0<br />
Win32 Version: 1.0.3705.288<br />
CodeBase: file:----------------------------------------<br />
Accessibility<br />
Assembly Version: 1.0.3300.0<br />
Win32 Version: 1.0.3705.0<br />
CodeBase: file:----------------------------------------<br />
DShowNET<br />
Assembly Version: 1.0.0.1<br />
Win32 Version: 1.0.0.1<br />
CodeBase: file:----------------------------------------<br />
System.Web.Services<br />
Assembly Version: 1.0.3300.0<br />
Win32 Version: 1.0.3705.288<br />
CodeBase: file:----------------------------------------<br />
System.Data<br />
Assembly Version: 1.0.3300.0<br />
Win32 Version: 1.0.3705.288<br />
CodeBase: file:----------------------------------------<br />
System.Xml<br />
Assembly Version: 1.0.3300.0<br />
Win32 Version: 1.0.3705.288<br />
CodeBase: file:----------------------------------------<br />
System.Web<br />
Assembly Version: 1.0.3300.0<br />
Win32 Version: 1.0.3705.288<br />
CodeBase: file:----------------------------------------<br />
nfmtjpvp<br />
Assembly Version: 0.0.0.0<br />
Win32 Version: 1.0.3705.288<br />
CodeBase: file:----------------------------------------<br />
System.EnterpriseServices<br />
Assembly Version: 1.0.3300.0<br />
Win32 Version: 1.0.3705.288<br />
CodeBase: file:----------------------------------------
I am trying to call a web service which accepts the following paramaters (string, string, byte[]). The web service then connects to an MS Sql DB to store the byte[] along with other information, after performing some user validation using the two strings supplied.
Cheers,
Peter
Why does it always rain on me
|
|
|
|
|
Hi all,
I am not sure if this is the right place to post this...sorry in advance if it should be elsewhere:
I need a little help...here's the problem:
I am writing a windows service that runs under the localsystem account. In it's startup code it impersonates a domain user in order to gain access to files on another machine in the domain. All that works fine.
Trouble is: I try to create a set of FileSystemWatcher objects to monitor the directories on the remote machine and they fail, saying that the path is invalid. When I run the service under a domain account (not localsystem) the FileSystemWatchers work fine.
So I suspect (maybe) that the FileSystemWatchers are living in a seperate thread(s) that are running under the same login as the process started under, not the impersonated one.
Does this sound (un)reasonable to anyone? Anyone know how to get the FileSystemWatcher object to run under an impersonated identity?
Thanks in advance
Bill
|
|
|
|
|
Maybe a different way of asking the question is in order. If you were to successfully implement the impersonation, how would you (or your client) specify the user name and password for the user to impersonate? Likely, the answer would involve adding to or createing a configurtion UI and encrypting passwords to store in files or registry keys, etc. Since that would only get you to the same place that you already reached by specifying a proper login for the service itself -- are there any reasons you should not require that the service run under a domain account?
John
"You said a whole sentence with no words in it, and I understood you!" -- my wife as she cries about slowly becoming a geek.
|
|
|
|
|
Hi John,
Thanks for the advice. Actually, I have been considering that option too. As I understand it, I need to grant whatever domain user I select the "act as part of the operating system" privilege on the machine running the service, yes? I need to discuss with our network admins. if they have a domain level policy preventing this...don't know yet.
Definitely a good option...but I am not sure it's going to fly in the present setting.
Besides, at this point, I'd REALLY like to know how to make it work the way I am trying it...
Thanks again,
Bill
|
|
|
|
|
The FileSystemWatcher runs in another thread, yes. How do you think you can set Enabled to true and continue your code?
Before you do set Enabled , you should get the impersonated IIdentity , wrap that in an IPrincipal implementation (such as WindowsPrincipal ) and pass that to AppDomain.SetThreadPrincipal in order to set the principal for new threads created in this AppDomain .
Another idea to solve this problem is to - if possible - create an account in your domain specifically for this service, much like many database admins do for SQL Server. Then you can grant this user permission to whatever directories you need watched and exclude it from those that don't (just be sure to handle exceptions properly when access is denied).
Microsoft MVP, Visual C#
My Articles
|
|
|
|
|
Thank you Heath!
Duh! Of course they run in a seperate thread...Sorry my ignorance here runs deep aparently.
I tried to implement what you suggested...the code is below.
<br />
System.Security.Principal.WindowsPrincipal p;<br />
p=new WindowsPrincipal(System.Security.Principal.WindowsIdentity.GetCurrent());<br />
<br />
AppDomain.CurrentDomain.SetThreadPrincipal (p);<br />
I've verified that WindowsIdentity.GetCurrent() is, in fact, the identity I want to use...but it still gives me the same error (at the creation of the FileSystemWatchers...not when I enable them, btw).
What did I mess up? Do I need to create a new AppDomain?
I may follow your other advice and run the service under a special domain user but I'd really like to know how to do it this way too.
Thanks again.
Bill
|
|
|
|
|
Did you use WindowsIdentity.GetCurrent in the handler for any of the FileSystemWatcher events, or just after your service was started?
Microsoft MVP, Visual C#
My Articles
|
|
|
|
|
Heath,
All the Impersonation, WindowsIdentity.GetCurrent, etc. occur in the code of the service itself. It's all part the the OnStart event handler which, subsequently, also creates the FileSystemWatchers.
I do not reference WindowsIdentity.GetCurrent in the FileSystemWatcher event handlers...but I don't think it would matter, since the error occurs when the FileSystemWatcher constructor is called.
Bill
|
|
|
|
|
OK...
I could not get the AppDomain.SetThreadPrincipal to work, so I took another tact.
I created a class ImpersonatingLurker that derives from the System.IO.FileSystemWatcher. The only difference is that the first thing it does in it's constructor is the impersonation. This seems the get the principal set correctly for the thread then handles the FileSystemWatcher. The full class definition is:
public class ImpersonateingLurker :System.IO.FileSystemWatcher
{
public ImpersonateingLurker(string strPath,string strFilter, System.Security.Principal.WindowsPrincipal p)
{
Debug.WriteLine ("Lurker Constructor:"+p.Identity.Name );
WindowsIdentity i = (WindowsIdentity) p.Identity;
i.Impersonate ();
this.Path = strPath;
this.Filter = strFilter;
}
}
Then in the OnStart event handler for the windows service we do:
int iToken;
LogonUser("user","domain","password",3,0,out iToken);
IntPtr token2 = new IntPtr(iToken);
WindowsIdentity wi = new WindowsIdentity(token2);
WindowsPrincipal wp = new WindowsPrincipal (wi);
...
ImpersonateingLurker IL = new ImpersonateingLurker (PathOfInterest,Filter,wp);
And it all seems to work out...Thanks to Heath and John for their advice!
Bill
|
|
|
|
|
I need view combobox in datagrid
please help me
|
|
|
|
|
There are several articles available which teach people how to do this. Look through the articles here on www.codeproject.com[^], first. If you don't find it there, then do a search on www.google.com[^]. You will find a walkthrough, code, and other people's opinions on the article -- much better than a quick response someone may give here.
John
"You said a whole sentence with no words in it, and I understood you!" -- my wife as she cries about slowly becoming a geek.
|
|
|
|
|
I have a conundrum. I have recently been tasked with using a C# program to extract files from an Access Database. The files, Excel 2002, were stored using the following VBA based that I found on MSDN.
ACC: Reading, Storing, & Writing Binary Large Objects (BLOBs)
Further research found the following code which I thought would be the C# equivalent code so that I could extract the Excel spreadsheets back to a file. The aim of the project is that I could then email them as attachments to a central party in my company for review.
Obtaining BLOB Values from a Database
The VBA code extracts the Excel files back to their original state correctly while the C# extracted files are twice the size of the originals and totally unreadable by Excel.
Help????? What am I doing wrong?
Paul Kennedy
Father/Son/Husband/C Programmer
What else could you ask for?
|
|
|
|
|
Hi Paul,
First, I'm assuming that your code matches exactly with that from the links (except for the data source settings).
Second, I'm assuming that the data in the BLOB was generated by your VB code and not some other software.
In my experience, a size difference of exactly 2x normally indicates an ASCII vs. Unicode issue. Looking quickly at the links you provided, the VB code may actually storing a Unicode (2 byte) value in the database for each byte that was loaded into the string. IF that is the case, the VB code handles this when it reverses the loads the Blob that it had stored previously. However, the C# code is being precise by avoiding any translation to or from a string.
Take a hard look at the actual bytes coming back through the C# blob request. If every other byte is a zero, it is very probable that the VB code stored extra data. To solve this, you could either re-write the correct data into the database, or strip the extra byte from the values returned when the C# code gets the BLOB data.
John
"You said a whole sentence with no words in it, and I understood you!" -- my wife as she cries about slowly becoming a geek.
|
|
|
|
|
If this BLOB represents text, you can also use the System.Text.Encoding to translate the bytes to the correct text using the encoding that you specify.
Microsoft MVP, Visual C#
My Articles
|
|
|
|
|
Hi all.
I have the following regular expression pattern that I go t from a book.
^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,10}$
The book says this is suppose to validate atleast 1 uppercase, 1 lowercase, 1 digit, no special characters and between 8 and 10 characters. So "hello123" is not valid, but "Hello123" is valid. Unfortunately "Hello 123" or "Hello@123" are also valid, but should be invalid. What is the correct regular expression syntax?
Thanks in advance
|
|
|
|
|