|
OK I have the answer to my previous post : it was option 2 (so stupid).
When receiving the mails from Codeproject in Outlook, i see 'Steve S' as the sender.
So I innocently sent my reply (with the attached file) back to the sender; it's
only now that I realize the sender was 'forums@codeproject.com' ... (i must say for my defense it's the first time i made a post on CodeProject).
Anyway... Steve, if you're still on the subject, here are the occurences of
GetAttributes that i find in acad.tlh :
struct __declspec(uuid("2928d4a2-ca93-11d1-b60f-0060b087e235"))
IAcadBlockReference : IAcadEntity
{
...
// Wrapper methods for error-handling
...
_variant_t GetAttributes ( );
...
// Raw methods provided by interface
...
virtual HRESULT __stdcall raw_GetAttributes (VARIANT * pAttrObjs ) = 0;
...
}
// Function implementation mapping
#pragma start_map_region("d:\polar32JPG\spacad\debug\acad.tli")
{
// Wrapper methods for error-handling
...
__declspec(implementation_key(1096)) _variant_t IAcadBlockReference::GetAttributes ( );
...
}
JPG
|
|
|
|
|
and, persevering in my 'monologue' (chat with myself),
here are the occurences of IAcadBlockReference (the object i'm trying to get of the array returned by GetAttributes() ) :
namespace AutoCAD {
...
struct __declspec(uuid("2928d4a2-ca93-11d1-b60f-0060b087e235"))
/* dual interface */ IAcadBlockReference;
...
}
// Smart pointer typedef declarations
_COM_SMARTPTR_TYPEDEF(IAcadBlockReference, __uuidof(IAcadBlockReference));
struct __declspec(uuid("2928d4a2-ca93-11d1-b60f-0060b087e235"))
IAcadBlockReference : IAcadEntity
{
...
...
}
struct __declspec(uuid("2928d4a3-ca93-11d1-b60f-0060b087e235"))
AcadBlockReference;
// [ default ] interface IAcadBlockReference
// [ default, source ] interface IAcadObjectEvents
|
|
|
|
|
(Fx: Wakes up, staring at screen thinking - I must try and work fewer hours this week...)
Your GetAttributes is returning a _variant_t. This is probably a safearray, so you need to check the vt member to determine the type.
if (vt == (VT_ARRAY|VT_UNKNOWN)) || vt == (VT_ARRAY|VT_DISPATCH))
This would mean it's a SAFEARRAY of either IUnknown or IDispatch values.
It's not clear from the context what the bounds of the array are, but there are functions to tell you (see SafeArrayGetDim), but chances are it's single dimension, so you can use SafeArrayGetUBound(1) and SafeArrayGetLBound(1) to find the max and min elements in it.
Then you should be able to use SafeArrayGetElement to get a copy of the interface. Don't forget that you pass the address of an index variable to SafeArrayGetElement, not the index itself.
If you want to iterate over the attributes, then SafeArrayAccessData and SafeArrayUnaccessData around a loop will be more efficient, but that deals with a pointer to the data, and you're responsible for doing your own copying.
The call can't directly return the interface you would expect, unless it's IUnknown or IDispatch, in which case it's either the punkVal (IUnknown) or pdispVal (IDispatch). Since they both support QueryInterface, it's no problem to use either of them the get the interface you actually want, but you absolutely must do that, rather than a simple assignment/cast.
It's probable that the pointer isn't pointing to an appropriate v-table anyway.
It's possible that GetAttributes() might return VT_ARRAY|VT_VARIANT, in which case you then have an extra step involved in examining the variant you get back.
Hope this helps
(and no, I wasn't offended by your email - sometimes work just gets in the way of things, like those stupid people who write viruses and worms...)
Steve S
|
|
|
|
|
In fact i have no problem with GetAttributes : i know it returns a valid safearray
(variant type = VT_ARRAY|VT_DISPATCH); SafeArrayGetLBound & SafeArrayGetUBound return
correct values.
The problem is extracting a IAcadAttributeReference * from that array :
if i try to extract a variant from the array (presuming that the IAcadAttributeReference * is a member of the variant) :
_variant_t val; // i tried also with _variant_t *val
result = SafeArrayGetElement(arrayAttrib.parray, &i, &val); // result = S_OK
switch(val.vt)
{
case VT_BYREF|VT_UNKNOWN: ...
break;
case VT_BYREF|VT_DISPATCH: ...
break;
case VT_UNKNOWN: ...
break;
case VT_DISPATCH: ...
break;
case VT_ARRAY: ...
break;
}
val.vt does not correspond to any case of the switch
and most members of val are clearly invalid (0xccccccc)
-------------------
i understand you have others things to do than finding solutions to other people
problems; what you have already done is very kind, so if you don't see an evident
solution, don't mind. Thanks.
|
|
|
|
|
Ah hah!
You're trying to retrieve into a variant. What you should do is retrieve into an IDispatch, because that's what's in the array.
CComPtr<idispatch> myDisp;
result = SafeArrayGetElement(arrayAttrib.parray, &i, &myDisp);
// Should give S_OK
CComQIPtr<iacadattributereference, &iid_iacadattributereference=""> myAttrib;
try
{
myAttrib = myDisp;
}
catch(_com_error& e)
{
result = E_NOINTERFACE;
}
catch(...)
{
result = E_FAIL;
}
if (result==S_OK)
{
// do your thing here...
}
Since the CComPtr and CComQIPtr are smart, they'll release when they go out of scope. SafeArrayGetElement will give you a copy of the element, and in this context means it will be a reference counted interface which you must release, CComPtr will do that bit for you.
You might need to modify your #import to generate the named guids for interfaces etc.
Hope this helps.
[Sorry if I seemed grouchy, I'm having a bad day...]
Steve S
|
|
|
|
|
Curse that HTML!
It should, of course, read...
CComPtr <myDisp>;
result = SafeArrayGetElement(arrayAttrib.parray, &i, &myDisp);
// Should give S_OK
CComQIPtr <myAttrib,&IID_AcadAttributeReference>;
try
{
myAttrib = myDisp;
}
catch(_com_error& e)
{
result = E_NOINTERFACE;
}
catch(...)
{
result = E_FAIL;
}
if (result==S_OK)
{
// do your thing here...
}
Steve S
|
|
|
|
|
there is progress, but ...
CComPtr<iacadattributereference> myDisp;
CComQIPtr<iacadattributereference ,&__uuidof(iacadattributereference)=""> myAttrib;
result = SafeArrayGetElement(arrayAttrib.parray, &i, &myDisp); // --> S_OK
try
{
myAttrib = myDisp;
if (result == S_OK)
myAttrib->GetColor(); //--> "access violation" in oleaut32.dll
...
What is strange is that, when looking inside myAttrib, it has type IAcadEntity,
and not IAcadAttributeReference; IAcadAttributeReference is derived from IAcadEntity.
GetColor() is a method of IAcadAttributeReference, and it did "access violation" in oleaut32.dll (the catch(_com_error& e) didn't catch anything).
If I try myAttrib->GetHeight(), where GetHeight() is a method of IAcadEntity, the
message is
"The value of ESP was not properly saved across a function call.
This is usually a result of calling a function declared with one
calling convention with a function pointer declared with a different
calling convention."
I don't know if it can give you some light : GetHeight() is :
inline double AutoCAD::IAcadAttributeReference::GetHeight ( )
{
double _result;
HRESULT _hr = get_Height(&_result);
if (FAILED(_hr)) _com_issue_errorex(_hr, this, __uuidof(this));
return _result;
}
and
struct __declspec(uuid("2928d4a0-ca93-11d1-b60f-0060b087e235"))
IAcadAttributeReference : IAcadEntity
{
...
virtual HRESULT __stdcall get_Height (double * Height ) = 0;
}
-------
My boss, who is a lot more aware of COM than me (but that's easy), has no clue.
So it's up to you, you grouchy
JPG
|
|
|
|
|
Just wait...
I'm beginning to understand.
When you write myDisp, you mean an object of type IDispatch.
So in my case i declare CComPtr<IAcadObject> myDisp;
When you write myAttrib, you mean an object of type IAcadAttributeReference.
So i declare CComQIPtr<IAcadAttributeReference ,&__uuidof(IAcadAttributeReference)> myAttrib;
I will try that immediately ...
(my previous post was also corrupted by the remove of <> !)
|
|
|
|
|
IT WORKED !!!
long i = 0;
CComPtr<IAcadObject> myDispatch;
CComQIPtr<IAcadAttributeReference ,&__uuidof(IAcadAttributeReference)> myAttrib;
try
{
result = SafeArrayGetElement(arrayAttrib.parray, &i, &myDispatch);
myAttrib = myDispatch;
if (result == S_OK)
{
double dist = myAttrib->GetHeight();
Wonderful support, thanks you very much, and now let's get some work done please
|
|
|
|
|
|
I have impelemented the following code:
STDMETHODIMP CCSerialno::MachineID()
{
// TODO: Add your implementation code here
char bufVolumeLabel[255] ="";
DWORD Size=255;
DWORD SerialNo;
long Slnum=0;
DWORD MCL;
DWORD Flags;
char bufFileSystem[255] ="";
for (int iCounter=0;iCounter
|
|
|
|
|
In your C++ code,
<br />
STDMETHODIMP CCSerialno::MachineID(long *machineID)<br />
{<br />
...<br />
*machineID = ...;<br />
...<br />
}<br />
In your IDL interface,
HRESULT MachineID([out,retval]long *machineID);
RSS feed
|
|
|
|
|
What the method returns is an HRESULT, which simply reveals success or failure.
Your IDL (or ODL) for the method needs to be
HRESULT MachineID([out,retval]long *pSerialNo)
and you need to modify the C++ declaration and code
STDMETHODIMP CCSerialno::MachineID(long* pRes)
{
// TODO: Add your implementation code here
TCHAR bufVolumeLabel[255] = _T("");
DWORD Size=255;
DWORD SerialNo;
long Slnum=0;
DWORD MCL;
DWORD Flags;
TCHAR bufFileSystem[255] =_T("");
for (int iCounter=0;iCounter < 26; i++)
{
if (GetDriveType((LPCTSTR)(HardDiskLetters[iCounter]))==DRIVE_FIXED)
if (GetVolumeInformation((LPCTSTR)(HardDiskLetters[iCounter]),
(LPTSTR)(bufVolumeLabel),Size,&SerialNo,&MCL,&Flags,(LPTSTR)(bufFileSystem),Size))
{
Slnum=Slnum+SerialNo;
}
}
if (pRes!=NULL)
{
*pRes = Slnum;
return S_OK;
}
return E_INVALIDARG;
}
Steve S
|
|
|
|
|
|
We aim to please!
Steve S
|
|
|
|
|
I am trying to implement tree control context menus and their not working very well. When right-clicking on an item, the item is not selected, making the context menu very useless. The tree control is in a dialog bar. What could be the problem?
-- Steve
|
|
|
|
|
You're getting either NM_RCLICK or WM_CONTEXTMENU too soon, not that you can do anything about that. What I've done in similar situations is to use PostMessage to send a private message that tells me to pop up a context menu. By the time I receive this, the select operation has completed. Alternatively, you have to get the coords of the mouse at the time of the original message and hit test the items yourself, then update the selection state.
Sounds trickier than it is, really...
Steve S
[This signature space available for rent]
|
|
|
|
|
My application needs to run 2 powerpoint presentations in a "kiosk" manner. One is a screensaver, that is shown until the user moves the mouse, when the application should automatically display the interactive application.
The app is able to show the presentations, but how can I get some kind of mousemove event from Powerpoint so that I can change the presentation being shown?
Thanks in advance.
G. Raven
|
|
|
|
|
I'm actually trying to solve a similar problem myself. In my case, what I'd like to do is to be able to detect mouse clicks on elements in a running PowerPoint presentation, or at least clicks in the PowerPoint window. Can anyone give me some suggestions on how to do this, or let me know if it's even possible?
|
|
|
|
|
Hello all,
I am currently writing a COM plug-in for Outlook that gets all AppointmentItem data utilizing Invoke and calling methods such as GetSubject and GetAddress. However, I need to get the recurrence pattern of the AppointmentItem and I am unsure how to setup the Invoke call to get this to work. Also, I don't know the return value. Unfortunately, MSDN only shows how to do this using a typelib, and I have been unable to find anything on the web on how to do a straight COM call. Does anyone have any idea on how to get the recurrence for a particular AppointmentItem?
Brigg Thorp
Software Engineer
Timex Corporation
|
|
|
|
|
I implemented the following code using ATL COM and implemented the method MachineID.
I have declared MAX_OF_HARD_DISKS and HardDiskLetters[] as follows
#define MAX_OF_HARD_DISKS 24
static char HardDiskLetters[MAX_OF_HARD_DISKS][4]={
"c:\\", "d:\\", "e:\\", "f:\\", "g:\\", "h:\\",
"i:\\", "j:\\", "k:\\", "l:\\", "m:\\", "n:\\",
"o:\\", "p:\\", "q:\\", "r:\\", "s:\\", "t:\\",
"u:\\", "v:\\", "w:\\", "x:\\", "y:\\", "z:\\"
};
STDMETHODIMP CSerialno::MachineID()
{
// TODO: Add your implementation code here
ULARGE_INTEGER AvailableToCaller, Disk, Free;
for (int iCounter=0;iCounter
|
|
|
|
|
adsilva wrote:
I get error at code GetDiskFreeSpaceEx as "cannot convert parameter 1 from char[4] to const unsigned short* "
static TCHAR HardDiskLetters[][MAX_OF_HARD_DISKS]={
"c:\\", "d:\\", "e:\\", "f:\\", "g:\\", "h:\\",
"i:\\", "j:\\", "k:\\", "l:\\", "m:\\", "n:\\",
"o:\\", "p:\\", "q:\\", "r:\\", "s:\\", "t:\\",
"u:\\", "v:\\", "w:\\", "x:\\", "y:\\", "z:\\"
};
RSS feed
|
|
|
|
|
Thanks a lot!!
But now I am getting 25 errors after changing char to TCHAR. Do I need to add any header file to get rid of the errors.
The error is as follows
error C2440: 'initializing' : cannot convert from 'char [4]' to 'unsigned short'
This conversion requires a reinterpret_cast, a C-style cast or function-style cast
Thanks
Anna
|
|
|
|
|
I didn't only change char to TCHAR. I have also changed the order in [][] dimensions.
The overall code compiles and runs fine on my machine (vc++6.0).
RSS feed
|
|
|
|
|
Sorry!! Still I just can't get rid of the errors!!
D:\Backup Codes\Crypts\Serialno.cpp(18) : error C2440: 'initializing' : cannot convert from 'char [4]' to 'unsigned short'
This conversion requires a reinterpret_cast, a C-style cast or function-style cast
Note: I have used this code in ATL COM .
Thanks ,
Anna.
|
|
|
|
|