C# - Softwareschil, aanroepen functie andere thread

Pagina: 1
Acties:

Acties:
  • 0 Henk 'm!

  • korgakos
  • Registratie: April 2008
  • Laatst online: 12-06 19:59
Beste medeTweakers!,

Ik heb een programma die ik kan aansturen met verschillende functies geschreven in c++

Hiervoor heb ik DLL geschreven omdat de taal waar ik het in schrijf C# is.

Tot nu toe werkt alles, ik kan een instantie vna het programma opstarten, ik kan alle instructies uitvoeren etc.

Maar nu is er een instructie (import) die een file moet importeren met miljoenen regels, wat op zijn beurt weer ellendenlang duurt.. (lees 60+ sec)
en nu voel je het aankomen, dan gaat uiteraard de UI zichzelf locken..

Mijn eerste solution was, om gewoon alle instructies vanuit een backgroundworker te doen, dit werkte prima, maar niet geheel naar mijn wens.

Wat ik nu wil:

Ik wil graag vanuit de UI, functies kunnen aanroepen (bijvoorbeeld het opstarten van het programma etc) en vanuit een aparte thread wil ik die `import` functie aanroepen.

Kan ik (en hoe) dit realiseren?


Ik heb de volgende test gedaan:
2 dll's gemaakt, en via de een het programma opstarten en via een functie de pointer achterhalen van "pApp"
om via een ander dll de volgende functie aan te roepen:

pApp->ShowWindow(flag);

Dit werkte, maar wanneer ik dit ga doen in een andere thread,lukt dit op geen enkele manier
(die mij bekend is..)

Schijnbaar gaat dit niet lukken vanuit een andere thread dan waar het programma aangeroepen is.

Weet iemand hier een oplossing voor? Of een andere manier op hoe ik dit beter kan doen?

Overigens kleine info:
Ik ben pas enkele weken geleden begonnen met C#, dus ik weet nog niet geheel van alle mogelijkheden af.

Mvg

Erwin

Acties:
  • 0 Henk 'm!

  • Danot
  • Registratie: Juni 2003
  • Niet online
