How to drop files onto .MAPIMail - winapi

Given some files (or shell file objects) how do i invoke the .MAPIMail registered shell extension handler with them?
The Question
i have some files on the computer:
C:\Users\ian\AppData\Local\Temp\Contoso_Invoice_141174.pdf
C:\Users\ian\AppData\Local\Temp\Contoso_Invoice_141173.pdf
C:\Users\ian\AppData\Local\Temp\Contoso_Invoice_141171.pdf
That i want to do the programmatic equivalent of dropping them on the .MAPIMail registered handler:
The Sent to folder's Mail recipient option is actually a special registered .MAPIMail extension:
Which is a file type that is registered on the system:
HKEY_CLASSES_ROOT\.mapimail
How do i invoke a drop onto a ephermeral .mapimail file?
Can't you just look in the registry?
Now, i could be a bad developer, and spellunk the registry, the .mapimail entry's default value:
CLSID\{9E56BE60-C50F-11CF-9A2C-00A0C90A90CE}
Extract the clsid {9E56BE60-C50F-11CF-9A2C-00A0C90A90CE}, and confirm that class is registered:
HKEY_CLASSES_ROOT\CLSID\{9E56BE60-C50F-11CF-9A2C-00A0C90A90CE}
(default) = Desktop Shortcut
\InProcServer32
(default) = %SystemRoot%\System32\sendmail.dll
And use CoCreateInstance to create that COM object:
IUnknown unk = CreateComObject("{9E56BE60-C50F-11CF-9A2C-00A0C90A90CE}");
And then i'm in an undocumented, unsupported world, where i don't know what interface i have to QueryInterface for, and what methods to call in what order.
So we're left with shell programming
What i'd like is to likely something involving the shell (pseudo-code):
IShellFolder desktop;
OleCheck(SHGetDesktopFolder(out desktop));
List<pidl> pidls = new List<pidl>();
ULONG chEaten = 0;
ULONG dwAttributes = 0;
PIDL pidl;
foreach (String filename in Files) do
{
OleCheck(desktop.ParseDisplayName(0, nil, filename, out chEaten, out pidl, ref dwAttributes));
pidls.Add(pidl);
}
//Get the shell folder of the temp folder
IShellFolder tempShellFolder;
desktop.ParseDisplayName(0, nil, GetTemporaryPath, out chEaten, out pidl, ref dwAttributes));
desktop.BindToObject(pidl, nil, IShellFolder, tempShellFolder);
//i have no idea what i've been doing; just throwing reasonable looking code together
//nobody will actually ever read this
IDontCare context;
tempShellFolder.GetUIObjectOf(0, pidls.Count, pidls, IDontCareAnymore, nil, ref context);
Except all that code relies on the extistance of a context menu, which i don't have. Nobody says that .MAPIMail has to be in any context Send to menu.
i was asking how to drop files on a .mapimail file.
And my god.
Why not just use MAPI?
Because no MAPI client is installed when you're a 32-bit application running on Windows 64-bit with Office 64-bit installed. So i need to be able to accomplish what the user already can.

