Ich habe ein kleines Problem mit Threads. Die Situation ist die: Ich rufe eine Prozedur auf, die im Prinzip das Programm blockieren würde. Sie macht ihre Arbeit, kehrt dann zurück, und dann geht´s weiter. Bei Fenstern passiert dann dieses unschöne "weiß werden", und im TaskMan steht u.U. "reagiert nicht", usw.
Das habe ich bei der alten Delphi-Version mit einem Thread gelöst:
Delphi-Quellcode:
//
// merging
//
var
fThreadIsBusy : boolean = false;
function ThreadProc(p: pointer): integer; stdcall;
var
session : HxSession;
col : IHxCollection;
s : string;
begin
Result := 0;
// get namespace name
s := string(p);
if(s = '') then exit;
// set busy flag
fThreadIsBusy := true;
// create "HxSession" interface
if(CoInitializeEx(nil,COINIT_APARTMENTTHREADED or
COINIT_SPEED_OVER_MEMORY) = S_OK) then
try
session := CoHxSession.Create;
if(session <> nil) then
begin
// initialize namespace
try
session.Initialize(widestring('ms-help://' + s),0);
except
session := nil;
end;
if(session <> nil) then
begin
// Get "IHxCollection" interface, ...
col := session.Collection;
// ... & merge index
if(col <> nil) then col.MergeIndex;
end;
session := nil;
end;
finally
CoUninitialize;
end;
// clear busy flag
fThreadIsBusy := false;
end;
procedure MergeNamespace(const NamespaceName: string;
ThreadPriority: TPrioritySet = tpHighest);
const
RealPriorityClasses : array[TPrioritySet]of integer =
(THREAD_PRIORITY_ABOVE_NORMAL,
THREAD_PRIORITY_BELOW_NORMAL,
THREAD_PRIORITY_HIGHEST,
THREAD_PRIORITY_IDLE,
THREAD_PRIORITY_LOWEST,
THREAD_PRIORITY_NORMAL,
THREAD_PRIORITY_TIME_CRITICAL);
var
dwThreadId : dword;
hThread : THandle;
begin
if(NamespaceName = '') then exit;
// set busy flag
fThreadIsBusy := true;
// create thread, ...
hThread := CreateThread(nil,0,@ThreadProc,
pointer(NamespaceName),0,dwThreadId);
if(hThread <> 0) then
begin
// ... & set its priority
SetThreadPriority(hThread,RealPriorityClasses[ThreadPriority]);
CloseHandle(hThread);
end;
end;
function MergeIsBusy: boolean;
begin
Result := fThreadIsBusy;
end;
aufgerufen sah das dann so aus:
Delphi-Quellcode:
MergeNamespace('MS.PSDK.1033');
while(MergeIsBusy) do ProcessMessages(dlg);
So wurde der Dialog mit der Statusmeldung immer aktualisiert, usw.
In CSharp habe ich das jetzt so versucht:
Code:
public sealed class MergeNamespace
{
#region ConsoleMerge
public static void CallConsoleMerge(string namespaceName)
{
try {
HxSession session = new HxSession();
session.Initialize(String.Format("ms-help://{0}", namespaceName), 0);
IHxCollection collection = session.Collection;
collection.MergeIndex();
}
catch {
}
}
#endregion
#region UiMerge
private static bool threadIsBusy = false;
private static string nspaceName = String.Empty;
private static Thread mergeThread = null;
public static bool ThreadIsBusy
{
get {
return threadIsBusy;
}
}
private static void ThreadProc()
{
CallConsoleMerge(nspaceName);
threadIsBusy = false;
try {
mergeThread.Join();
}
catch {
}
}
public static void CallUiMerge(string namespaceName)
{
if(namespaceName == null || namespaceName == "") return;
threadIsBusy = true;
nspaceName = namespaceName;
mergeThread = new Thread(new ThreadStart(ThreadProc));
mergeThread.Start();
}
#endregion
public MergeNamespace()
{
}
}
Prinzipiell klappt es auch,
, nur der Thread wird nicht ordnungsgemäß freigegeben/entfernt, so dass ein zweiter Aufruf nicht mehr funktioniert. Und in meinem Tool kann man diesen
Merging-Prozess auch mehrmals aufrufen, wenn man will. Bei Delphi habe ich "CloseHandle" benutzt, aber bei CSharp?
Hat jemand einen Tipp für mich?
Bessere Ideen sind natürlich auch willkommen. Wichtig ist mir, wie gesagt, dass ich mit folgender Konstruktion:
Code:
MergeNamespace.CallUiMerge("MS.PSDK.1033");
while(MergeNamespace.ThreadIsBusy) { Application.DoEvents(); };
den Dialog regelmäßig aktualisieren kann, so dass der User nicht den Eindruck hat, das Programm hat sich aufgehangen, denn dieses
Merging kann manchmal doch recht lange dauern.