Kijk eens naar MSDN Using Threading (C# Programming Guide). Hiermee zou je uit de voeten moeten kunnen.

Volgens mij hoef je niet 2 dlls te maken. Gewoon de dll aanspreken vanuit je C#-thread. Je GUI draait dan op een andere thread.

Acties:
  • 0 Henk 'm!

  • korgakos
  • Registratie: April 2008
  • Laatst online: 12-06 19:59
Danot schreef op dinsdag 01 december 2009 @ 11:28:
Kijk eens naar MSDN Using Threading (C# Programming Guide). Hiermee zou je uit de voeten moeten kunnen.

Volgens mij hoef je niet 2 dlls te maken. Gewoon de dll aanspreken vanuit je C#-thread. Je GUI draait dan op een andere thread.
Maar zoals ik al zei had ik al een "thread" gebruikt (backgrounworker)
of zie ik het verkeerd?

ik zou graag direct vanuit de UI de functies willen aanroepen, maar de import functie wil ik vanuit een aparte thread doen, aangezien dit de enige is die lang duurt

[edit]
Of bedoel je het stuk, multithread?

[ Voor 3% gewijzigd door korgakos op 01-12-2009 11:32 ]


Acties:
  • 0 Henk 'm!

Verwijderd

Ik begrijp je post niet helemaal, maar mijn interpretatie is dat je problemen krijgt in de trand van CrossThread exceptions, klopt dat?
Je UI draait in een aparte thread, de main, data die bij een andere thread hoort (je backgroundworker) hebben daar niet zonder meer toegang toe, je zult aan de slag moeten met delegates om het thread boundary probleem op te lossen.

[ Voor 6% gewijzigd door Verwijderd op 01-12-2009 11:35 ]


Acties:
  • 0 Henk 'm!

  • D-Raven
  • Registratie: November 2001
  • Laatst online: 10-09 20:32
Je kunt je type die je in je backgroundworker hebt ingeladen, teruggeven aan de UI thread. Zie de documentatie van de backgroundworker over hoe je resultaten uit je DoWork delegate kunt marshallen naar je UI thread.

Hint: RunWorkerCompleted event..

Acties:
  • 0 Henk 'm!

  • korgakos
  • Registratie: April 2008
  • Laatst online: 12-06 19:59
Nou toen ik vanuit de backgroundworker alle functies uitvoerde die communiceerden met het aan te sturen programma, toen kreeg ik wel eens CrossThread exceptions.
Die kreeg ik wel uiteindelijk weg maar ik vond dit geen mooie oplossing

Daarom wou ik de functies gewoon in de UI laten draaien, behalve de timeconsuming functies (import functie)
deze wil ik apart in een losse thread draaien.

Alleen weet ik niet hoe ik dit moet realiseren


edit:
ik moet wel zeggen dat hier snel gereageerd word, thumbs up !

[ Voor 8% gewijzigd door korgakos op 01-12-2009 11:44 ]


Acties:
  • 0 Henk 'm!

  • korgakos
  • Registratie: April 2008
  • Laatst online: 12-06 19:59
Misschien verduidelijkt dit het:

De c++ code in de dll file die ervoor zorgt dat het programma zich opstart:

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// initialize COM Library
    CoInitialize (NULL);
    // create Application object
    // note: on successful creation, an instance of PGApp will be launched
    // on the server machine
    hr = CoCreateInstance (CLSID_PGApplication, NULL,
    CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER,
    IID_IPGApplication, (void**)&pApp);

    assert(SUCCEEDED(hr));
    hr = pApp->ShowWindow( 0 ); 

    // obtain System object
    hr = pApp->GetSystem(&pTmp);
    assert(SUCCEEDED(hr));
    hr = pTmp->QueryInterface(IID_IPGSystem, (void **)&pSystem);
    assert(SUCCEEDED(hr));
    pTmp->Release();
    // … use objects here
    // release objects
    // note: after the Application object is released, the instance of PGApp that
    // was launched at creation will terminate


De functies vanaf dit punt gebruiken dan of pApp of pSystem.
Dus ik dacht van als ik nu een functie maakt die deze 2 retourneert, en dan via een IntPtr in C# binnen haalt, en dan weer terug stuurt naar een andere functie. en dan een functie aanroept, dacht ik dat het misschien zou lukken om via een andere thread een functie aan te roepen, maar dat lukte niet


C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
public class PGApp_COM
{
[ComImport, Guid("6173E342-AABF-4698-A9BD-AC964F609668")]
public class CoInitializeEx
{
}

[ComImport, Guid("6173E341-AABF-4698-A9BD-AC964F609668"), InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface IPGApplication
{
void ShowWindow(long i);
[return: MarshalAs(UnmanagedType.Interface)]
object GetSystem();
}
[ComImport, Guid("00000000-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface IDispatch 
{
[return: MarshalAs(UnmanagedType.IDispatch)]
object QueryInterface(Guid guid);
}

[ComImport, Guid("6173E343-AABF-4698-A9BD-AC964F609668"), InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface IPGSystem
{
int GetModuleCount();
int GetModuleSerialNumber(
int ModuleIndex);



void AcquireModules(
int SerialNumber0,
int SerialNumber1,
int SerialNumber2,
int SerialNumber3);

void ReleaseAllModules();

int GetAcquiredModuleCount();

[return: MarshalAs(UnmanagedType.BStr)]
string GetAcquiredModuleProperties(
int ModuleIndex);

[return: MarshalAs(UnmanagedType.BStr)]
string GetSWVersion();

void LoadSystem(
[In, MarshalAs(UnmanagedType.BStr)] string SystemPath);

void SaveSystem(
[In, MarshalAs(UnmanagedType.BStr)] string SystemPath,
[In, MarshalAs(UnmanagedType.BStr)] string UserComment,
int SaveData);

void Import(
[In, MarshalAs(UnmanagedType.BStr)] string ImportFilePath,
int BlockNo);

void Export(
[In, MarshalAs(UnmanagedType.BStr)] string ExportFilePath,
long BlockNo,
long ExportType);

void Run();

void Stop();

void Advance();

void Step();

void Jump();

void SetRunTriggerSource(
int RunTriggerSource);

void SetHostRunTrigger();

int GetRunStatus();

bool IsPGBusy();

void SetClockMode(
int ClockMode);

void SetClockPeriod(
double Period);

void SetClockFrequency(
double Frequency);

void SetReferenceClockSource(
int Source);

void SetInputClockThreshold(
double Threshold);

void SetInputClockFilterPeriod(
int FilterPeriod);

void SetInputClockInvert(
int Invert);

void SetInputClockDelay(
double Delay);

void SetDiscontinuousClock(
int DiscontinuousClock);

void SetEventThreshold(
double Threshold);

void SetEventFilterPeriod(
int FilterPeriod);

void SetEventModeForAdvance(
int EventMode);

void SetEventModeForJump(
int EventMode);

void SetRunMode(
int RunMode);

void SetHiZOnStop(
int HiZOnStop);

int GetProbeType(
int ModulePos,
int ProbeIndex);

void SetOutputLevel(
int ModulePos,
int ProbeIndex,
double Level);

void SetDataDelay(
int ModulePos,
int ProbeIndex,
int ByteIndex,
double Delay);

void SetDataDelay180(
int ModulePos,
int ProbeIndex,
int ByteIndex,
int Delay180);

void SetStrobeShape(
int ModulePos,
int ProbeIndex,
int StrobeShape);

void SetVarGroup(
int ModulePos,
int ProbeIndex,
int ChannelIndex,
int Group);

void SetVarHighLevel(
int ModulePos,
int ProbeIndex,
int ChannelIndex,
double HighLevel);

void SetVarLowLevel(
int ModulePos,
int ProbeIndex,
int ChannelIndex,
double LowLevel);

void SetVarSlewRate(
int ModulePos,
int ProbeIndex,
int ChannelIndex,
int SlewRate);

void SetVarDifferential(
int ModulePos,
int ProbeIndex,
int ChannelIndex,
int Differential);

void SetVarDelay(
int ModulePos,
int ProbeIndex,
int ChannelIndex,
double Delay);

void SetVarInhibitThreshold(
int ModulePos,
int ProbeIndex,
double Threshold);

void SetVarInhibitEnable(
int ModulePos,
int ProbeIndex,
int Enable);

void SetSignalInput(
int InputSource);

void SetSignalOutput(
int OutputDest);

void InvertSignalOutput(
int Invert);

object GetGroupNames(); //VARIANT RETURN TYPE!

int GetGroupSize(
[In, MarshalAs(UnmanagedType.BStr)] string GroupName);

[return: MarshalAs(UnmanagedType.BStr)]
String GetProbeChannelNames(
[In, MarshalAs(UnmanagedType.BStr)] string GroupName);

void SetDACSingle(
int ModulePos,
int ProbeIndex,
int Single);

void SetDACBipolar(
int ModulePos,
int ProbeIndex,
int DACInx,
int Bipolar);

void SetDACFilter(
int ModulePos,
int ProbeIndex,
int DACInx,
int Filter);

void DeleteAllBlocks();

int AddBlock(
int VectorCount,
[In, MarshalAs(UnmanagedType.BStr)] string BlockName);

void DeleteAllSequenceLines();

int AddSequenceLine(
[In, MarshalAs(UnmanagedType.BStr)] string p_sLabel,
[In, MarshalAs(UnmanagedType.BStr)] string p_sWaitFor,
[In, MarshalAs(UnmanagedType.BStr)] string p_sBlockName,
int p_nRepeatCount,
[In, MarshalAs(UnmanagedType.BStr)] string p_sJumpIf,
[In, MarshalAs(UnmanagedType.BStr)] string p_sJumpTo,
int p_nSignalValue);

void DeleteAllEvents();

int AddEvent(
[In, MarshalAs(UnmanagedType.BStr)] string p_sEventName,
[In, MarshalAs(UnmanagedType.BStr)] string p_sEventDef);

int UpdateSystemView();
} 
}

[ Voor 66% gewijzigd door korgakos op 16-12-2009 16:59 ]


Acties:
  • 0 Henk 'm!

Verwijderd

- ReportProgress (aangeboden door BackgroundWorker)
- Delegates/events

Acties:
  • 0 Henk 'm!

  • korgakos
  • Registratie: April 2008
  • Laatst online: 12-06 19:59
Verwijderd schreef op dinsdag 01 december 2009 @ 11:46:
- ReportProgress (aangeboden door BackgroundWorker)
- Delegates/events
oke dan ga ik me even hierin verdiepen

Delegates and Events in C# / .NET

thx alvast

Acties:
  • 0 Henk 'm!

  • korgakos
  • Registratie: April 2008
  • Laatst online: 12-06 19:59
Ik heb nu via een delegate het volgende gedaan:

C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
  public void MyFunc()
        {
            PGApp_dll.library.ShowApplication(1);

        }
        delegate void SimpleDelegate();
        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            SimpleDelegate myDelegate = new SimpleDelegate(MyFunc);

            myDelegate();
            
        }

en dan via een knopje de backgroundworker laten runnen,
als ik step into doe zie ik dat de functie PGApp_dll.library.ShowApplication(1); wordt uitgevoerd maar er gebeurd niks...(het programma zou uit hidden mode moeten komen..)

Hierna lukt het ook niet meer via de UI het programma aan te sturen, dan krijg ik een exception

[ Voor 9% gewijzigd door korgakos op 01-12-2009 13:18 ]


Acties:
  • 0 Henk 'm!

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
offtopic:
Ik heb het topic niet helemaal gelezen, maar zet je code a.u.b. even in [code=c#] code hier \[\] tags, dan is het een stuk beter leesbaar

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”


Acties:
  • 0 Henk 'm!

  • korgakos
  • Registratie: April 2008
  • Laatst online: 12-06 19:59
offtopic:
ok thx, ik heb het aangepast

[ Voor 96% gewijzigd door korgakos op 01-12-2009 13:29 ]


Acties:
  • 0 Henk 'm!

  • korgakos
  • Registratie: April 2008
  • Laatst online: 12-06 19:59
is het misschien zo dat omdat ik
CoInitialize gebruik bij het opstarten van het programma ?
Initializes the COM library on the current thread and identifies the concurrency model as single-thread apartment

Acties:
  • 0 Henk 'm!

  • pedorus
  • Registratie: Januari 2008
  • Niet online
Uit het laatste stukje code blijkt dat je de .NET BackgroundWorker en delegates nog niet helemaal snapt. Het aanroepen van de mainThread die de BackgroundWorker gebruikt moet gebeuren in de events RunWorkerCompleted en ProgressChanged, waarbij je de laatste aanroept met ReportProgress. Verder bestaat je SimpleDelegate al, dat is namelijk Action, en hoef je geen new() te gebruiken. En wat je nu doet, is eigenlijk gewoon hetzelfde als gelijk MyFunc aanroepen.

Alternatief kun je ook Invoke() gebruiken.

Vitamine D tekorten in Nederland | Dodelijk coronaforum gesloten


Acties:
  • 0 Henk 'm!

  • korgakos
  • Registratie: April 2008
  • Laatst online: 12-06 19:59
Hmm oke, nu raak ik helemaal in de war?

de RunWorkerCompleted-event treed pas op als de backgroundworker "klaar" is, maar ik wil niet in die event het importeren doen. Want dan gaat de UI weer freezen ?

Kunje misschien een voorbeeld geven, dat helpt stukken sneller, thx :)


Invoke voert de functie toch uit in de thread waar hij inzit? dus dat is handig voor Crossthread problemen, maar dat is niet wat ik nodig heb?!

[ Voor 23% gewijzigd door korgakos op 01-12-2009 15:11 ]


Acties:
  • 0 Henk 'm!

  • pedorus
  • Registratie: Januari 2008
  • Niet online
Het lijkt me toch niet zo moeilijk om een voorbeeld en/of uitleg te hebben, want dat staat gewoon in de documentatie? ;)
http://msdn.microsoft.com...del.backgroundworker.aspx

Vitamine D tekorten in Nederland | Dodelijk coronaforum gesloten


Acties:
  • 0 Henk 'm!

  • farlane
  • Registratie: Maart 2000
  • Laatst online: 16-09 22:43
CoInitialize moet sowieso in elke thread worden aangeroepen, dus in een functie initializen en daarna vanuit een andere thread een COM call doen is een no-go.

[ Voor 5% gewijzigd door farlane op 01-12-2009 15:22 ]

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


Acties:
  • 0 Henk 'm!

  • korgakos
  • Registratie: April 2008
  • Laatst online: 12-06 19:59
Volgens mij, is hier sprake van een misverstand..

Ik snap best wat je met een backgroundworker kunt doen.
Maar het lukt niet om de import functie uit de dll uit te voeren vanuit de backgroundworker als ik niet ook vanuit de backgroundworker de funcite start heb aangeroepen

De import functie schijnt alleen te werken als ik hem in de thread uitvoer waar ik de "start"-functie heb aangeroepen om het programma te starten.

Doe ik echter de import functie in de backgroundworker, dan komt er geen exception, geen error, hij loopt er vrolijk overheen..

Met de reportprogress en runworkercompleted heb ik niet veel te maken, aangezien ik die niet nodig heb hiervoor..

even vorige reactie lezen

Acties:
  • 0 Henk 'm!

  • korgakos
  • Registratie: April 2008
  • Laatst online: 12-06 19:59
farlane schreef op dinsdag 01 december 2009 @ 15:22:
CoInitialize moet sowieso in elke thread worden aangeroepen, dus in een functie initializen en daarna vanuit een andere thread een COM call doen is een no-go.
Moet ik dan een uninitialize uitvoeren in mainthread voordat ik een initialize aanroep in de backgroundworker?
Of hoe zit die sequence in elkaar?
En waar moet ik dan nog meer opletten?

-----------

Volgens mij moet ik dit gebruiken in de dll :
C++:
1
CoInitializeEx(NULL,COINIT_MULTITHREADED);

Alleen werkt het nog niet, ik laat nog van me weten:)
-------------------
Getinstance perhaps?.

[ Voor 19% gewijzigd door korgakos op 01-12-2009 15:55 ]


Acties:
  • 0 Henk 'm!

  • roy-t
  • Registratie: Oktober 2004
  • Laatst online: 08-09 11:33
korgakos schreef op dinsdag 01 december 2009 @ 11:58:
Ik heb nu via een delegate het volgende gedaan:

C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
  public void MyFunc()
        {
            PGApp_dll.library.ShowApplication(1);

        }
        delegate void SimpleDelegate();
        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            SimpleDelegate myDelegate = new SimpleDelegate(MyFunc);

            myDelegate();
            
        }

en dan via een knopje de backgroundworker laten runnen,
als ik step into doe zie ik dat de functie PGApp_dll.library.ShowApplication(1); wordt uitgevoerd maar er gebeurd niks...(het programma zou uit hidden mode moeten komen..)

Hierna lukt het ook niet meer via de UI het programma aan te sturen, dan krijg ik een exception
Je kunt niet myDelegate(); doen maar je moet:
C#:
1
form.Invoke(myDelegate); 


doen :)

~ Mijn prog blog!


Acties:
  • 0 Henk 'm!

  • pedorus
  • Registratie: Januari 2008
  • Niet online
Ehh, tsja, als de importfunctie niet door jou valt aan te passen, en zo is geschreven dat het alleen met een thread werkt, dan gaat dit nooit werken natuurlijk. In andere gevallen maakt het hele DLL-verhaal weinig uit.

Overigens vind ik het schema trouwens gek:
eigen c# programma->eigen c++ dll->com-interface(?) naar c++ applicatie in zijn eigen thread(?)
Wat staat er in die c++ dll wat niet in c# kan? Of was er al veel c++-code beschikbaar ofzo? Waar worden de threads geinitialiseerd? In welke thread(s) worden windows messages afgehandeld/staan messageloops? Wil je dat de messageloop van je eigen programma door blijft gaan, zodat de UI blijft werken, of bedoel je de UI van het third party programma?
korgakos schreef op dinsdag 01 december 2009 @ 15:32:
Volgens mij moet ik dit gebruiken in de dll :
C++:
1
CoInitializeEx(NULL,COINIT_MULTITHREADED);
Als ik het goed snap doe je nu in c++ een CoInitalize in een .NET-Thread. Dat moet niet zo, zie hier.

Vitamine D tekorten in Nederland | Dodelijk coronaforum gesloten


Acties:
  • 0 Henk 'm!

  • korgakos
  • Registratie: April 2008
  • Laatst online: 12-06 19:59
Hmm ja ik heb die c++ code genomen omdat deze al gegeven was en ik nog nooit met comobjecten heb gewerkt en weet hoe ze in elkaar zitten..
Ik had geen zin om het geheel in c++ te doen, dus deed ik het op deze manier met c#
Zoals je misschien al merkt zijn veel dingen die ik nu doe nieuw voor me, maar goed dit is mijn stageopdracht, ik heb eigenlijk al een werkend programma maar ik wil het iets netter doen.

Ik ben nu bezig om de com in c# te doen.
Tot nu toe werkt het openen en het verbergen al, blijkt best simpel te zijn!

edit:
Niet verwacht dat het omschrijven van c++ com-code naar C# zo easy ging :)!

[ Voor 7% gewijzigd door korgakos op 02-12-2009 09:27 ]


Acties:
  • 0 Henk 'm!

  • korgakos
  • Registratie: April 2008
  • Laatst online: 12-06 19:59
OKe lui, Consider dit als opgelost


Ik heb nu dus in plaats van een DLL te gebruiken (van c++) deze functies omgeschreven in C# en doe nu de COM-afhandelingen in C#.

Als iemand hetzelfde ooit nodig heeft:

http://msdn.microsoft.com/en-us/library/aa645736%28VS.71%29.aspx

Deze "tutorial" bied gewoon ALLES wat je nodig hebt..

Nu nog even de mensen bedanken voor het wijzen naar de goede richting, ik zat dus helemaal verkeerd te denken (en misschien te moeilijk)

Thx!
Pagina: 1