Although it doesn't answer my question, Raymond pointed out that it's a stupid question. Nobody in their right mind should be trying to send mail to recipients. But i was desperate!
Turns out i'm not completely stuck. While there is a bitness nightmare when dealing with 64-bit Outlook (MAPI provider) from 32-bit applications (or vice versa), there is one out.
If i use just MapiSendMail, and no other MAPI functions, it is safe to cross the 32-bit/64-bit barrier. From Building MAPI Applications on 32-Bit and 64-Bit Platforms:
32-bit MAPI Application and 64-Bit Outlook
32-bit MAPI applications are not supported to run on a computer installed with 64-bit Outlook and 64-bit Windows. The application developer must update and rebuild the application as a 64-bit application for the 64-bit platform. This is because a 32-bit application cannot load a 64-bit Msmapi32.dll file. There are a small number of API changes that application developers must incorporate to build their code successfully for a 64-bit environment. MAPI header files have been updated with these changes to support the 64-bit platform. You can download these header files at Outlook 2010: MAPI Header Files. Developers can use this same set of MAPI header files to build both 32-bit and 64-bit MAPI applications
That makes it sound like all hope is lost. But, there is, on Windows 7:
Exception: MAPISendMail
However, one function call among all Simple MAPI and MAPI elements, MAPISendMail, would succeed in a Windows-32-bit-on-Windows-64-bit (WOW64) or Windows-64-bit-on-Windows-32-bit (WOW32) scenario and would not result in the above alert. This WOW64 scenario only applies to Windows 7. Figure 2 shows a WOW64 scenario in which a 32-bit MAPI application calls MAPISendMail on a computer installed with 64-bit Windows 7. In this scenario, the MAPI library makes a COM call to launch a 64-bit Fixmapi application. The Fixmapi application implicitly links to the MAPI library, which routes the function call to the Windows MAPI stub, which in turn forwards the call to the Outlook MAPI stub, enabling the MAPISendMail function call to succeed.
So, as a Delphi Jedi user, their Simple Send E-mail functions will fail (as they use too much of MAPI). So i had to create my own:
procedure MapiSimpleSendMail(slFiles: TStrings; ToEmailAddress: string=''; ToName: string='');
var
mapiMessage: TMapiMessage;
flags: LongWord;
// senderName: AnsiString;
// senderEmailAddress: AnsiString;
emailSubject: AnsiString;
emailBody: AnsiString;
// sender: TMapiRecipDesc;
recipients: packed array of TMapiRecipDesc;
attachments: packed array of TMapiFileDesc;
i: Integer;
hr: Cardinal;
es: string;
const
MAPI_E_UNICODE_NOT_SUPPORTED = 27; //Windows 8. The MAPI_FORCE_UNICODE flag is specified and Unicode is not supported.
begin
ZeroMemory(#mapiMessage, SizeOf(mapiMessage));
{ senderName := '';
senderEmailAddress := '';
ZeroMemory(#sender, sizeof(sender));
sender.ulRecipClass := MAPI_ORIG; //MAPI_TO, MAPI_CC, MAPI_BCC, MAPI_ORIG
sender.lpszName := PAnsiChar(senderName);
sender.lpszAddress := PAnsiChar(senderEmailAddress);}
mapiMessage.lpOriginator := nil; //PMapiRecipDesc; { Originator descriptor }
if ToEmailAddress <> '' then
begin
SetLength(recipients, 1);
recipients[0].ulRecipClass := MAPI_TO;
recipients[0].lpszName := LPSTR(ToName);
recipients[0].lpszAddress := LPSTR(ToEmailAddress);
mapiMessage.lpRecips := #recipients[0]; //A value of NULL means that there are no recipients. Additionally, when this member is NULL, the nRecipCount member must be zero.
mapiMessage.nRecipCount := 1;
end
else
begin
mapiMessage.lpRecips := nil; //A value of NULL means that there are no recipients. Additionally, when this member is NULL, the nRecipCount member must be zero.
mapiMessage.nRecipCount := 0;
end;
mapiMessage.lpszMessageType := nil;
if slFiles.Count > 0 then
begin
emailSubject := 'Emailing: ';
emailBody :=
' '+#13#10+ //Yes, the shell really does create a blank mail with a leading line of ten spaces
'Your message is ready to be sent with the following file or link attachments:'+#13#10;
SetLength(attachments, slFiles.Count);
for i := 0 to slFiles.Count-1 do
begin
attachments[i].ulReserved := 0; // Cardinal; { Reserved for future use (must be 0) }
attachments[i].flFlags := 0; // Cardinal; { Flags }
attachments[i].nPosition := $FFFFFFFF; //Cardinal; { character in text to be replaced by attachment }
attachments[i].lpszPathName := PAnsiChar(slFiles[i]); { Full path name of attachment file }
attachments[i].lpszFileName := nil; // LPSTR; { Original file name (optional) }
attachments[i].lpFileType := nil; // Pointer; { Attachment file type (can be lpMapiFileTagExt) }
if i > 0 then
emailSubject := emailSubject+', ';
emailSubject := emailSubject+ExtractFileName(slFiles[i]);
emailBody := emailBody+#13#10+
ExtractFileName(slFiles[i]);
end;
emailBody := emailBody+#13#10+
#13#10+
#13#10+
'Note: To protect against computer viruses, e-mail programs may prevent sending or receiving certain types of file attachments. Check your e-mail security settings to determine how attachments are handled.';
mapiMessage.lpFiles := #attachments[0];
mapiMessage.nFileCount := slFiles.Count;
end
else
begin
emailSubject := '';
emailBody := '';
mapiMessage.lpFiles := nil;
mapiMessage.nFileCount := 0;
end;
{
Subject
Emailing: 4388_888871544_MVM_10.tmp, amt3.log, swtag.log, wct845C.tmp, ~vs1830.sql
Body
<-- ten spaces
Your message is ready to be sent with the following file or link attachments:
4388_888871544_MVM_10.tmp
amt3.log
swtag.log
wct845C.tmp
~vs1830.sql
Note: To protect against computer viruses, e-mail programs may prevent sending or receiving certain types of file attachments. Check your e-mail security settings to determine how attachments are handled.
}
mapiMessage.lpszSubject := PAnsiChar(emailSubject);
mapiMessage.lpszNoteText := PAnsiChar(emailBody);
flags := MAPI_DIALOG;
hr := Mapi.MapiSendMail(0, 0, mapiMessage, flags, 0);
case hr of
SUCCESS_SUCCESS: {nop}; //The call succeeded and the message was sent.
MAPI_E_AMBIGUOUS_RECIPIENT:
begin
//es := 'A recipient matched more than one of the recipient descriptor structures and MAPI_DIALOG was not set. No message was sent.';
raise Exception.CreateFmt('Error %s sending e-mail message: %s', ['MAPI_E_AMBIGUOUS_RECIPIENT', SysErrorMessage(hr)]);
end;
MAPI_E_ATTACHMENT_NOT_FOUND:
begin
//The specified attachment was not found. No message was sent.
raise Exception.CreateFmt('Error %s sending e-mail message: %s', ['MAPI_E_ATTACHMENT_NOT_FOUND', SysErrorMessage(hr)]);
end;
MAPI_E_ATTACHMENT_OPEN_FAILURE:
begin
//The specified attachment could not be opened. No message was sent.
raise Exception.CreateFmt('Error %s sending e-mail message: %s', ['MAPI_E_ATTACHMENT_OPEN_FAILURE', SysErrorMessage(hr)]);
end;
MAPI_E_BAD_RECIPTYPE:
begin
//The type of a recipient was not MAPI_TO, MAPI_CC, or MAPI_BCC. No message was sent.
raise Exception.CreateFmt('Error %s sending e-mail message: %s', ['MAPI_E_BAD_RECIPTYPE', SysErrorMessage(hr)]);
end;
MAPI_E_FAILURE:
begin
//One or more unspecified errors occurred. No message was sent.
raise Exception.CreateFmt('Error %s sending e-mail message: %s', ['MAPI_E_FAILURE', SysErrorMessage(hr)]);
end;
MAPI_E_INSUFFICIENT_MEMORY:
begin
//There was insufficient memory to proceed. No message was sent.
raise Exception.CreateFmt('Error %s sending e-mail message: %s', ['MAPI_E_INSUFFICIENT_MEMORY', SysErrorMessage(hr)]);
end;
MAPI_E_INVALID_RECIPS:
begin
//One or more recipients were invalid or did not resolve to any address.
raise Exception.CreateFmt('Error %s sending e-mail message: %s', ['MAPI_E_INVALID_RECIPS', SysErrorMessage(hr)]);
end;
MAPI_E_LOGIN_FAILURE:
begin
//There was no default logon, and the user failed to log on successfully when the logon dialog box was displayed. No message was sent.
raise Exception.CreateFmt('Error %s sending e-mail message: %s', ['MAPI_E_LOGIN_FAILURE', SysErrorMessage(hr)]);
end;
MAPI_E_TEXT_TOO_LARGE:
begin
//The text in the message was too large. No message was sent.
raise Exception.CreateFmt('Error %s sending e-mail message: %s', ['MAPI_E_TEXT_TOO_LARGE', SysErrorMessage(hr)]);
end;
MAPI_E_TOO_MANY_FILES:
begin
//There were too many file attachments. No message was sent.
raise Exception.CreateFmt('Error %s sending e-mail message: %s', ['MAPI_E_TOO_MANY_FILES', SysErrorMessage(hr)]);
end;
MAPI_E_TOO_MANY_RECIPIENTS:
begin
//There were too many recipients. No message was sent.
raise Exception.CreateFmt('Error %s sending e-mail message: %s', ['MAPI_E_TOO_MANY_RECIPIENTS', SysErrorMessage(hr)]);
end;
MAPI_E_UNICODE_NOT_SUPPORTED:
begin
//The MAPI_FORCE_UNICODE flag is specified and Unicode is not supported.
//Note This value can be returned by MAPISendMailW only.
raise Exception.CreateFmt('Error %s sending e-mail message: %s', ['MAPI_E_UNICODE_NOT_SUPPORTED', SysErrorMessage(hr)]);
end;
MAPI_E_UNKNOWN_RECIPIENT:
begin
//A recipient did not appear in the address list. No message was sent.
raise Exception.CreateFmt('Error %s sending e-mail message: %s', ['MAPI_E_UNKNOWN_RECIPIENT', SysErrorMessage(hr)]);
end;
MAPI_E_USER_ABORT:
begin
es := 'The user canceled one of the dialog boxes. No message was sent.';
raise Exception.CreateFmt('Error %s sending e-mail message: %s', ['MAPI_E_USER_ABORT', es]);
end;
else
raise Exception.CreateFmt('Error %d sending e-mail message: %s', [hr, SysErrorMessage(hr)]);
end;
end;
Note: Any code is released into the public domain. No attribution required.

Related

Mail not being received after adding a ReplyRecipient

Using Outlook for Microsoft Office 365 32 bit and Delphi XE8
I am evaluation Redemption.dll as Windows 11 has blocked my application from accessing Outlook.
I have Outlook configure with multiple profiles and stores
I can open the profiles find the store/account and can send/receive.
In one combination I do not receive the email.
The issue is with
Mail.ReplyRecipients.Add('xxx#gmail.com');
if I comment this line out I receive the email
In the sent folder I can dblclick and by clicking reply I see the Reply Address but in the inbox (of the recipient) I get nothing. I scanned all Outlook items to no avail.
In the reverse direction I do receive the email.
I intend ti purchase the product on completion of my evaluation. But this feature is important
procedure TForm61._Send(Profile, Sender, _To, _CC, _BCC, Subject, Body: String;
ReadReceiptRequested: Boolean; _Attachments: TArray<String>);
var
FolderFound: Boolean;
c, j, Count, k: Integer;
Session: IRDOSession;
Store: IRDOStore;
Drafts: IRDOFolder;
Recip: IRDORecipient;
MAil: IRDOMail;
IPMRoot: IRDOFolder;
ReplyRecip: IRDORecipient;
_name: String;
begin
Session:=CoRDOSession.Create;
Session.Logon(Profile,'', False, True,EmptyParam,EmptyParam);
Drafts:=Session.GetFolderFromPath('\\'+Sender+'\Inbox');
Mail:= Drafts.Items.Add(olMailItem);
Recip := Mail.Recipients.Add(_To);
Recip.type_:= olTo;
if not _CC.IsEmpty then
begin
Recip := Mail.Recipients.Add(_CC);
Recip.type_:= olCC;
end;
if not _BCC.IsEmpty then
begin
Recip := Mail.Recipients.Add(_BCC);
Recip.type_:= olBCC;
end;
// Recip.Resolve(EmptyParam, EmptyParam);
// ReplyRecip:=Mail.ReplyRecipients.Add('xxx#gmail.com');
Mail.ReplyRecipients.Add('xxx#gmail.com');
// ReplyRecip.Resolve(EmptyParam, EmptyParam);
for j:=0 to Length(_Attachments)- 1 do
Mail.Attachments.Add(_Attachments[j], EmptyParam, EmptyParam, EmptyParam);
Mail.Subject:=Subject;
Mail.ReadReceiptRequested:=ReadReceiptRequested;
Mail.HTMLBody:=Body;
if SignatureIndex>-1 then
begin
Signature:=Session.Signatures.Item(SignatureIndex+1); //noy zero-based
Signature.ApplyTo(Mail, False);
end;
Mail.OriginatorDeliveryReportRequested:=True;
Mail.Save;
Mail.Send;
end;
TIA
Ephraim

Inno Setup - How to validate serial number online

Using Inno Setup, setup.exe was given to a client, according to contract he is allowed only to use 2016 and 2017. But on 01-01-2018 he should not be able to continue with same serial 2017.
How to make the setup.exe by innosetup limited to from and to date?
[Setup]
#define SerialNumber "2017"
UserInfoPage=yes
[Code]
function CheckSerial(Serial: String): Boolean;
begin
Result := Serial = '{#SerialNumber}';
end;
setup.exe is executed
license key is inserted
after submit, i want to check URL https://www.example.com/query/license?id=2017
if the result is ok or nok based on that the installation continue
Starting with a code from: Inno Setup - HTTP request - Get www/web content, you will get something like:
[Setup]
UserInfoPage=yes
[Code]
// Presence of the CheckSerial event function displays the serial number box.
// But here we accept any non-empty serial.
// We will validate it only in the NextButtonClick,
// as the online validation can take long.
function CheckSerial(Serial: String): Boolean;
begin
Result := (Serial <> '');
end;
function NextButtonClick(CurPageID: Integer): Boolean;
var
WinHttpReq: Variant;
Url: string;
begin
Result := True;
if CurPageID = wpUserInfo then
begin
WinHttpReq := CreateOleObject('WinHttp.WinHttpRequest.5.1');
Url := 'https://www.example.com/serial.php?serial=' +
WizardForm.UserInfoSerialEdit.Text;
WinHttpReq.Open('GET', Url, False);
WinHttpReq.Send('');
// Depending on implementation of the server,
// use either HTTP status code (.Status)
// or contents of returned "page" (.ResponseText)
// Here we use the HTTP status code:
// 200 = serial is valid, anything else = serial is invalid,
// and when invalid, we display .ResponseText
Result := (WinHttpReq.Status = 200);
if not Result then
MsgBox(WinHttpReq.ResponseText, mbError, MB_OK);
end;
end;
A simple server-side validation PHP script (serial.php) would be like:
<?
if (empty($_REQUEST["serial"]) || ($_REQUEST["serial"] != "2017"))
{
header("HTTP/1.0 401 The serial number is not valid");
// error message to be displayed in installer
echo "The serial number is not valid";
}
For consideration:
This validation is not difficult to bypass, i.e. using a proxy server.
It also does not prevent the user from extracting the files from the installer and installing them manually.
You may consider instead an on-line download of the actual files only after validating the serial number.
Or downloading some license file that the application will require for functioning. You need that anyway, if you want to enforce the application to stop working once the license expires.
Or you can also encrypt the installer and make the online service return the decryption password:
Read Inno Setup encryption key from Internet instead of password box
For a similar question, see also
How to store serial numbers in a Sharepoint List, for to call from Inno Setup and verify if is autorized user?

Issue implementing an OSX CoreMidi MidiCallback function in Lazarus/FreePascal

I'am struggling implementing an OSX CoreMidi MidiCallback procedure with Lazarus / FreePascal.
In the MIDIServices unit, MIDIReadProc, the callback routine, is definded:
MIDIReadProc = procedure( (*const*) pktlist: MIDIPacketListPtr; readProcRefCon: UnivPtr; srcConnRefCon: UnivPtr );
This routine is called on a separate high-priority thread owned by CoreMidi when midi events are received.
I defined a callback procedure for handling received midi events:
Type procedure MyMidiCallback(pktList: MIDIPacketListPtr;readProcRefCon: UnivPtr; srcConnRefCon: UnivPtrMy);
procedure TMainForm.MyMidiCallback(pktList: MIDIPacketListPtr;readProcRefCon: UnivPtr; srcConnRefCon: UnivPtr);
begin
// handle midi packets
end;
The midi callback hook is defined in the following code at 'MidiInputPortCreate':
procedure TMainForm.ReceiveMidiTestClick(Sender: TObject);
var
NumOfSources, NumOfDestinations: ItemCount;
x: byte;
MIDIDestinationPointer, MidiSourcePointer: MIDIEndpointRef;
EndPointName: CFStringRef;
MidiClient: MidiClientRef;
InputPort: MidiPortRef;
MidiCallback: MidiReadProc;
begin
NumOfDestinations := MIDIGetNumberOfDestinations;
NumOfSources := MIDIGetNumberOfSources;
Memo.Lines.Add('Number of Midi Sources: ' + IntToStr(NumOfSources));
EndPointName := nil;
MidiClient := nil;
InputPort := nil;
MidiCallback := #TMainform.MyMidiCallback;
for x := 0 to NumOfDestinations -1 do // show destinations
begin
MidiDestinationPointer := MidiGetDestination(x);
MIDIObjectGetStringProperty(MidiDestinationPointer, kMIDIPropertyName, EndPointName);
Memo.Lines.Add('Destination ' + IntToStr(x) + ': ' + CFStrToAnsiStr(EndPointName));
end;
for x := 0 to NumOfSources -1 do // show sources
begin
MidiSourcePointer := MIDIGetSource(x);
MIDIObjectGetStringProperty(MidiSourcePointer, kMIDIPropertyName, EndPointName);
Memo.Lines.Add('Source ' + IntToStr(x) + ': ' + CFStrToAnsiStr(EndPointName));
end;
MidiClientCreate(CFSTRP('Midi Input Client'), nil, nil, MidiClient);
MidiInputPortCreate(MidiClient, CFSTRP('Input'), MidiCallback, nil, InputPort); // MidiCallback
MIDISourcePointer := MIDIGetSource(0); // select source(0) = midi keyboard
MidiPortConnectSource(InputPort, MIDISourcePointer, nil);
end;
Compiling generates the following error message:
mainunit.pas(480,19) Error: Incompatible types: got "<procedure variable type of procedure(MIDIPacketListPtr,Pointer,Pointer) of object;Register>" expected "<procedure variable type of procedure(MIDIPacketListPtr,Pointer,Pointer);MWPascal>"
I'am stuck here now; hope someone can help.
--------------------------------- UPDATE #1 ----------------------------------
The code above was indeed a bit strange so I rewrote things:
procedure TMainForm.ReceiveMidiTestClick(Sender: TObject);
var
MidiClient: MidiClientRef;
InputPort: MidiPortRef;
MidiCallback: MIDIReadProc;
begin
MidiCallback := MyMidiCallback;
MidiClientCreate(CFSTRP('Midi Input Client'), nil, nil, MidiClient);
MidiInputPortCreate(MidiClient, CFSTRP('Input'), MidiCallback, nil, InputPort);
MidiPortConnectSource(InputPort, MIDIGetSource(0), nil);
end;
procedure MyMidiCallback(pktList: MIDIPacketListPtr; readProcRefCon: UnivPtr; srcConnRefCon: UnivPtr);
begin
// handle midi packets
end;
Now the code compiles without errors but as soon as i hit a key on the midi keyboard, the application crashes with the following error message:
'ERROR Project ... raised exception class 'External: Sigtrap' at address FFFFD96F'
(FFFFD96F is probably the pointer to the MidiCallback routine).
Basically, the issue I have is how to let the MidiCallback pointer in MidiInputPortCreate point correctly to my MyMidiCallback procedure where I handle midi events.
BTW, sending Midi events works fine.
Let's put the error declarations in the error on separate lines:
mainunit.pas(480,19) Error: Incompatible types: got "
procedure(MIDIPacketListPtr,Pointer,Pointer) of object;Register>" expected "<
procedure variable type of procedure(MIDIPacketListPtr,Pointer,Pointer);MWPascal>"
Note two crucial differences:
1) The "of object" difference in the two procedure declarations in the error means you passed a method instead of a proper procedure.
2) Besides that, calling conventions doesn't seem to match, one is mwpascal; one is Register. Register is the default for most modes, so no calling convention modifier means register.
The "callback" part of your question is strange. You define a type as a procedure, but provide a method as implementation?

