|
freehawk wrote:
tell me what difference is between a function and a callback function translated
to dll as a function pointer?
There is no difference really. Callback is just a semantic label for programmers.
--
Try walking in my shoes. You stumble in my footsteps.
|
|
|
|
|
Thank you for the reply.
I did it.
-Freehawk
|
|
|
|
|
I need to allocate and fill a large block of bytes in an ATL object, then pass that memory back to the client, which can delete it when it wants to.
i tried this:
<br />
[id(3), helpstring("method MFIGetFrame")] HRESULT MFIGetFrame([in] ULONG FrameIdx, [out] unsigned char **FrameArray, [out,retval] ULONG* Retval);<br />
but the COleDispatchDriver wrapper returns DISP_E_BADVARTYPE, because it doesn't know what to do with the "unsigned char **" .
i've tried using:
[id(3), helpstring("method MFIGetFrame")] HRESULT MFIGetFrame([in] ULONG FrameIdx, [out] SAFEARRAY(unsigned char)*FrameArray, [out,retval] ULONG* Retval);<br />
but the compiler keeps giving me: "error C2061: syntax error : identifier 'tagSAFEARRAY'".
i'm using VS.Net, which seems to make everything twice as hard as it needs to be.
any ideas?
ClickPic | ImgSource | CheeseWeasle
|
|
|
|
|
First, if you are returning an array in COM/IDL, you need to make it "conformant". You do that by indicating the number of elements in your array. I.e.:
HRESULT MFIGetFrame([in] ULONG FrameIdx, [out] ULONG* ArraySize, [out, size_is(1, *ArraySize)] unsigned char** FrameArray, [out, retval] ULONG* Retval)
At least that's what Essential IDL by Martin Gudgin told me last night.
As for the SAFEARRAY business, have you tried importing oaidl.idl? import "oaidl.idl"; It should be imported by default if I'm not mistaken though.
--
Try walking in my shoes. You stumble in my footsteps.
|
|
|
|
|
Jörgen Sigvardsson wrote:
have you tried importing oaidl.idl? import "oaidl.idl";
i tried that. but the error is actually happening in the "__interface" section of the ATL object's .H header (not in the IDL). apparently VC7 puts the IDL stuff right in the .H file, instead of an external IDL... ?
and, i can't figure out how to do an import in that __interface section.
ClickPic | ImgSource | CheeseWeasle
|
|
|
|
|
Just out of curiosity.. if you are calling the object using COleDispatchDriver, why not call using the vtable instead? Or is the interface a pure dispinterface, and you cannot in any way make the interface dual?
--
Try walking in my shoes. You stumble in my footsteps.
|
|
|
|
|
Jörgen Sigvardsson wrote:
why not call using the vtable instead?
never done that before. i've always used COleDispatchDriver (and the project i'm doing this for is designed to use them).
i'm about to scrap the whole COM/ATL thing and just go back to plain old C-interfaced DLLs. ATL is far more trouble than it's worth.
ClickPic | ImgSource | CheeseWeasle
|
|
|
|
|
Hello Chris,
Don't give up yet, Chris .
>> ... i've always used COleDispatchDriver
Looks like your COM Server is meant to be IDispatch-based or dual interfaced. I did some experiments based on your sample code and came up with the following :
interface IMFIObject : IDispatch
{
[id(1), helpstring("method MFIGetFrame")] HRESULT MFIGetFrame([in] long FrameIdx, [out] VARIANT *pFrameArray, [out,retval] long* Retval);
};
In essence, I changed your second parameter from :
[out] unsigned char **FrameArray
and
[out] SAFEARRAY(unsigned char)*FrameArray
to :
[out] VARIANT *pFrameArray
This is how I implemented the method :
STDMETHODIMP CMFIObject::MFIGetFrame(long FrameIdx, VARIANT *pFrameArray, long *Retval)
{
// TODO: Add your implementation code here
LPBYTE lpbyToReturn = NULL;
SAFEARRAY* lpSafeArrayOfBytes = NULL;
lpbyToReturn = (LPBYTE)malloc(1024);
memset (lpbyToReturn, 'B', 1024);
// Wrap up lpbyToReturn in a SAFEARRAY.
CreateSafeArrayFromBytes
(
(LPBYTE)lpbyToReturn,
(ULONG)1024,
(SAFEARRAY**)&lpSafeArrayOfBytes
);
if (lpSafeArrayOfBytes)
{
// Note well that this function should always return a
// pointer to what is logically returned.
V_VT(pFrameArray) = VT_ARRAY | VT_UI1;
V_ARRAY(pFrameArray) = lpSafeArrayOfBytes;
}
if (lpbyToReturn)
{
free (lpbyToReturn);
lpbyToReturn = NULL;
}
*Retval = 1024;
return S_OK;
}
Here is a summary of what happens in the function :
1. I allocate an array of 1024 bytes and point to it via "lpbyToReturn". The number 1024 is not important. I simply wanted to "allocate and fill a large block of bytes in an ATL object" which is also what you wanted to achieve.
2. I then set all bytes in the array to the letter 'B'. This is done for verification purposes only.
3. I then create a SAFEARRAY and copy the data from the "lpbyToReturn" array to the SAFEARRAY.
4. I then take the second parameter "pFrameArray", which is a pointer to a VARIANT, and make it a valid VARIANT which holds a SAFEARRAY of BYTEs and make the VARIANT point to the newly created SAFEARRAY.
5. Note that I will now need to free the memory of the original array "lpbyToReturn". This is because the SAFEARRAY already contains the same BYTE values in "lpbyToReturn" .
6. Note that I do not free the SAFEARRAY because this is the memory block that is passed back to the client and the client is free to delete it whenever it wants to.
By the way, Chris, I've also supplied the source codes to CreateSafeArrayFromBytes() :
long CMFIObject::CreateSafeArrayFromBytes
(
LPBYTE lpbyBytes,
ULONG ulSize,
SAFEARRAY** ppSafeArrayReceiver
)
{
HRESULT hrRetTemp = S_OK;
SAFEARRAY* pSAFEARRAYRet = NULL;
SAFEARRAYBOUND rgsabound[1];
ULONG ulIndex = 0;
long lRet = 0;
// Initialise receiver.
if (ppSafeArrayReceiver)
{
*ppSafeArrayReceiver = NULL;
}
if (lpbyBytes)
{
rgsabound[0].lLbound = 0;
rgsabound[0].cElements = ulSize;
pSAFEARRAYRet = (SAFEARRAY*)SafeArrayCreate
(
(VARTYPE)VT_UI1,
(unsigned int)1,
(SAFEARRAYBOUND*)rgsabound
);
}
for (ulIndex = 0; ulIndex < ulSize; ulIndex++)
{
long lIndexVector[1];
lIndexVector[0] = ulIndex;
SafeArrayPutElement
(
(SAFEARRAY*)pSAFEARRAYRet,
(long*)lIndexVector,
(void*)(&(lpbyBytes[ulIndex]))
);
}
if (pSAFEARRAYRet)
{
*ppSafeArrayReceiver = pSAFEARRAYRet;
}
return lRet;
}
Now, over to client code. I made sure that my client code will also use the COleDispatchDriver class :
void CVCTestDlg::OnBnClickedButtonGetdynamicarrayfromobject()
{
// TODO: Add your control notification handler code here
IDispatch* pIDispatch = NULL;
COleDispatchDriver ole_disp_driver;
SAFEARRAY* pSafeArrayOfBytes = NULL;
m_spIMFIObject -> QueryInterface (IID_IDispatch, (void**)&pIDispatch);
if (pIDispatch)
{
long lRet = 0;
long lRet2 = 0;
BYTE byParamInfo[2 * 2 + 1];
VARIANTARG pVar;
VariantInit(&pVar);
VariantClear(&pVar);
ole_disp_driver.AttachDispatch(pIDispatch, FALSE);
sprintf ((LPTSTR)byParamInfo, TEXT("%s%s"), VTS_I4, VTS_PVARIANT);
ole_disp_driver.InvokeHelper(0x01, DISPATCH_METHOD, VT_I4, (void*)&lRet, byParamInfo, 1, &pVar);
pIDispatch -> Release();
pIDispatch = NULL;
pSafeArrayOfBytes = pVar.parray;
}
if (pSafeArrayOfBytes)
{
SafeArrayDestroy (pSafeArrayOfBytes);
pSafeArrayOfBytes = NULL;
}
return;
}
Notice that I defined a pointer to a SAFEARRAY object "pSafeArrayOfBytes" which will be filled by the MFIGetFrame() method which is of ordinal 0x01 in my example.
At the end of the function, I will actually delete the SAFEARRAY :
if (pSafeArrayOfBytes)
{
SafeArrayDestroy (pSafeArrayOfBytes);
pSafeArrayOfBytes = NULL;
}
I hope that the above code will be useful to you. Email me if you should want the full scource codes to the above sample. My email address is :
bllim@singnet.com.sg
Best Regards,
Bio.
|
|
|
|
|
|
Hello Chris,
You're most welcome, Chris. I strongly believe that what you are trying to accomplish -is- achievable. Just remember to use OLE-Automation-compatible types for the parameters in your interface methods. Where all else fails, VARIANTs usually help.
Contact me again if you need further clarifications, Chris.
Best Regards,
Bio.
|
|
|
|
|
Hello,
I have a problem compiling a project using the MinDependency option.
It gives me all kind of linke errors like these
<br />
Linking...<br />
LIBCMT.lib(crt0dat.obj) : error LNK2005: __osplatform already defined in atlmincrt.lib(atlinit.obj)<br />
LIBCMT.lib(crt0dat.obj) : warning LNK4006: __osplatform already defined in atlmincrt.lib(atlinit.obj); second definition ignored<br />
Creating library .\ReleaseMinDependency/myproj.lib and object .\ReleaseMinDependency/myproj.exp<br />
LIBCMT.lib(crt0.obj) : error LNK2019: unresolved external symbol _main referenced in function _mainCRTStartup<br />
.\ReleaseMinDependency/myproj.dll : fatal error LNK1120: 1 unresolved externals<br />
Now, if I understand it correctly, this is because _ATL_MIN_CRT is defined.
I goto the project properties, set 'Minimize CRT usage in ATL' to No and 'Use of ATL' to Statically linked.
When I cross check with C/C++ Preprocessor I see _ATL_MIN_CRT is gone from the Inherited Values in the 'Preprocessor Definitions' property.
Now, when I compile and when the linkstep failed, I check the build.log and surprisingly I see the /D "_ATL_MIN_CRT" flag.
Did I do something wrong? Do other options (/GX) flag automatically add it to the cl.exe parameters?
Even when I check the C/C++ commandline in the project preoperties tab, it is not there.
Any clue?
Thanks
Wim
|
|
|
|
|
I'm trying to develop a WTL helper class, that does handle some extra messages, like this:
template <class BASE>
class CInplaceCtrl : public BASE
{
BEGIN_MSG_MAP(CInPlaceCtrl<BASE>)
MESSAGE_HANDLER(WM_KEYDOWN, OnInplaceEditKeydown)
MESSAGE_HANDLER(WM_KILLFOCUS, OnInPlaceEditKillfocus)
CHAIN_MSG_MAP(BASE)
END_MSG_MAP()
};
An instance is created as
CInplaceCtrl<CEdit> m_edInplace;
m_edInplace.Create( , rect, ....);
The edit is created ok, but the message map seems not to be processed at all.
What to do?
Flirt harder, I'm a coder.
mlog || Agile Programming | doxygen
|
|
|
|
|
Try using DECLARE_WND_SUPERCLASS(_T("Your new class name"), _T("BASE class name")) and derive from CWindowImpl<CInplaceCtrl, BASE>.
That works when overriding the behaviour of system classes such as buttons, list views etc. Dunno if it works on a CWindowImpl-based class. I see no direct reasons it shouldn't though.
Also, remember that you're getting the first go at all events. If you intend to pass the event to the base class, either set the fourth argument (BOOL&) to FALSE, or call DefWindowProc() to let the base message map dispatch the event.
--
<british-accent>Pass the jam, would you?
|
|
|
|
|
Thanks!
Works seemingly perfect without the DECLARE_WND_SUPERCLASS
really necessary?
Flirt harder, I'm a coder.
mlog || Agile Programming | doxygen
|
|
|
|
|
Ah. No I guess not. I think I've mixed some concepts up. I need to redo all this some day.
--
<british-accent>Pass the jam, would you?
|
|
|
|
|
Has anyone used this successfully? I need to do something so simple it's pathetic, but I haven't figured out HOW... Here's what I want to do:
I'd like to have a webpage that loads my dll (it's in a cab and all that)... And it's being called like this:
<object classid="clsid:XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX" codebase="XXXXXX.CAB">
<param name="text" value="Yo man!">
</object>
So here's the deal... All I want said application to do... Is to be able to get that text in the param tag!!! Any hints/code snippets in the right direction? I've been having a bugger of a time, and Microsoft's help pages are of NO help for a newb like me!
I know it's probably something easy, but I can't get it to work! Thanks in advance!
|
|
|
|
|
The problem is that the simple stuff doesn't work with BSTRs
In DevStudio6, If my ATL control had the interface ITestControl & the class name CTestControl , I would do the following...
* Inherit from IPersistPropertyBagImpl
* add COM_INTERFACE_ENTRY(IPersistPropertyBag) to BEGIN_COM_MAP(CTestControl)
* Add a member variable that will store the "Yo man!", maybe CComBSTR m_bsText;
* In workspace view, right click on ITestControl, and select "Add Property"
- Set the property type to BSTR,
- the name to "test",
- uncheck "Get Function"
- leave "Put Function" enabled
- Remember the "id(n)" number displayed in the implementation preview at the bottom of the dialog, you'll need that. It's the dispatch ID
* In your header file, look for BEGIN_PROP_MAP(CTestControl)
- Add the entry PROP_DATA_ENTRY("test",1,CLSID_NULL) . Observe that the number (in this case 1) is THE SAME dispatch ID for the property you just added!
* Modify the newly created "CTestControl::put_test(BSTR newVal) " to assign newVal to the local variable m_bsText .
Now when your control loads, IPersistPropertyBagImpl will call CTestControl::put_test(BSTR newVal) and store the value "Yo man!" in m_bsText
|
|
|
|
|
Wow, thanks SO much. That totally answers my question. I'll give it a try and see what happens. Thanks again, Jason!
|
|
|
|
|
Well, I gave that a try... The only thing is this...
I had to add these two parts in:
(110) BEGIN_COM_MAP(CIEBand)
(111) COM_INTERFACE_ENTRY(IPersistPropertyBag)
(112) END_COM_MAP()
(113)
(114) BEGIN_PROP_MAP(CIEBand)
(115) PROP_DATA_ENTRY("text",1,CLSID_NULL)
(116) END_PROP_MAP()
I didn't have the com or prop maps in there before...
When I went to compile, it crapped out on the PROP_DATA_ENTRY line, with the following error(s):
IEBand.h(115) : error C2059: syntax error : 'constant'
IEBand.h(115) : error C2059: syntax error : ','
IEBand.h(116) : error C2143: syntax error : missing ';' before '{'
IEBand.h(116) : error C2447: '{' : missing function header (old-style formal list?)
IEBand.h(116) : error C2059: syntax error : '}'
IEBand.h(116) : error C2059: syntax error : 'return'
IEBand.h(116) : error C2059: syntax error : '}'
YOUCH! :P Any thoughts on this?
|
|
|
|
|
Whoops!
PROP_ENTRY("test", 1, CLSID_NULL)
Did I mention that individual milage may vary?
|
|
|
|
|
Heheheh. Yeah, figured that out JUST a second ago. :P Thanks a ton, buddy.
|
|
|
|
|
Hi
I’ve got an ATL control (ActiveX) which currently exposes a property page that is used to manipulate all the properties in the control (This property page is launched in the usual manner by the user activating the ‘Custom Properties’ item in the container).
However, instead of displaying a property page to manipulate my control, I need to execute an arbitrary piece of code that displays a custom built editor dialog. My problem is that I cannot find out how to execute an arbitrary piece of code in response to the user clicking the “(custom)”
button on the control container’s property pane (or a similarly easy method of the user activating the editor).
One approach that I have considered is to create and show the dialog from the property page’s InitDialog handler, then destroy the property sheet after the custom dialog has exited (The problem here is knowing how to close the entire property sheet and not just the page) - I'm sure there must be other approaches to this problem though.
Thanks
|
|
|
|
|
I want to call a atl component from vbscript dynamically how can i do it please explain it briefly or give me some articles links
ThanX in advance
Inam
|
|
|
|
|
Your ATL component must expose a dispinterface or dual interface.
--
C'est normal!
|
|
|
|
|
How do you Sign an ActiveX Control?
Where Can i get the Certificate required?
C makes it easy to shoot yourself in the foot; C++ makes it harder, but when you do, it blows away your whole leg
|
|
|
|
|