Как правило, вы позволяете базе данных генерировать ключ в виде числового значения, а затем форматируете его в своей программе.
Скажем, у вас есть автоматически сгенерированный первичный ключ из вашей базы данных, и сгенерированный ключ 18435876, вы можете отформатировать его в java, чтобы он был «1843-5876».
Delphi использует так называемое fastcall соглашение о вызовах по умолчанию. Это означает, что компилятор пытается передать параметры функции в регистрах ЦП и только использует стек, если существует больше параметров, чем бесплатные регистры. Например, использование Delphi (EAX, EDX, ECX) для первых трех параметров к функции.
В Вашем коде C# Вы на самом деле используете stdcall соглашение о вызовах, которое дает компилятору команду передавать параметры через стек (в обратном порядке, т.е. последний параметрический усилитель продвинут сначала) и позволять очистке вызываемого стек.
Напротив, вызов cdecl, используемый компиляторами C/C++, вынуждает вызывающую сторону к очистке стек.
Просто удостоверьтесь, что Вы используете то же соглашение о вызовах с обеих сторон. Stdcall главным образом используется, потому что он может использоваться почти везде и поддерживается каждым компилятором (API Win32 также используют эту конвенцию).
Обратите внимание, что fastcall не поддерживается.NET так или иначе.
jn является правильным. Прототипа функции, столь же данного, нельзя легко назвать непосредственно от C#, пока это находится в Delphi register
соглашение о вызовах. Любой необходимо записать a stdcall
функция обертки для него - возможно, в другом DLL, если у Вас нет источника - или необходимо получить людей, которые поддерживают функцию для изменения ее соглашения о вызовах на stdcall
.
Обновление: Я также вижу, что первым аргументом является строка Delphi. Это не что-то, что C# может предоставить также. Это должен быть PChar вместо этого. Кроме того, важно согласиться, является ли функцией Ansi или Unicode; если DLL записан с Delphi 2009 (или позже), то это - Unicode, иначе это - Ansi.
Я никогда не делал этого, но пытаюсь изменить Ваш код на:
function CreateCode(SerialID : String;
StartDateOfYear, YearOfStartDate, YearOfEndDate, DatePeriod : Word;
CodeType,RecordNumber,StartHour,EndHour : Byte) : PChar; stdcall;
external 'CreateCodeDLL.dll';
Отметьте дополнительный stdcall.
Edit2: Поскольку Вы видите от других ответов Вас или должны сделать изменение выше или записать обертку dll, который делает то же самое.
Возвращаемое значение могло бы быть другой проблемой. Это - вероятно, любой утечка памяти (Они выделяют буфер на "куче" и никогда не освобождают ее), или доступ к уже свободной памяти (Они возвращают локальный бросок строковой переменной PChar).
Возврат строк (или переменная измерил данные в целом) от функции до другого модуля проблематичен в целом.
Одно решение (используемый winapi) состоит в том, чтобы потребовать, чтобы вызывающая сторона передала в буфере и его размере. Недостаток этого - то, что, если буфер является слишком маленьким, функциональные сбои и вызывающая сторона должны назвать его снова с более крупным буфером.
Другое возможное решение состоит в том, чтобы выделить буфер от "кучи" в функции и возвратить его. Затем необходимо экспортировать другую функцию, которую вызывающая сторона должна использовать для освобождения выделенной памяти снова. Это гарантирует, что память освобождена тем же временем выполнения, которое выделило ее.
При передаче (Delphi) строковый параметр между различным (не Borland) языки, вероятно, невозможен. И даже между модулями Delphi Вы для обеспечения обоих модулей используете тот же экземпляр диспетчера памяти. Обычно это означает добавлять, "использует ShareMem" в качестве первого использования ко всем модулям. Другим различием является соглашение о вызовах "регистр", который является fastcall конвенцией, но не идентичный с fastcall использованием компиляторов MS.
Совершенно другое решение могло перекомпилировать Delphi dll с одним из компиляторов Delphi.net. Сколько работы, которая является, зависит от их кода.
Создайте обертку COM в Delphi и вызове, которые в Вашем C# кодируют через interop. Вуаля.. простой в использовании от C# или любой другой будущей платформы.
В то время как Вы просите, чтобы они изменили соглашение о вызовах, необходимо также попросить, чтобы они изменили первый параметр так, чтобы это не была "строка". Заставьте их использовать указатель на (завершенный пустым указателем) символ или массив widechar вместо этого. Используя строки Delphi как параметры DLL плохая идея даже без добавленной сложности попытки достигнуть межъязыковой совместимости. Кроме того, строковая переменная будет или содержать ASCII или содержание Unicode, в зависимости от которой версии Delphi они используют.
На днях я шутил, пытаясь узнать о созыве конвенций, и написал несколько приёмов для конвертации между различными из них. Вот один для StdCall>FastCall.
typedef struct
{
USHORT ParameterOneOffset; // The offset of the first parameter in dwords starting at one
USHORT ParameterTwoOffset; // The offset of the second parmaeter in dwords starting at one
} FastCallParameterInfo;
__declspec( naked,dllexport ) void __stdcall InvokeFast()
{
FastCallParameterInfo paramInfo;
int functionAddress;
int retAddress;
int paramOne, paramTwo;
__asm
{
// Pop the return address and parameter info. Store in memory.
pop retAddress;
pop paramInfo;
pop functionAddress;
// Check if any parameters should be stored in edx
movzx ecx, paramInfo.ParameterOneOffset;
cmp ecx,0;
je NoRegister;
// Calculate the offset for parameter one.
movzx ecx, paramInfo.ParameterOneOffset; // Move the parameter one offset to ecx
dec ecx; // Decrement by 1
mov eax, 4; // Put 4 in eax
mul ecx; // Multiple offset by 4
// Copy the value from the stack on to the register.
mov ecx, esp; // Move the stack pointer to ecx
add ecx, eax; // Subtract the offset.
mov eax, ecx; // Store in eax for later.
mov ecx, [ecx]; // Derefernce the value
mov paramOne, ecx; // Store the value in memory.
// Fix up stack
add esp,4; // Decrement the stack pointer
movzx edx, paramInfo.ParameterOneOffset; // Move the parameter one offset to edx
dec edx; // Decrement by 1
cmp edx,0; // Compare offset with zero
je ParamOneNoShift; // If first parameter then no shift.
ParamOneShiftLoop:
mov ecx, eax;
sub ecx, 4;
mov ecx, [ecx]
mov [eax], ecx; // Copy value over
sub eax, 4; // Go to next
dec edx; // decrement edx
jnz ParamOneShiftLoop; // Loop
ParamOneNoShift:
// Check if any parameters should be stored in edx
movzx ecx, paramInfo.ParameterTwoOffset;
cmp ecx,0;
je NoRegister;
movzx ecx, paramInfo.ParameterTwoOffset; // Move the parameter two offset to ecx
sub ecx, 2; // Increment the offset by two. One extra for since we already shifted for ecx
mov eax, 4; // Put 4 in eax
mul ecx; // Multiple by 4
// Copy the value from the stack on to the register.
mov ecx, esp; // Move the stack pointer to ecx
add ecx, eax; // Subtract the offset.
mov eax, ecx; // Store in eax for later.
mov ecx, [ecx]; // Derefernce the value
mov paramTwo, ecx; // Store the value in memory.
// Fix up stack
add esp,4; // Decrement the stack pointer
movzx edx, paramInfo.ParameterTwoOffset; // Move the parameter two offset to ecx
dec edx; // Decrement by 1
cmp edx,0; // Compare offset with zero
je NoRegister; // If first parameter then no shift.
ParamTwoShiftLoop:
mov ecx, eax;
sub ecx, 4;
mov ecx, [ecx]
mov [eax], ecx; // Copy value over
sub eax, 4; // Go to next
dec edx; // decrement edx
jnz ParamTwoShiftLoop; // Loop
NoRegister:
mov ecx, paramOne; // Copy value from memory to ecx register
mov edx, paramTwo; //
push retAddress;
jmp functionAddress;
}
}
}