How to read a text file from the Internet resource?

I would like to read a text file containing a version number from the Internet resource. Then I need to use this version number within my script.
How to do this in InnoSetup ?
There are many ways how to get a file from the Internet in InnoSetup. You can use an external library like for instance InnoTools Downloader, write your own library, or use one of the Windows COM objects. In the following example I've used the WinHttpRequest COM object for file receiving.
The DownloadFile function in this script returns True, when the WinHTTP functions doesn't raise any exception, False otherwise. The response content of the HTTP GET request to an URL, specified by the AURL parameter is then passed to a declared AResponse parameter. When the script fails the run on exception, AResponse parameter will contain the exception error message:
[Code]
function DownloadFile(const AURL: string; var AResponse: string): Boolean;
var
WinHttpRequest: Variant;
begin
Result := True;
try
WinHttpRequest := CreateOleObject('WinHttp.WinHttpRequest.5.1');
WinHttpRequest.Open('GET', AURL, False);
WinHttpRequest.Send;
AResponse := WinHttpRequest.ResponseText;
except
Result := False;
AResponse := GetExceptionMessage;
end;
end;
procedure InitializeWizard;
var
S: string;
begin
if DownloadFile('http://www.example.com/versioninfo.txt', S) then
MsgBox(S, mbInformation, MB_OK)
else
MsgBox(S, mbError, MB_OK)
end;

