-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathuCoGetServerPID.pas
109 lines (85 loc) · 2.94 KB
/
uCoGetServerPID.pas
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
unit uCoGetServerPID;
// Copyright (c) 2012, Jon Robertson
// All rights reserved.
//
// Released under the Modified BSD license. For details, please see LICENSE file.
//
// CoGetServerPID will take a COM Object and return the Process ID of the
// server that is hosting the object.
//
// This code was converted from Kim Gräsman's C version. Please see Kim's web page for additional credits.
// The web page is at http://www.kontrollbehov.com/articles/cogetserverpid/
//
// Thanks to Robert Marquardt for assisting with the conversion. Thanks to
// Project JEDI (http://www.delphi-jedi.org/) for all of their conversion work!
//
// I use this like so:
//
// var
// WordApp: OleVariant;
// WordPID: DWORD;
// begin
// WordApp := CreateOleObject('Word.Application');
// OleCheck(CoGetServerPID(FWordApp, dwWordPID));
//
// Although it's a hack, it works great!
// Disclaimer: Actually, I've only tested it from Delphi 6.
// Your mileage will vary.
interface
uses Windows;
function CoGetServerPID (const unk: IUnknown; var dwPID: DWORD): HRESULT;
implementation
uses ActiveX, ComObj, Variants;
type
// Used to verify the COM object's signature and to sniff the PID out of the header.
TComObjRefHdr = packed record
signature: DWORD; // Should be 'MEOW'
padding : array[0..47] of Byte;
pid : WORD;
end;
PComObjRefHdr = ^TComObjRefHdr;
function CoGetServerPID(const unk: IUnknown; var dwPID: DWORD): HRESULT;
var
PObjRefHdr : PComObjRefHdr;
spProxyManager : IUnknown;
spMarshalStream : IStream;
liNewPos : Int64;
HG : HGLOBAL;
const
IID_IUnknown: TGUID = (D1:$00000000;D2:$0000;D3:$0000;D4:($C0,$00,$00,$00,$00,$00,$00,$46));
begin
if VarIsNULL(unk) then begin
Result := E_INVALIDARG;
Exit;
end;
// Check if not standard proxy. We can't make any assumptions about remote PID
Result := unk.QueryInterface(IID_IProxyManager, spProxyManager);
if Failed(Result) then Exit;
// Marshall the interface to get a new OBJREF
Result := CreateStreamOnHGlobal(0, True, spMarshalStream);
if Failed(Result) then Exit;
Result := CoMarshalInterface(spMarshalStream, IID_IUnknown, unk, MSHCTX_INPROC, nil, MSHLFLAGS_NORMAL);
if Failed(Result) then Exit;
// We just created the stream. So go back to a raw pointer.
Result := GetHGlobalFromStream(spMarshalStream, HG);
if Succeeded(Result) then try
// Start out pessimistic
Result := RPC_E_INVALID_OBJREF;
PObjRefHdr := GlobalLock(HG);
if Assigned(PObjRefHdr) then begin
// Verify that the signature is MEOW
if PObjRefHdr^.signature = $574f454d then begin
// We got the remote PID
dwPID := PObjRefHdr^.pid;
Result := S_OK;
end;
end;
finally
GlobalUnlock(HG);
end;
// Rewind stream and release marshal data to keep refcount in order
liNewPos := 0;
spMarshalStream.Seek(0, STREAM_SEEK_SET, liNewPos);
CoReleaseMarshalData(spMarshalStream);
end;
end.