You are not logged in. You can browse in the PowerBASIC Community, but you must click Login (top right) before you can post. If this is your first visit, check out the FAQ or Sign Up.
Announcement
Collapse
No announcement yet.
VB Multi-Threaded COM Component Example in the Source Code Forum
Because it has to be done to use COM and it costs (almost) nothing to 'do it again.' (I think the compiler does it automatically whether you want/need it or not.)
What I don't know is if the compiler automatically does it on new threads of execution.. and it must be done on each thread in which COM calls are used.......
CoInitializeEx must be called at least once, and is usually called only once, for each thread that uses the COM library. Multiple calls to CoInitializeEx by the same thread are allowed as long as they pass the same concurrency flag, but subsequent valid calls return S_FALSE. To close the COM library gracefully on a thread, each successful call to CoInitialize or CoInitializeEx, including any call that returns S_FALSE, must be balanced by a corresponding call to CoUninitialize.
But the compiler handles a lot of these messy details, so even this documentation may not apply in all cases.
So far this thing works pretty well, the only issue I have is that the call from the window back into an "Event Marshaler" (IE. Doit()) I do not like. Is there anyway for me to call into a hidden method?
Sr. Software Development Engineer and Sr. Information Security Analyst,
CEH, Digital Forensic Examiner
ok this is what I have done (and trying NOT get aggravated (but obviously I am a wee bit) so maybe you guys can show me where I went wrong.
Compile the example
Register the DLL
Add a Reference to the DLL
(Note the below only works if the TLB that is created is included in your resource file from what I find)
From there is should be
Declare a variable to be my object to the DLL
Set the variable as a new object (Intellisence does not work, so I am hunting and pecking here, although I can see it in the toolbox window as to classes and variables that are shown)
Now you see why I can not get things working...its the 1st initial things that make the later not work
Engineer's Motto: If it aint broke take it apart and fix it
"If at 1st you don't succeed... call it version 1.0"
"Half of Programming is coding"....."The other 90% is DEBUGGING"
"Document my code????" .... "WHYYY??? do you think they call it CODE? "
Now that I am back on programming with objects, the error I get is that VB has encountered a problem and must close, and an invalid memory location error.
This happens both with the exe compiled and in the IDE.
I did some deeper digging about the CoInitializeEx which lead me to finding that rather than the hardcoded 0 the function is defined as
Code:
DECLARE FUNCTION CoInitializeEx LIB "ole32.dll" ALIAS "CoInitializeEx" (pvReserved AS ANY, BYVAL dwCoInit AS DWORD) AS LONG
Where MSDN says pvReserved must be NULL
and dwCoInit is described as
dwCoInit
[in] Flags specifying the concurrency model and initialization options for the thread. Values for this parameter are taken from the COINIT enumeration. Any combination of values from the COINIT enumeration can be used, except that the COINIT_APARTMENTTHREADED and COINIT_MULTITHREADED flags cannot both be set.
Then in the Win32Api.inc I found the values for COINIT are
Code:
' COM initialization flags; passed to CoInitialize. COINIT enum.
%COINIT_APARTMENTTHREADED = &H2 ' Apartment model
#IF %DEF(%WIN32_DCOM) ' DCOM
%COINIT_MULTITHREADED = &H0 ' OLE calls objects on any thread.
%COINIT_DISABLE_OLE1DDE = &H4 ' Don't use DDE for Ole1 support.
%COINIT_SPEED_OVER_MEMORY = &H8 ' Trade memory for speed.
' Flags for Synchronization API and Classes. COWAIT_FLAGS enum.
%COWAIT_WAITALL = 1
%COWAIT_ALERTABLE = 2
#ENDIF ' DCOM
But I can not find where %WIN32_DCOM is defined, nor what its value should be??? so that I can use %COINIT_MULTITHREADED, but also causes a conflict in my eyes that you can not have %COINIT_APARTMENTTHREADED and %COINIT_MULTITHREADED
So I am TOTALLY lost and no idea how figure out what the problem is until I can find documentation as to definitions and what they do????
Last edited by Cliff Nichols; 28 Oct 2008, 10:39 AM.
Reason: code mistake
Engineer's Motto: If it aint broke take it apart and fix it
"If at 1st you don't succeed... call it version 1.0"
"Half of Programming is coding"....."The other 90% is DEBUGGING"
"Document my code????" .... "WHYYY??? do you think they call it CODE? "
Thanx Jose,
At least that explains some of the difficulty.
One thing I am finding is if I comment out the CoUnInitialize then no crash (until closing of course), but with the CoUnInitialize, thats when I crash?
The docs say each CoInitializeEx MUST be paired with a CoUnInitialize....so I am confused why this is where I get the crash? (I even threw my errorhandler.inc at it to try and log the error, but too late, its crashed anyways)
Has anyone gotten it to work? I have even tried to do the same thing but no threads and my own code gets the same problem.
Engineer's Motto: If it aint broke take it apart and fix it
"If at 1st you don't succeed... call it version 1.0"
"Half of Programming is coding"....."The other 90% is DEBUGGING"
"Document my code????" .... "WHYYY??? do you think they call it CODE? "
Scratch that....digging deeper I find that CoInitializeEx is coming back with an error of an invalid parameter (no matter what I send to it??)
Code:
LOCAL Result AS LONG
LOCAL lResult AS LONG
LOCAL lReserved AS LONG
LOCAL ErrorBuff AS ASCIIZ * %MAX_PATH
lResult = CoinitializeEx( lReserved, %COINIT_APARTMENTTHREADED) '<--- Returns Invalid Parameter Error
' lResult = GetLastError '<--- Returns no error
FormatMessage %FORMAT_MESSAGE_FROM_SYSTEM, BYVAL %NULL, lResult, %NULL, ErrorBuff, SIZEOF(ErrorBuff), BYVAL %NULL 'Format the message
MSGBOX STR$(lResult) + $CR + ErrorBuff
Engineer's Motto: If it aint broke take it apart and fix it
"If at 1st you don't succeed... call it version 1.0"
"Half of Programming is coding"....."The other 90% is DEBUGGING"
"Document my code????" .... "WHYYY??? do you think they call it CODE? "
Being a COM DLL, PB does the calls to CoInitialize and CoUninitialize under the hood, so further calls to CoInitialize or CoInitializeEx will fail. If you want to call CoInitializeEx, you will need to call CoUninitialize first, but I wonder why you want to do this.
Ok I took a step back because I just could not figure things out.
From the help files the example shows
ComServer
Code:
#COMPILE DLL "ComServer.dll"
#COM TLIB ON
#RESOURCE "ComServer.pbr" 'Include TLB in resource
#INCLUDE "Win32API.inc"
$EvIFaceGuid = GUID$("{00000098-0000-0000-0000-000000000002}")
$MyClassGuid = GUID$("{00000098-0000-0000-0000-000000000003}")
$MyIFaceGuid = GUID$("{00000098-0000-0000-0000-000000000004}")
INTERFACE STATUS $EvIFaceGuid AS EVENT
INHERIT IUNKNOWN
METHOD Done
END INTERFACE
CLASS MyClass $MyClassGuid AS COM
INTERFACE MyMath $MyIFaceGuid
INHERIT IUNKNOWN
' inherit Dual
' INHERIT Dispatch
METHOD DoMath '<1>
MSGBOX "Calculating..." ' Do some math calculations here
RAISEEVENT Status.Done()
END METHOD
END INTERFACE
EVENT SOURCE STATUS
END CLASS
ComServer.rc
Code:
#include "resource.h" //<--- Typical Resource Call
1 typelib "ComServer.tlb" //<--- Unsure about this yet, but researching
PB ComClient
Code:
#COMPILE EXE "ComClient.exe"
$EvClassGuid = GUID$("{00000098-0000-0000-0000-000000000001}")
$EvIFaceGuid = GUID$("{00000098-0000-0000-0000-000000000002}")
$MyIFaceGuid = GUID$("{00000098-0000-0000-0000-000000000004}")
CLASS EvClass $EvClassGuid AS EVENT
INTERFACE STATUS $EvIFaceGuid AS EVENT
INHERIT IUNKNOWN
METHOD Done
MSGBOX "Done!"
END METHOD
END INTERFACE
END CLASS
INTERFACE MyMath $MyIFaceGuid
INHERIT IUNKNOWN
METHOD DoMath
END INTERFACE
FUNCTION PBMAIN()
DIM oMath AS MyMath
DIM oStatus AS STATUS
LET oMath = NEWCOM "MyClass"
LET oStatus = CLASS "EvClass"
EVENTS FROM oMath CALL oStatus
oMath.DoMath
EVENTS END oStatus
END FUNCTION
Which works fine
VB ComClient
Code:
Dim WithEvents MyEvent As MyClass
Dim MyClass As MyClass
Private Sub Command1_Click()
MyClass.DOMATH
End Sub
Private Sub Form_Load()
Set MyClass = CreateObject("MyClass")
End Sub
Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)
Set MyClass = Nothing
End Sub
Private Sub MyEvent_DONE()
MsgBox "Hello"
End Sub
Which does not work.
To replicate the VB side you will need to do the following
Have VB to test with
Place a copy of ComServer.dll in your VB Project folder
Register the ComServer.dll using Regsvr32
Add a reference to the ComServer.dll in the VB IDE
Save the project and close the IDE
Open the project again from Windows Explorer (This is so the IDE does not think the current folder is the M$ default)
Run the project
You will see the messagebox from PB, but will never see the messagebox from VB from the event that is supposed to fire, but does not.
I have no clue what to do to get the event to fire????
Engineer's Motto: If it aint broke take it apart and fix it
"If at 1st you don't succeed... call it version 1.0"
"Half of Programming is coding"....."The other 90% is DEBUGGING"
"Document my code????" .... "WHYYY??? do you think they call it CODE? "
And why do you use INHERIT IUNKNOWN instead of INHERIT IDISPATCH, both in the events class and MyClass class, if VB uses Automation, not direct interface calls?
I FINALLLLY found an avenue I can persue. but like Jose pointed out
Being a COM DLL, PB does the calls to CoInitialize and CoUninitialize under the hood, so further calls to CoInitialize or CoInitializeEx will fail. If you want to call CoInitializeEx, you will need to call CoUninitialize first
In this case (at least at first) it would have been better if they did not, then I would be forced to do it myself (but I see why it was done this way)
Is there a way to get the reference count as to matched pairs of CoInitialize and CoUnInitialize? or even unmatched count of what the computer says is open number of the reference count?
I am sooooo close that I can taste it....but just stumped by another M$ wall because I figured out how to defeat the last troll at the last M$ wall just to go 5 feet and see a new wall built
Engineer's Motto: If it aint broke take it apart and fix it
"If at 1st you don't succeed... call it version 1.0"
"Half of Programming is coding"....."The other 90% is DEBUGGING"
"Document my code????" .... "WHYYY??? do you think they call it CODE? "
We process personal data about users of our site, through the use of cookies and other technologies, to deliver our services, and to analyze site activity. For additional details, refer to our Privacy Policy.
By clicking "I AGREE" below, you agree to our Privacy Policy and our personal data processing and cookie practices as described therein. You also acknowledge that this forum may be hosted outside your country and you consent to the collection, storage, and processing of your data in the country where this forum is hosted.
Comment