TNetSharingManager access violation problem

I'm trying to compile this project in Delphi 2010, which uses TNetSharingManager. I have imported the type library and tried compiling it, but unfortunately I'm getting an Access Violation in this function:
function TNetSharingManager.GetDefaultInterface: INetSharingManager;
begin
if FIntf = nil then
Connect;
Assert(FIntf nil, 'DefaultInterface is NULL. Component is not connected to Server. You must call "Connect" or "ConnectTo" before this operation');
Result := FIntf;
end;
(part of NETCONLib_TLB)
The error is in : if FIntf = nil then for some odd reason..
The code which is calling it:
procedure TForm1.GetConnectionList(Strings,IdList: TStrings);
var
pEnum: IEnumVariant;
vNetCon: OleVARIANT;
dwRetrieved: Cardinal;
pUser: NETCONLib_TLB.PUserType1;
NetCon : INetConnection;
begin
Strings.Clear;
IdList.Clear;
pEnum := ( NetSharingManager.EnumEveryConnection._NewEnum as IEnumVariant);
while (pEnum.Next(1, vNetCon, dwRetrieved) = S_OK) do
begin
(IUnknown(vNetCon) as INetConnection).GetProperties(pUser);
NetCon := (IUnknown(vNetCon) as INetConnection);
if (pUser.Status in [NCS_CONNECTED,NCS_CONNECTING])//remove if you want disabled NIC cards also
and (pUser.MediaType in [NCM_LAN,NCM_SHAREDACCESSHOST_LAN,NCM_ISDN] )
and (GetMacAddress(GuidToString(pUser.guidId))'' ) then
begin
//we only want valid network cards that are enabled
Strings.Add(pUser.pszwName );
IdList.Add(GuidToString(pUser.guidId));
end;
end;
end;
I don't understand why I cannot compare with nil. Any ideas?
It is likely the TNetSharingManager object itself has actually died (or wasn't created in the first place) when that error is triggered. The FIntF = nil expression is the first reference to an actual field of the class, i.e. it will be pointing into invalid address space.
[Edit] I download the source and followed the steps to import the TLB (Delphi 2010). To execute the appilcation, I had to (a) run Delphi as an admin, because I'm not a power user by default and (b) had to add a check for pUser <> nil because the final getProperties returns a nil-structure, but other than that the code run fine. So unfortunately, I can't seem to reproduce your problem.
Rereading your question, are you getting an AV while compiling?

Resources