Autor Beitrag
Hagbard
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 142

Win XP Home / Pro
D7.1 Architekt
BeitragVerfasst: Mi 14.07.04 11:16 
Hallo zusammen,

dank Udontknow, habe Ich gesterm die Verbindung zu der VB OCX geschaffen. Nun habe Ich ein weiteres Problem.
Ich kann das Objekt Createn und kann auch den DeviceName zuweisen. Wenn Ich aber dem Property: PortOpen den Wert True zuweise bleibt mir Delphi wieder stehen. Durch die Exception Behandlung bekomme Ich dann die Fehlermeldung: "Client Site not available". (Fehlerbeschreibung siehe unten)... Hat jemand eine Idee woran das liegen könnte?

Code der Unit:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
constructor TTiCRIS320.Create;
  var test : IS320;
begin
  inherited;

  ComIS := CreateComObject(CLASS_IS320) as _IS320Disp;

  try

    ComIS.DeviceName := 'IntelliStripe';

    ComIS.PortOpen := True;

  except
    On E:Exception do begin
      ShowMessage('ClassName: ' + e.ClassName + #13#10 + 'Message: ' + e.Message);
    end;
  end;
end;



Fehlerbeschreibung (aus der MSDN Online Hilfe von M$):
ausblenden Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
  The User Control or User Document cannot retrieve information from its container.
  This error has the following cause and solution:
  The User Control or User Document tried to get information from the container's
  Ambient properties or its Extender object before the container attached to it. This can
  happen if you try to access these objects before your InitProperties or ReadProperties
  events get fired, such as in the Initialize event, or for some containers in the Terminate
  event.

  To solve this problem, wait for an InitProperties or ReadProperties event before
  accessing these objects.


Die Events, die in der Fehlerbeschreibung erwähnt werden habe Ich in Delphi, bzw. in dem TLB File nirgends finden können. Auch das COM/DCOM mit Delphi Buch konnte mir diesbezüglich nicht weiterhelfen :-(

P.S. das hier ist der Code der TLB Unit:
ausblenden volle Höhe Delphi-Quelltext
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:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146:
147:
148:
149:
150:
151:
152:
153:
154:
155:
156:
157:
158:
159:
160:
161:
162:
163:
164:
165:
166:
167:
168:
169:
170:
171:
172:
173:
174:
175:
176:
177:
178:
179:
180:
181:
182:
183:
184:
185:
186:
187:
188:
189:
190:
191:
192:
193:
194:
195:
196:
197:
198:
199:
200:
201:
202:
203:
204:
205:
206:
207:
208:
209:
210:
211:
212:
213:
214:
215:
216:
217:
218:
219:
220:
221:
222:
223:
224:
225:
226:
227:
228:
229:
230:
231:
232:
233:
234:
235:
236:
237:
238:
239:
240:
241:
242:
243:
244:
245:
246:
247:
248:
249:
250:
251:
252:
253:
254:
255:
256:
257:
258:
259:
260:
261:
262:
263:
264:
265:
266:
267:
268:
269:
270:
271:
272:
unit IS320OCX_TLB;

// ************************************************************************ //
// WARNUNG                                                                    
// -------                                                                    
// Die in dieser Datei deklarierten Typen wurden aus Daten einer Typbibliothek
// generiert. Wenn diese Typbibliothek explizit oder indirekt (über eine     
// andere Typbibliothek) reimportiert wird oder wenn die Anweisung            
// 'Aktualisieren' im Typbibliotheks-Editor während des Bearbeitens der     
// Typbibliothek aktiviert ist, wird der Inhalt dieser Datei neu generiert und 
// alle manuell vorgenommenen Änderungen gehen verloren.                           
// ************************************************************************ //

// PASTLWTR : 1.2
// Datei generiert am 13.07.2004 11:40:12 aus der unten beschriebenen Typbibliothek.

// ************************************************************************  //
// Typbib: C:\IS320OCX\MTIS320.ocx (1)
// LIBID: {749A82C2-4BBB-4929-80AC-5787472CC302}
// LCID: 0
// Hilfedatei: 
// Hilfe-String: MagTek ActiveX Comp for IntelliStripe 320 Device
// DepndLst: 
//   (1) v2.0 stdole, (C:\WINDOWS\System32\stdole2.tlb)
// ************************************************************************ //
{$TYPEDADDRESS OFF} // Unit muß ohne Typüberprüfung für Zeiger compiliert werden. 
{$WARN SYMBOL_PLATFORM OFF}
{$WRITEABLECONST ON}
{$VARPROPSETTER ON}
interface

uses Windows, ActiveX, Classes, Graphics, OleCtrls, OleServer, StdVCL, Variants;
  


// *********************************************************************//
// In dieser Typbibliothek deklarierte GUIDS . Es werden folgende         
// Präfixe verwendet:                                                     
//   Typbibliotheken     : LIBID_xxxx                                     
//   CoClasses           : CLASS_xxxx                                     
//   DISPInterfaces      : DIID_xxxx                                      
//   Nicht-DISP-Schnittstellen: IID_xxxx                                       
// *********************************************************************//
const
  // Haupt- und Nebenversionen der Typbibliothek
  IS320OCXMajorVersion = 1;
  IS320OCXMinorVersion = 0;

  LIBID_IS320OCX: TGUID = '{749A82C2-4BBB-4929-80AC-5787472CC302}';

  IID__IS320: TGUID = '{457E6C84-D0DB-4C0E-AEE4-353ACB9BB9E3}';
  DIID___IS320: TGUID = '{8533A84C-4E80-4F1A-9A64-B0194005C81F}';
  IID__IS320Class: TGUID = '{181E25E6-A9C3-4960-AF0F-5076DE028400}';
  CLASS_IS320Class: TGUID = '{D0EA3171-5BB6-4A7F-BB49-A2142A52F373}';
  CLASS_IS320: TGUID = '{CFC1F09E-0863-4349-ABAB-6DFA04FB13BB}';

// *********************************************************************//
// Deklaration von in der Typbibliothek definierten Enumerationen         
// *********************************************************************//
// Konstanten für enum DeviceStateType
type
  DeviceStateType = TOleEnum;
const
  PORTCLOSED = $00000000;
  INITIALIZECOMM = $00000001;
  ESTABLISHCOMM = $00000002;
  WAITCARDINSERT = $00000003;
  WAITCARDREADY = $00000004;
  PROCESSINGCARD = $00000005;
  WAITCARDREMOVAL = $00000006;
  WAITCARDUNSEATED = $00000007;

// Konstanten für enum ReadDirection
type
  ReadDirection = TOleEnum;
const
  READ_BOTH = $00000000;
  READ_FWD = $00000001;
  READ_REV = $00000002;

type

// *********************************************************************//
// Forward-Deklaration von in der Typbibliothek definierten Typen         
// *********************************************************************//
  _IS320 = interface;
  _IS320Disp = dispinterface;
  __IS320 = dispinterface;
  _IS320Class = interface;
  _IS320ClassDisp = dispinterface;

// *********************************************************************//
// Deklaration von in der Typbibliothek definierten CoClasses             
// (HINWEIS: Hier wird jede CoClass zu ihrer Standardschnittstelle        
// zugewiesen)                                                            
// *********************************************************************//
  IS320Class = _IS320Class;
  IS320 = _IS320;


// *********************************************************************//
// Schnittstelle: _IS320
// Flags:     (4560) Hidden Dual NonExtensible OleAutomation Dispatchable
// GUID:      {457E6C84-D0DB-4C0E-AEE4-353ACB9BB9E3}
// *********************************************************************//
  _IS320 = interface(IDispatch)
    ['{457E6C84-D0DB-4C0E-AEE4-353ACB9BB9E3}']
    function Get_PortOpen: WordBool; safecall;
    procedure Set_PortOpen(Param1: WordBool); safecall;
    function Get_DeviceState: DeviceStateType; safecall;
    procedure Set_DeviceState(Param1: DeviceStateType); safecall;
    function Get_SmartCardType: WideString; safecall;
    procedure Set_SmartCardType(const Param1: WideString); safecall;
    function Get_ReadTimeout: Smallint; safecall;
    procedure Set_ReadTimeout(Param1: Smallint); safecall;
    function Get_SmartCardData: WideString; safecall;
    procedure Set_SmartCardData(const Param1: WideString); safecall;
    function WriteMagStripe(const MagData: WideString): Smallint; safecall;
    function ReadMagStripe: Smallint; safecall;
    function Get_MagstripeData: WideString; safecall;
    procedure Set_MagstripeData(const Param1: WideString); safecall;
    procedure About; safecall;
    function ClearBuffer: Smallint; safecall;
    function Get_SmartCardATR: WideString; safecall;
    procedure Set_SmartCardATR(const Param1: WideString); safecall;
    function EjectCard: Smallint; safecall;
    function Get_DeviceName: WideString; safecall;
    procedure Set_DeviceName(const Param1: WideString); safecall;
    function Get_MSRReadDirManual: ReadDirection; safecall;
    procedure Set_MSRReadDirManual(Param1: ReadDirection); safecall;
    function Get_SmartCardEnable: WordBool; safecall;
    procedure Set_SmartCardEnable(Param1: WordBool); safecall;
    function Get_LatchEnable: WordBool; safecall;
    procedure Set_LatchEnable(Param1: WordBool); safecall;
    function Get_AutoEjectEnable: WordBool; safecall;
    procedure Set_AutoEjectEnable(Param1: WordBool); safecall;
    function Get_PowerFailDetectEnable: WordBool; safecall;
    procedure Set_PowerFailDetectEnable(Param1: WordBool); safecall;
    function Get_DeviceModel: WideString; safecall;
    function GetTrack(var TrackNum: Smallint): WideString; safecall;
    function GetFName: WideString; safecall;
    function GetLName: WideString; safecall;
    function FindElement(TrackNum: Smallint; const RefChar: WideString; Displacement: Smallint; 
                         const NumDigits: WideString; var DirectionBack: OleVariant): WideString; safecall;
    function GetDefSetting(const Key: WideString; var Default: WideString): WideString; safecall;
    procedure SaveDefSetting(var Key: WideString; var Setting: WideString); safecall;
    function Get_LastErrorNum: Smallint; safecall;
    procedure Set_LastErrorNum(Param1: Smallint); safecall;
    function Get_LastErrorString: WideString; safecall;
    procedure Set_LastErrorString(const Param1: WideString); safecall;
    function Get_PictureFileName: WideString; safecall;
    procedure Set_PictureFileName(const Param1: WideString); safecall;
    function Get_PictureAvailable: WordBool; safecall;
    procedure Set_PictureAvailable(Param1: WordBool); safecall;
    function EnumerateMCPDevices: OleVariant; safecall;
    function SaveSmartCardData(const PictureFileName: WideString; const PersonalData: WideString): Smallint; safecall;
    property PortOpen: WordBool read Get_PortOpen write Set_PortOpen;
    property DeviceState: DeviceStateType read Get_DeviceState write Set_DeviceState;
    property SmartCardType: WideString read Get_SmartCardType write Set_SmartCardType;
    property ReadTimeout: Smallint read Get_ReadTimeout write Set_ReadTimeout;
    property SmartCardData: WideString read Get_SmartCardData write Set_SmartCardData;
    property MagstripeData: WideString read Get_MagstripeData write Set_MagstripeData;
    property SmartCardATR: WideString read Get_SmartCardATR write Set_SmartCardATR;
    property DeviceName: WideString read Get_DeviceName write Set_DeviceName;
    property MSRReadDirManual: ReadDirection read Get_MSRReadDirManual write Set_MSRReadDirManual;
    property SmartCardEnable: WordBool read Get_SmartCardEnable write Set_SmartCardEnable;
    property LatchEnable: WordBool read Get_LatchEnable write Set_LatchEnable;
    property AutoEjectEnable: WordBool read Get_AutoEjectEnable write Set_AutoEjectEnable;
    property PowerFailDetectEnable: WordBool read Get_PowerFailDetectEnable write Set_PowerFailDetectEnable;
    property DeviceModel: WideString read Get_DeviceModel;
    property LastErrorNum: Smallint read Get_LastErrorNum write Set_LastErrorNum;
    property LastErrorString: WideString read Get_LastErrorString write Set_LastErrorString;
    property PictureFileName: WideString read Get_PictureFileName write Set_PictureFileName;
    property PictureAvailable: WordBool read Get_PictureAvailable write Set_PictureAvailable;
  end;

// *********************************************************************//
// DispIntf:  _IS320Disp
// Flags:     (4560) Hidden Dual NonExtensible OleAutomation Dispatchable
// GUID:      {457E6C84-D0DB-4C0E-AEE4-353ACB9BB9E3}
// *********************************************************************//
  _IS320Disp = dispinterface
    ['{457E6C84-D0DB-4C0E-AEE4-353ACB9BB9E3}']
    property PortOpen: WordBool dispid 1745027089;
    property DeviceState: DeviceStateType dispid 1745027088;
    property SmartCardType: WideString dispid 1745027087;
    property ReadTimeout: Smallint dispid 1745027086;
    property SmartCardData: WideString dispid 1745027085;
    function WriteMagStripe(const MagData: WideString): Smallint; dispid 1610809362;
    function ReadMagStripe: Smallint; dispid 1610809363;
    property MagstripeData: WideString dispid 1745027084;
    procedure About; dispid 1610809364;
    function ClearBuffer: Smallint; dispid 1610809370;
    property SmartCardATR: WideString dispid 1745027083;
    function EjectCard: Smallint; dispid 1610809371;
    property DeviceName: WideString dispid 1745027082;
    property MSRReadDirManual: ReadDirection dispid 1745027081;
    property SmartCardEnable: WordBool dispid 1745027080;
    property LatchEnable: WordBool dispid 1745027079;
    property AutoEjectEnable: WordBool dispid 1745027078;
    property PowerFailDetectEnable: WordBool dispid 1745027077;
    property DeviceModel: WideString readonly dispid 1745027076;
    function GetTrack(var TrackNum: Smallint): WideString; dispid 1610809376;
    function GetFName: WideString; dispid 1610809377;
    function GetLName: WideString; dispid 1610809378;
    function FindElement(TrackNum: Smallint; const RefChar: WideString; Displacement: Smallint; 
                         const NumDigits: WideString; var DirectionBack: OleVariant): WideString; dispid 1610809379;
    function GetDefSetting(const Key: WideString; var Default: WideString): WideString; dispid 1610809380;
    procedure SaveDefSetting(var Key: WideString; var Setting: WideString); dispid 1610809381;
    property LastErrorNum: Smallint dispid 1745027075;
    property LastErrorString: WideString dispid 1745027074;
    property PictureFileName: WideString dispid 1745027073;
    property PictureAvailable: WordBool dispid 1745027072;
    function EnumerateMCPDevices: OleVariant; dispid 1610809388;
    function SaveSmartCardData(const PictureFileName: WideString; const PersonalData: WideString): Smallint; dispid 1610809389;
  end;

// *********************************************************************//
// DispIntf:  __IS320
// Flags:     (4240) Hidden NonExtensible Dispatchable
// GUID:      {8533A84C-4E80-4F1A-9A64-B0194005C81F}
// *********************************************************************//
  __IS320 = dispinterface
    ['{8533A84C-4E80-4F1A-9A64-B0194005C81F}']
    procedure CardDataChanged; dispid 1;
  end;

// *********************************************************************//
// Schnittstelle: _IS320Class
// Flags:     (4560) Hidden Dual NonExtensible OleAutomation Dispatchable
// GUID:      {181E25E6-A9C3-4960-AF0F-5076DE028400}
// *********************************************************************//
  _IS320Class = interface(IDispatch)
    ['{181E25E6-A9C3-4960-AF0F-5076DE028400}']
  end;

// *********************************************************************//
// DispIntf:  _IS320ClassDisp
// Flags:     (4560) Hidden Dual NonExtensible OleAutomation Dispatchable
// GUID:      {181E25E6-A9C3-4960-AF0F-5076DE028400}
// *********************************************************************//
  _IS320ClassDisp = dispinterface
    ['{181E25E6-A9C3-4960-AF0F-5076DE028400}']
  end;

// *********************************************************************//
// Die Klasse CoIS320Class stellt die Methoden Create und CreateRemote zur      
// Verfügung, um Instanzen der Standardschnittstelle _IS320Class, dargestellt von
// CoClass IS320Class, zu erzeugen. Diese Funktionen können                     
// von einem Client verwendet werden, der die CoClasses automatisieren    
// möchte, die von dieser Typbibliothek dargestellt werden.               
// *********************************************************************//
  CoIS320Class = class
    class function Create: _IS320Class;
    class function CreateRemote(const MachineName: string): _IS320Class;
  end;

implementation

uses ComObj;

class function CoIS320Class.Create: _IS320Class;
begin
  Result := CreateComObject(CLASS_IS320Class) as _IS320Class;
end;

class function CoIS320Class.CreateRemote(const MachineName: string): _IS320Class;
begin
  Result := CreateRemoteComObject(MachineName, CLASS_IS320Class) as _IS320Class;
end;

end.


Viele Grüße,
Christian

Moderiert von user profile iconUdontknow: Beiträge zusammengefasst
Moderiert von user profile iconPeter Lustig: Code- durch Delphi-Tags ersetzt.

_________________
I haven't failed, I just found 10,000 ways that won't work!
Udontknow
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2596

Win7
D2006 WIN32, .NET (C#)
BeitragVerfasst: Mi 14.07.04 11:43 
Hallo!

Das scheint irgendein internes Problem zu sein. Vielleicht hilft ein Sleep(500) vor dem Open? Musst du vielleicht noch irgendwas einstellen? DeviceState oder SmartCardType?

Ansonsten würde ich mich mal direkt mit dem Herstellersupport in Verbindung setzen.

Cu,
Udontknow
Hagbard Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 142

Win XP Home / Pro
D7.1 Architekt
BeitragVerfasst: Mi 14.07.04 11:56 
Hi,

das mit dem Sleep hab ich auch schon probiert. bringt aber nichts :-(

Das mit dem Hersteller Support ist so ne Sache, hab schon etliche Mails geschrieben
und nie ne Antwort bekommen :-(

aber Thx! :-)

Gruß,
Christian

P.S. Das ist ein DEMO VB Code, der funktioniert...:
ausblenden volle Höhe Quelltext
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:
Dim Imagefile As String

Private Sub cboMSRReadDir_Click()
IS3201.MSRReadDirManual = cboMSRReadDir.ListIndex
End Sub

Private Sub Check1_Click()
IS3201.AutoEjectEnable = CBool(Check1.Value)
End Sub

Private Sub cmdClear_Click()
txtTrack(1).Text = ""
txtTrack(2).Text = ""
txtTrack(3).Text = ""
txtSmartCardATR.Text = ""

Image1.Visible = False

End Sub

Private Sub cmdClosePort_Click()
IS3201.PortOpen = False
If Not IS3201.PortOpen Then
  cmdOpenPort.Enabled = True
  cmdClosePort.Enabled = False
End If
End Sub

Private Sub cmdOpenPort_Click()
IS3201.DeviceName = txtDeviceName.Text
IS3201.PortOpen = True
If IS3201.PortOpen Then
  cmdOpenPort.Enabled = False
  cmdClosePort.Enabled = True
  txtDeviceModel.Text = IS3201.DeviceModel
Else
MsgBox IS3201.LastErrorNum & " : " & IS3201.LastErrorString
End If
End Sub

Private Sub Command1_Click()
IS3201.EjectCard

End Sub


Private Sub Command2_Click()
Dim smcarddata As String
  smcarddata = InputBox("Enter string to put on card", "Smart Card Data", "This is a test")
  Imagefile = InputBox("Enter File name of the image", "Image File", "C:\micr.jpg")
  MsgBox IS3201.SaveSmartCardData(Imagefile, smcarddata)
End Sub

Private Sub Command3_Click()
MsgBox IS3201.SmartCardData
End Sub

Private Sub Form_Load()
txtDeviceName.Text = GetSetting("IntPictureDemo", "Settings", "DeviceName", "ISPictureDemo")
cboMSRReadDir.ListIndex = IS3201.MSRReadDirManual
IS3201.PictureFileName = "C:\testimage.jpg"
'IS3201.PictureFileName = ""

End Sub

Private Sub Form_Unload(Cancel As Integer)
IS3201.PortOpen = False

End Sub

Private Sub IS3201_CardDataChanged()
txtTrack(1).Text = IS3201.GetTrack(1)
txtTrack(2).Text = IS3201.GetTrack(2)
txtTrack(3).Text = IS3201.GetTrack(3)
txtSmartCardATR.Text = IS3201.SmartCardATR

If IS3201.PictureAvailable Then
  Set Image1.Picture = LoadPicture("C:\testimage.jpg")
  Image1.Visible = True
Else
  Image1.Visible = False
End If




'MsgBox IS3201.SmartCardData
'MsgBox IS3201.FindElement(6, "!", 0, "^")

End Sub


Edit:

Gibt es andere möglichkeiten auf eine OCX zuzugreifen? Z.b.: Das man sie irgendwie installiert und ähnlich wie die normalen Delphi Komponenten benutzen kann??

Viele Grüße,
Christian

Moderiert von user profile iconUdontknow: Beiträge zusammengefasst.

_________________
I haven't failed, I just found 10,000 ways that won't work!
Udontknow
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2596

Win7
D2006 WIN32, .NET (C#)
BeitragVerfasst: Do 15.07.04 10:42 
Nun, eine sogenannte Wrapperkomponente hast du ja im Endeffekt versucht, selbst zu erstellen. Ich glaube, Delphi kann das auch selber (ActiveX importieren\Installieren), aber das wird dir nicht bei deinem Problem helfen, da intern eben doch wieder das Interface genutzt wird.

Cu,
Udontknow
Hagbard Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 142

Win XP Home / Pro
D7.1 Architekt
BeitragVerfasst: Do 15.07.04 12:01 
das hab ich schon gemerkt. Egal ob ich nur die Units erstellen lasse, oder das ActiveX versuche zu installieren.

Es werden immer lediglich die TLB DPR und die PAS erzeugt und dann dem entsprechenden Projekt hinzugefügt.

Meine Vermutung:
Es gibt in der IS320OCX_TLP CoClasses, welche mir ein Objekt vom Typ _IS320Class zurückliefern. Wahrscheinlich muß Ich mit diesem Objekt irgendwie ein _IS320Disp Objekt erstellen, um auf die entsprechenden Funktionen der OCX zugreifen zu können.

Das Große Problem an der Sache ist eigentlich nur... wie?? *fg*

_________________
I haven't failed, I just found 10,000 ways that won't work!