|
I've been trying to add a new interface to my application, and for some reason, I keep getting the following error:
C2504: IWWAlmDBAck : base class undefined
I defined a new interface in an IDL file, and IWWAlmDBAck is using IUnknown.
I declare the interface in a header file, underneath a class called CWWAlmDBPrg, declaring it as public IWWAlmDBAck.
The error is pointing to the header file, saying that the base class is undefined. However, there are old interfaces defined under CWWAlmDBPrg, and no errors generated from that. Why is it when I add a new one, the error occur?
Below is my header code:
This is where I got the error, at IWWAlmDBACK
class CWWAlmDBPrg :
public IWWAlmDBConnection,
public IWWAlmDBInfo,
public IWWAlmDBTable,
public IWWAlmDBProviderSession,
public IWWAlmDBQuery,
public IWWAlmDBDetailed,
public IWWAlmDBConsolidated,
public IWWAlmDBCause,
public IWWAlmDBComment,
public IWWAlmDBDefaultQuery,
public IWWAlmDBTagStatus,
public IWWAlmDBEvents,
public IWWAlmDBErrorInfo,
//New Interface:
public IWWAlmDBACK,
public CComObjectRoot,
public CComCoClass<cwwalmdbprg,&clsid_wwalmdbprg>
{
public:
CWWAlmDBPrg()
Below is code from my IDL:
This is where I defined the interface IWWAlmDBACK:
//New
[
object,
uuid(2D65B748-6B53-45e5-A201-74D072F39045),
helpstring("IWWAlmDBACK Interface"),
pointer_default(unique)
]
interface IWWAlmDBACK : IUnknown
{
[helpstring("method LogAlmAckConsolidated")] HRESULT LogAlmAckConsolidated([in] int AlarmId,[in,string] wchar_t* AckTime,[in] int AckTimeFracSec,[in] int AckTimeZoneOffset,[in] int AckDaylightAdjustment,[in] int OutstandingAcks,[in] int AckCommentId, [in,string] wchar_t* AckOperatorName,[in,string] wchar_t* AckNodeName, [in] double User1, [in] double User2, [in,string]wchar_t* User3, [in] long Cookie);
};
//End New
I generated the uuid using guidgen.exe
I defined the interface in coclass:
coclass WWAlmDBPrg
{
[default] interface IWWAlmDBConnection;
interface IWWAlmDBInfo;
interface IWWAlmDBTable;
interface IWWAlmDBProviderSession;
interface IWWAlmDBQuery;
interface IWWAlmDBDetailed;
interface IWWAlmDBConsolidated;
interface IWWAlmDBCause;
interface IWWAlmDBComment;
interface IWWAlmDBDefaultQuery;
interface IWWAlmDBTagStatus;
interface IWWAlmDBEvents;
interface IWWAlmDBErrorInfo;
//New
interface IWWAlmDBACK;
};
Thank you!
|
|
|
|
|
The only thing I can think of is to make sure the interface is defined before it is used (i.e., defined before CWWAlmDBPrg) and that the header is included in the source file in which its used. Also, perhaps recompiling the IDL file before building the project would help. I had a similar problem once where the IDL file wasn't getting compiled automatically during the build, and I had to manually do it before the build process.
Reminiscent of my younger years...
10 LOAD "SCISSORS"
20 RUN
|
|
|
|
|
Hi,
The IHTMLDocument2 interface has the method get_images(), which supposedly returns the images found in the document. But trough that interface I can only access the attributes concerning the images (e.g. height, width, border etc.).
So my question can I access the actual image data from somewhere. From IHTMLDocument2 or from some other related interface. I'm developing an ActiveX component which needs to alter images on pages.
"There is no reason for any individuals to have a computer in their home". Ken Olson, president and founder of Digital Equipment Corp.
|
|
|
|
|
There doesn't seem to be any way of doing this, short of hosting the WebBrowser control (or MSHTML) and handling the markup and rendering yourself, which I'm betting isn't an option.
Intead, what about displaying the image in your ActiveX control. That way, it would have exclusive control over the display of the image. MSN Photos used to have a print wizard that worked similar (they probably still do, but they went to strickly subscription-based usability so I can't use it anymore).
You could still get certain images on the page by getting their src attribute and downloading and displaying in your ActiveX. Just an alternative suggestion.
Reminiscent of my younger years...
10 LOAD "SCISSORS"
20 RUN
|
|
|
|
|
Yep, I was also thinking about, taking the src of the image and then downloading it again and so. Though it is kind of stupid to download the images two times, so I was hoping for an easier solution.
But I quess I have to live with this ... Thanx
|
|
|
|
|
You don't actually have to download it twice. Use the moniker functions like IE does like URLDownloadToCacheFile , which even gives you callback. The file is pulled from the cache based on the browser's cache settings. You can also bind an image to the URL moniker directly, which is how IE / Windows usually handles things. This, agian, should be under the control of the cache settings.
Reminiscent of my younger years...
10 LOAD "SCISSORS"
20 RUN
|
|
|
|
|
That sounds good. at least better than downloading the images twice. I'll have to try that.
Thnx again for your answer
|
|
|
|
|
i wrote a EXE server.registered the dll and exe. when i am running my client program it throws an error that required interfaces are not implemented.
the client is a standard OPC client, it only detects the IConnectionPointImpl
default interface.the other custom interfaces are not detected by the client.
what may be the cause.
cheers
satish
|
|
|
|
|
I have a query regarding component versioning.
I had a component named "Old_VC_Exe_Component" exposed as an STA, out-of proc COM server, developed in VC++. This is for our internal use and not for client.
"Old_VC_Exe_Component" is wrapped by another component "Old_VB_Dll_Component_Wrapper" which is in-proc COM server developed in VB, and this is exposed as SDK to client.
Now we are planning to provide new version of our product.
In new version, we are thinking of removing the wrapper layer. That is we want to expose "Old_VC_Exe_Component" to client (as "New_VC_Exe_Component") instead of "Old_VB_Dll_Component_Wrapper".
We can change server code at server end. And the requirement is that, client of "Old_VB_Dll_Component_Wrapper" SDK should not be required to make any change in his code, when we replace "Old_VB_Dll_Component_Wrapper" by "New_VC_Exe_Component".
Can you tell me is this possible? Or what can be the possible issues in doing this?
|
|
|
|
|
Yes, of course. Your new component should have the same CLSID (or ProgID, translated into necessary CLSID) and the same set of interfaces as the old DLL-component.
There is a "location transparency" rule in COM. Look at MSDN for more information about this.
With best wishes,
Vita
|
|
|
|
|
Thanks. I am facign following trouble:
Create a COM component "InProcVB.dll" as in-proc DLL in VB exposing some interfaces and methods .
Write its client as "clientVB".
Write another COM component as "OutOfProc.exe" as out-of-proc exe server in VC. This has same
interface/class/InterfaceIDs/ClassIDs as that of "InProcVB.dll". This is written with purpose of
replacing "InProcVB.dll". And, the expectation is that client need not re-compile. (As defined by
rule "Location transparency of COM).
After developing "OutOfProc.exe", we unregistered "InProcVB.dll", and registered "OutOfProc.exe".
Executed "clientVB" without any change. It gave error type-mismatch. The error point was:
Dim objSrvClass as SrvClass
set SrvClass = CreateObject("Server.Class") --> Problem: Type mismatch.
If I change code as
Dim objSrvClass as Object
set SrvClass = CreateObject("Server.Class")
It works well.
Please suggest.
|
|
|
|
|
I have no problem at all.
I made the VB's Server.dll, VC's Server.exe and testing Project1.exe. Tested object has one method xxx in VB server
Public Sub xxx()
MsgBox "xxx subroutine is called"
End Sub
and in VC server
STDMETHODIMP CClass::xxx()
{
MessageBox(NULL,"ATL xxx is called", "ATL", MB_OK);
return S_OK;
}
and testing code in Project1 project
Sub Main()
Dim x As Server.Class
Set x = CreateObject("Server.Class")
x.xxx
End Sub
When i register some COM server, I have relevant message: if VB, then VB, if VC, then VC. I.e.
>regsvr32 Server.dll
>Project1.exe
Having ... xxx subroutine is called
>regsvr32 /u Server.dll
>Server.exe -RegServer
>Project1.exe
Having ... ATL xxx is called
>Server.exe -UnRegServer
There is no magic. It's possible that you have a mistake. I also firstly made a mistake - I have mixed up the coclass and interface IDs. And I had "Type mismatch"
With best wishes,
Vita
|
|
|
|
|
Thanks for your efforts. Can you please send us the code of both VB and VC server and client samples that you have written?
This will help us in locating problem at our end.
Regards.
|
|
|
|
|
Just wondering if anyone has done any study into the speed of COM? In particular, a comparison of the time taken to access a COM object's methods with a locally defined object's methods.
In my application I have put all of the ADO functionality into a COM object, however, it's really slow to query the database (through the COM object) and then display the results. I am considering using a simple C++ class instead, since there is only one application accessing the database anyhow.
Any comments or ideas on this would be really helpfull.
|
|
|
|
|
You need to answer following before perfromace measurement:
What is type of your server? out-of-proc/in-proc?
What interfaces are you using? Dispatch/Dual?
What is the frequency of clietn server interaction?
|
|
|
|
|
Here are the results of the test, performed on NT4SP3, Pentium Pro 300Mhz, 128Mb RAM, and a 10Base-T network connection:
Early Bound Late Bound Cached
In Process 20 ms 90 ms 80 ms
Out of Proc 1952 ms 5137 ms 2944 ms
Remote 14952 ms 36403 ms 20089 ms
|
|
|
|
|
Thanks for your test results.
My server is a DLL with proxy/stub merged, with a dispatch interface. The server is always local and in-process. This is the fastest possible configuration, right?
The client-server interaction is fairly high frequency... i think this is my problem. For example, to populate a dialog before it is displayed, the client queries the server to Find() the appropriate record (ADO to an Access DB), then the client uses separate calls to retrieve each field (about 10 fields). The server is not doing much work here, just returning global variables that were set during the previous Find() method.
My customer requires this to run on a pre-pentium machine, 100MHz, 24Mb RAM, Win 98. Of course, on my development beast, the screen updates instantly, but the customer machine takes about 7 seconds (yuk )
Do you think it's the COM component slowing it down?
Jo
|
|
|
|
|
The solution for this is that you should club separate calls into a single call. For example:
Suppose you have a collection of 100 items, and collection's object has 4 attributes each. To display all the properties, your client is doing something like this:
For each item of collection:
{
Get object
get first prop of object
get second prop of object
get third prop of object
get fourth prop of object
}
So, you are making 5 *100 = 500 calls to COM server. Instead you should define prototype like this:
Collection->GetAllproperties([out] Variantarray)
So, single call to COM server will achieve this.
Regards.
|
|
|
|
|
As long as the threading model of the thread matches that of the component, there shouldn't be any proxy/stub work going on, and the call into the component is just a virtual function call, which isn't much more costly than a non-virtual call.
If both parts (client and component) are written in C++, or if the client is VB6, try to ensure that your component exposes a vtable interface as well as the dispatch interface - a dual interface, as it's known. This is basically a custom interface derived from IDispatch, so that callers which can early bind do so, while late-binding callers aren't shut out.
If the threading model of the component doesn't match the threading model of the caller, COM will introduce a proxy and stub to marshal between the caller and the component within the thread. This is less costly than having the component as a local server process, but more costly than a plain call.
This might happen if your component is marked 'Free' but your client is either VB6, or calls CoInitialize or CoInitializeEx( NULL, COINIT_APARTMENTTHREADED ); to initialise COM from C++. If the component is marked 'Both', it will behave as if you'd specified 'Apartment' if the thread that created it runs in the Single-Threaded Apartment (conditions as above), or 'Free' if the creator runs in the Multi-Threaded Apartment.
I suspect, though, that your database accesses are what's killing you. Measure the actual performance of Access on that system configuration. It's going to be sluggish - indeed with only 24Mb of RAM, it's likely to be constantly swapping.
Generally it's a good idea to compile your app with the 'Minimize Size' compiler options - in VB, this is Project Properties > Compile tab > select Compile to Native Code and Optimize for Small Code.
In VC 6.0, I use the /Oxs option - full optimization, favor small code - and the /Og option - global optimizations. I also use /Gy (enable function-level linking) and specify /OPT:REF to the linker (Remove unreferenced functions). This last is the default, but it gets turned off if you generate debugging information for the release build, which I do. Specifying /OPT:WIN98 might improve your startup time on Windows 98.
Doing this can reduce your code size, which can reduce the number of page faults you take.
You could also try using a profiler to find out where the hotspots are. The Win32 SDK contains a tool called the Call Attributed Profiler, or CAP.
--
Mike Dimmick
|
|
|
|
|
Thanks Mike, for such a detailed response!
I have been working through each of your points.
My COM objects and the exe use apartment threading, and a dual interface.
(All of the components are written in VC++).
The exe initialises COM with ...
struct InitOle {
InitOle() { ::CoInitialize(NULL); }
~InitOle() { ::CoUninitialize(); }
} _init_InitOle_;
And then creates the COM objects with ...
CoCreateInstance( CLSID_SubstrateMgr,
NULL,
CLSCTX_INPROC_SERVER,
IID_ISubstrateMgr,
(void **) &g_pSubstrateMgr);
Is this the fastest method?
I have used all of the optimisation settings you suggested, although I can't see any noticable difference.
I believe you are right about the database access being the trouble spot. If the COM calls aren't that much worse than a function call, I can leave my COM interfaces alone and focus on the database access.
Thanks again for your help.
Jo
|
|
|
|
|
Keep in mind that ADO is dog slow. Use OLEDB directly and you will see 2-3 times perfomance increase. Example: I created an ASP page that used ADO to return a simple recordset(SELECT TOP 50 FROM TABLE1) and loop through the recordset to generate an HTML table. Then I wrote a C++ COM object that that accessed OLEDB directly instead of ADO from my ASP page. Then I used ATL Server and my C++ COM object.
Here's what I found: 1) ASP/ADO - 70 requests/sec 2) ASP/C++ COM/OLEDB - 290 request/sec 3) ATL Server/C++ COM/OLEDB - 370 request/sec.
The problem with ADO is that everything is a VARIANT so it can be easily used by scripting clients. OLEDB is meant to be used by compiled/early bound languages.
|
|
|
|
|
I ported Mario Zucca's grid control to WinCE using eVC++ 3.0 compiler, but making it a Full Control to that it can be easily used in c++ MFC programs like any other ActiveX control. All that went without very many problems -- except being able to fire events. So I just copied the code to do that into my project and it seemed to work.
Then I created a test C++ MFC Dialog-based program, added the control and using ClassWizzard created the events that were exposed and explained above. That too seemed to work. However, When the control attempts to fire the event, it cannot because it doesn't realize that it has any client containers!
For example: m_vec.GetSize(); always returns 0. Does anyone know how to fix this problem?
<br />
HRESULT Fire_BeforeEdit(INT Row, INT Col, VARIANT_BOOL * Cancel)<br />
{<br />
CComVariant varResult = VT_EMPTY;<br />
T* pT = static_cast<T*>(this);<br />
int nConnectionIndex;<br />
CComVariant* pvars = new CComVariant[3];<br />
<br />
int nConnections = m_vec.GetSize();<br />
<br />
<br />
for (nConnectionIndex = 0; nConnectionIndex < nConnections; nConnectionIndex++)<br />
{<br />
pT->Lock();<br />
|
|
|
|
|
Hello!
Can I access COM object from java?
Thanks
|
|
|
|
|
EZ JCom lets you call COM objects from Java. Check http://www.ezjcom.com/
|
|
|
|
|
I would like to create a COM object with all my ADO methods. I then would like to have Visual Basic pass a recordset pointer to my COM DLL. Is this possible? If so how would I go about it?
Thanks
|
|
|
|
|