Vulkan vkCreateInstance - Access violation writing location 0x0000000000000000 - c

I am trying to write a basic program using Vulkan, but I keep getting a runtime error.
Exception thrown at 0x00007FFDC27A8DBE (vulkan-1.dll) in VulkanTest.exe: 0xC0000005: Access violation writing location 0x0000000000000000.
This seems to be a relatively common issue, resulting from a failure to initialize the arguments of the vkCreateInstance function. I have tried all of the solutions I found proposed to others, even initializing things I am fairly certain I don't need to, and I still haven't been able to solve the problem. The program is written in C using the MSVC compiler.
#include "stdio.h"
#include "SDL.h"
#include "vulkan\vulkan.h"
#include "System.h"
int main(int argc, char *argv[])
{
//Initialize SDL
if (SDL_Init(SDL_INIT_EVERYTHING) < 0)
{
printf("Error");
}
printf("Success");
//Initialize Vulkan
VkInstance VulkanInstance;
VkApplicationInfo VulkanApplicationInfo;
VulkanApplicationInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
VulkanApplicationInfo.pNext = 0;
VulkanApplicationInfo.pApplicationName = "VulkanTest";
VulkanApplicationInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
VulkanApplicationInfo.pEngineName = "VulkanTest";
VulkanApplicationInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
VulkanApplicationInfo.apiVersion = VK_API_VERSION_1_0;
VkInstanceCreateInfo VulkanCreateInfo = {0,0,0,0,0,0,0,0};
VulkanCreateInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
VulkanCreateInfo.pNext = 0;
VulkanCreateInfo.pApplicationInfo = &VulkanApplicationInfo;
VulkanCreateInfo.enabledLayerCount = 1;
VulkanCreateInfo.ppEnabledLayerNames = "VK_LAYER_KHRONOS_validation";
vkEnumerateInstanceExtensionProperties(0, VulkanCreateInfo.enabledExtensionCount,
VulkanCreateInfo.ppEnabledExtensionNames);
//Create Vulkan Instance
if(vkCreateInstance(&VulkanCreateInfo, 0, &VulkanInstance) != VK_SUCCESS)
{
printf("Vulkan instance was not created");
}
//Create SDL Window
SDL_Window* window;
window = SDL_CreateWindow("VulkanTest", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 0, 0, SDL_WINDOW_VULKAN || SDL_WINDOW_FULLSCREEN_DESKTOP);
SDL_Delay(10000);
return 0;
}

Are you sure the call to vkCreateInstance() is what is crashing? I have not tried to debug the code you have shown (that is your job), but just looking at the calls that the code is making, it should be the call to vkEnumerateInstanceExtensionProperties() that is crashing (if it even compiles at all!).
The 2nd parameter of vkEnumerateInstanceExtensionProperties() expects a uint32_t* pointer, but you are passing in a uint32_t value (VulkanCreateInfo.enabledExtensionCount) that has been initialized to 0. So, that would make the pPropertyCount parameter be a NULL pointer (if it even compiles).
You are passing VulkanCreateInfo.ppEnabledExtensionNames in the 3rd parameter (if that even compiles), and ppEnabledExtensionNames has been initialized to NULL. Per the documentation for vkEnumerateInstanceExtensionProperties():
If pProperties is NULL, then the number of extensions properties available is returned in pPropertyCount. Otherwise, pPropertyCount must point to a variable set by the user to the number of elements in the pProperties array, and on return the variable is overwritten with the number of structures actually written to pProperties.
Since pPropertCount is NULL, vkEnumerateInstanceExtensionProperties() has nowhere to write the property count to! That would certainly cause an Access Violation trying to write to address 0x0000000000000000.
The documentation clears states:
pPropertyCount must be a valid pointer to a uint32_t value
On top of that, your call to vkEnumerateInstanceExtensionProperties() is just logically wrong anyway, because the 3rd parameter expects a pointer to an array of VkExtensionProperties structs, but VulkanCreateInfo.ppEnabledExtensionNames is a pointer to an array of const char* UTF-8 strings instead.
In other words, you should not be using vkEnumerateInstanceExtensionProperties() to initialize criteria for the call to vkCreateInstance(). You are completely misusing vkEnumerateInstanceExtensionProperties(). You probably meant to use SDL_Vulkan_GetInstanceExtensions() instead, eg:
uint32_t ExtensionCount = 0;
if (!SDL_Vulkan_GetInstanceExtensions(NULL, &ExtensionCount, NULL))
{
...
}
const char **ExtensionNames = (const char **) SDL_malloc(sizeof(const char *) * ExtensionCount);
if (!ExtensionNames)
{
...
}
if (!SDL_Vulkan_GetInstanceExtensions(NULL, &ExtensionCount, ExtensionNames))
{
SDL_free(ExtensionNames);
...
}
VulkanCreateInfo.enabledExtensionCount = ExtensionCount;
VulkanCreateInfo.ppEnabledExtensionNames = ExtensionNames;
if (vkCreateInstance(&VulkanCreateInfo, 0, &VulkanInstance) != VK_SUCCESS)
{
...
}
SDL_free(ExtensionNames);
...

Related

Freeing a buffer in C that was created in a function [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 months ago.
Improve this question
I'm having some problems trying to free a buffer created in a function from outside that function in C. What I'm doing is to create bufA, do some stuff with it, then call a function which creates bufB, whose length is calculated inside that function. Bytes in bufA are then copied to bufB with some additional bytes added, then the function returns. Some further processing is done with bufB back in main(), then both bufA and bufB are freed. The program runs correctly, but throws an error when free(bufB) is called.
For very much simplified code, I have something like this:
typedef unsigned char BYTE;
// -----
int main(void) {
// -----
BYTE bufA = NULL;
// Specify lenBufA
bufA = calloc(lenBufA, 1);
// Populate bufA with some stuff.
BYTE bufB = NULL;
int lenBufB = myFunction(bufA, &bufB);
// Do something with bufB.
free(bufA);
free(bufB); // <=== Throws an error here.
return 0;
}
Then in myFunction() I may have something like this:
int myFunction(BYTE* inBuf, BYTE** outBuf) {
// Initialization.
// Calculate the length that outBuf will have and put it in outLen.
*outBuf = (BYTE*)calloc(outLen, 1);
// Do stuff with outBuf.
return outLen;
}
inBuf is not specified as constant as some bytes may be changed. calloc() rather than malloc() is used in main() and in the function because I want the bytes in both buffers to be initialized to zero, as a few bytes in both are not given values.
I'm using visual Studio 2022 with Windows 10. Somehow the error caused by free(bufB) must be related to the fact that memory is allocated in the function, not in main(). How is this fixed?
Your code is incomplete and does not compile. The main issue appears to be that the type of bufA and bufB is BYTE but should be a pointer BYTE *. Here is working code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef unsigned char BYTE;
int myFunction(const BYTE *inBuf, BYTE **outBuf) {
int outLen = strlen(inBuf);
*outBuf = calloc(outLen, 1);
if(!*outBuf) {
printf("calloc failed\n");
exit(1);
}
return outLen;
}
int main(void) {
BYTE *bufA = NULL;
int lenBufA = 42;
bufA = calloc(lenBufA, 1);
if(!bufA) {
printf("calloc failed\n");
exit(1);
}
memset(bufA, !'\0', lenBufA - 1); // heh
BYTE *bufB = NULL;
int lenBufB = myFunction(bufA, &bufB);
free(bufA);
free(bufB);
return 0;
}
It checks the return code of calloc, clarifies with const BYTE *inBuf that function doesn't change that argument.
On Googling ntdll.dll, it appears to be a Windows file of some type, and based on some blurb, it might be corrupted.
Accordingly, I copied the source files to another Windows 10 computer that also has Visual Studio 2022 installed, created a project, then compiled the source code. On executing I get the same message with different hex codes, However the hex code for sixbit-encoding6.exe is the same. Unfortunately the copy and paste feature of the mouse doesn't work for the message on that computer, but it thus looks as if the dll is probably not corrupted, and there is a problem with my application.

Segmentation fault 11 in following code. How to avoid overflow?

void main(int argc, char* argv[]) {
char* hostname = (char*)malloc(sizeof(char)*1024);
hostname = getClientHostName("122.205.26.34");
printf("%s\n", hostname);
free(hostname);
}
char* getClientHostName(char* client_ip) {
char hostnames[5][2];
hostnames[0][0] = "122.205.26.34";
hostnames[0][1] = "aaaaa";
hostnames[1][0] = "120.205.36.30";
hostnames[1][1] = "bbbbb";
hostnames[2][0] = "120.205.16.36";
hostnames[2][1] = "ccccc";
hostnames[3][0] = "149.205.36.46";
hostnames[3][1] = "dddddd";
hostnames[4][0] = "169.205.36.33";
hostnames[4][1] = "eeeeee";
for(int i = 0; i<5; i++) {
if(!strcmp(hostnames[i][0], client_ip))
return (char*)hostnames[i][1];
}
return NULL;
}
Beginner in C.
I am not sure if there would be a better way to implement what I am trying to implement. The code is self-explanatory. Is there any way that I can predefine the size of hostname, using some general size of IP addresses, to avoid seg fault? Is there a even better way where I don't have to hardcode the size?
After fixing the compiler errors and warnings you get:
const char* getClientHostName(const char* client_ip) {
const char * hostnames[5][2];
hostnames[0][0] = "122.205.26.34";
hostnames[0][1] = "aaaaa";
hostnames[1][0] = "120.205.36.30";
hostnames[1][1] = "bbbbb";
hostnames[2][0] = "120.205.16.36";
hostnames[2][1] = "ccccc";
hostnames[3][0] = "149.205.36.46";
hostnames[3][1] = "dddddd";
hostnames[4][0] = "169.205.36.33";
hostnames[4][1] = "eeeeee";
for(int i = 0; i<5; i++) {
if(!strcmp(hostnames[i][0], client_ip))
return hostnames[i][1];
}
return NULL;
}
int main(int argc, char* argv[]) {
const char * hostname = getClientHostName("128.205.36.34");
printf("%s\n", hostname);
}
Is there a even better way where I don't have to hardcode the size?
Take the habit to compile with all warnings and debug info: gcc -Wall -Wextra -g with GCC. Improve the code to get no warnings at all.
If you want to get genuine IP addresses, this is operating system specific (since standard C11 don't know about IP addresses; check by reading n1570). On Linux you would use name service routines such as getaddrinfo(3) & getnameinfo(3) or the obsolete gethostbyname(3).
If this is just an exercise without actual relationship to TCP/IP sockets (see tcp(7), ip(7), socket(7)) you could store the table in some global array:
struct myipentry_st {
const char* myip_hostname;
const char* myip_address;
};
then define a global array containing them, with the convention of terminating it by some {NULL, NULL} entry:
const struct myipentry_st mytable[] = {
{"aaaaa", "122.205.26.34"},
{"bbbb", "120.205.36.30"},
/// etc
{NULL, NULL} // end marker
};
You'll better have a global or static variable (not an automatic one sitting on the call stack) because you don't want to fill it on every call to your getClientHostName.
Then your lookup routine (inefficient, since in linear time) would be:
const char* getClientHostName(char* client_ip) {
for (const struct myipentry_st* ent = mytable;
ent->myip_hostname != NULL;
ent++)
// the if below is the only statement of the body of `for` loop
if (!strcmp(ent->myip_address, client_ip))
return ent->myip_hostname;
// this happens after the `for` when nothing was found
return NULL;
}
You could even declare that table as a heap allocated pointer:
const struct myipentry_st**mytable;
then use calloc to allocate it and read its data from some text file.
Read the documentation of every standard or external function that you are using. Don't forget to check against failure (e.g. of calloc, like here). Avoid memory leaks by appropriate calls to free. Use the debugger gdb and valgrind. Beware of undefined behavior.
In the real world, you would have perhaps thousands of entries and you would perform the lookup many times (perhaps millions of times, e.g. once per every HTTP request in a web server or client). Then choose a better data structure (hash table or red-black tree perhaps). Read some Introduction to Algorithms.
Add * to type definition char * hostnames[5][2]. This must be array of pointers, not simple chars. Another necessary change is strcpy instead of = in strcpy( hostname, getClientHostName("122.205.26.34") );.
PS: Always try to compile with 0 compiler warnings, not only 0 errors!

TCL_LINK_STRING causing segmentation fault (core dumped)

I'm trying to share a variable with c and tcl, the problem is when i try to read the variable in the c thread from tcl, it causes segmentation error, i'm not sure this is the right way to do it, but it seems to work for ints. The part that is causing the segmentation fault is this line is when i try to print "Var" but i want to read the variable to do the corresponding action when the variable changes.
Here is the C code that i'm using
void mode_service(ClientData clientData) {
while(1) {
char* Var = (char *) clientData;
printf("%s\n", Var);
usleep(100000); //100ms
}
}
static int mode_thread(ClientData cdata, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) {
Tcl_ThreadId id;
ClientData limitData;
limitData = cdata;
id = 0;
Tcl_CreateThread(&id, mode_service, limitData, TCL_THREAD_STACK_DEFAULT, TCL_THREAD_NOFLAGS);
printf("Tcl_CreateThread id = %d\n", (int) id);
// Wait thread process, before returning to TCL prog
int i, aa;
for (i=0 ; i<100000; i++) {aa = i;}
// Return thread ID to tcl prog to allow mutex use
Tcl_SetObjResult(interp, Tcl_NewIntObj((int)id));
printf("returning\n");
return TCL_OK;
}
int DLLEXPORT Modemanager_Init(Tcl_Interp *interp){
if (Tcl_InitStubs(interp, TCL_VERSION, 0) == NULL) {
return TCL_ERROR;
}
if (Tcl_PkgProvide(interp, "PCIe", "1.0") == TCL_ERROR) {
return TCL_ERROR;
}
// Create global Var
int *sharedPtr=NULL;
//sharedPtr = sharedPtr = (char *) Tcl_Alloc(sizeof(char));
Tcl_LinkVar(interp, "mode", (char *) &sharedPtr, TCL_LINK_STRING);
Tcl_CreateObjCommand(interp, "mode_thread", mode_thread, sharedPtr, NULL);
return TCL_OK;
}
In the tcl code, i'm changing the variable mode whenever the user presses a button for example:
set mode "Idle"
button .startSamp -text "Sample Start" -width 9 -height 3 -background $btnColor -relief flat -state normal -command {set mode "Sampling"}
set threadId [mode_thread]
puts "Created thread $threadId, waiting"
Your code is a complete mess! You need to decide what you are doing and then do just that. In particular, you are using Tcl_LinkVar so you need to decide what sort of variable you are linking to. If you get a mismatch between the storage, the C access pattern and the declared semantic type, you'll get crashes.
Because your code is in too complicated a mess for me to figure out exactly what you want to do, I'll illustrate with less closely related examples. You'll need to figure out from them how to change things in your code to get the result you need.
Linking Integer Variables
Let's do the simple case: a global int variable (declared outside any function).
int sharedVal;
You want your C code to read that variable and get the value. Easy! Just read it as it is in scope. You also want Tcl code to be able to write to that variable. Easy! In the package initialization function, put this:
Tcl_LinkVar(interp /* == the Tcl interpreter context */,
"sharedVal" /* == the Tcl name */,
(char *) &sharedVal /* == pointer to C variable */,
TCL_LINK_INT /* == what is it! An integer */);
Note that after that (until you Tcl_UnlinkVar) whenever Tcl code reads from the Tcl variable, the current value will be fetched from the C variable and converted.
If you want that variable to be on the heap, you then do:
int *sharedValPtr = malloc(sizeof(int));
C code accesses using *sharedValPtr, and you bind to Tcl with:
Tcl_LinkVar(interp /* == the Tcl interpreter context */,
"sharedVal" /* == the Tcl name */,
(char *) sharedValPtr /* == pointer to C variable */,
TCL_LINK_INT /* == what is it! An integer */);
Linking String Variables
There's a bunch of other semantic types as well as TCL_LINK_INT (see the documentation for a list) but they all follow that pattern except for TCL_LINK_STRING. With that, you do:
char *sharedStr = NULL;
Tcl_LinkVar(interp, "sharedStr", (char *) &sharedStr, TCL_LINK_STRING);
You also need to be aware that the string will always be allocated with Tcl_Alloc (which is substantially faster than most system memory allocators for typical Tcl memory usage patterns) and not with any other memory allocator, and so will also always be deallocated with Tcl_Free. Practically, that means if you set the string from the C side, you must use Tcl_Alloc to allocate the memory.
Posting Update Notifications
The final piece to note is when you set the variable from the C side but want Tcl to notice that the change has set (e.g., because a trace has been set or because you've surfaced the value in a Tk GUI), you should do Tcl_UpdateLinkedVar to let Tcl know that a change has happened that it should pay attention to. If you never use traces (or Tk GUIs, or the vwait command) to watch the variable for updates, you can ignore this API call.
Donal's answer is correct, but I try to show you what you did with your ClientData.
To clarify: All (or almost all, Idk) Tcl functions that take a function pointer also take a parameter of type ClientData that is passed to your function when Tcl calls it.
Let's take a look at this line:
Tcl_CreateObjCommand(interp, "mode_thread", mode_thread, NULL, NULL);
// ------------------------------------------------------^^^^
You always pass NULL as ClientData to the mode_thread function.
In the mode_thread function you use the passed ClientData (NULL) to pass it as ClientData to the new Thread:
limitData = cdata;
// ...
Tcl_CreateThread(&id, mode_service, limitData, TCL_THREAD_STACK_DEFAULT, TCL_THREAD_NOFLAGS);
In the mode_service function you use the ClientData (which is still NULL) as pointer to a char array:
char* Var = (char *) clientData;
Which is a pointer to the address 0x00.
And then you tell printf to dereference this NULL pointer:
printf("%s\n", Var);
Which obviously crashes your program.

Using pthread_create

I am having errors when I try to use pthread_create. I understand that my use of argsRight->thread_id / argsLeft->thread_id and NULL are not correct, but I am unsure how else to make a reference to the thread id. It requires a pointer, but it seems like every way I tried (&, *), the GCC compiler would not accept.
Also, is there any reason it will not accept my use of NULL? I can't see any reason that would be wrong, but GCC says my use of the void function is invalid.
Can anyone shed some light on how to properly set up a call to pthread_create? I have included parts from my method where I am using the pthread_create function.
void pthreads_ms(struct ms_args* args)
{
int left_end = (args->end + args->start) / 2;
int right_start = left_end + 1;
int rc1, rc2;
// Create left side struct
struct ms_args* argsLeft;
argsLeft = malloc(sizeof(args));
argsLeft->thread_id = (2 * args->thread_id + 1);
argsLeft->start = args->start;
argsLeft->end = left_end;
argsLeft->array = args->array;
// Same methodology as above to create the right side
if (args->start != args->end)
{
// Print the thread id number, and start and end places
printf("[%d] start %d end %d", args->thread_id, args->start, args->end);
// Sort Left Side
rc1 = pthread_create(argsLeft->thread_id, NULL, pthreads_ms(argsLeft), argsLeft); //problem line here
//Sort right side
rc2 = pthread_create(argsRight->thread_id, NULL, pthreads_ms(argsRight), argsRight); //problem line here
}
It is not your application, it's pthread_create() will fill thread_id field. So, first of all, struct ms_args's field should be of type pthread_t and you should pass a pointer to that field:
pthread_create(&argsLeft->thread_id, ...
According to pthread_create the proper call should be
rc1 = pthread_create(&(argsLeft->thread_id), NULL, &pthreads_ms, argsLeft);
Same goes for right side.
The definition of pthread_ms() should include a return value
void *pthreads_ms(struct ms_args* args) { ... }
Besides that, your code looks pretty dangerous to me, since it creates recursively two threads for every existing one. Depending on your input, this might build a large tree of threads, which could bring your system to a halt.

asynchronous serial port communication in windows in c

I am getting an error when I try to run a c file which does some basic writes to a serial port. I am trying to run it asynchronously because the writes sometimes take a long time to transfer. My original version had it running synchronously with WriteFile() commands which worked fine. I am new to using OVERLAPPED and would appreciate and input concerning it.
The error I am getting is:
Debug Assertion Failed!
<path to dbgheap.c>
Line: 1317
Expression: _CrtIsValidHeapPointer(pUserData)
when the second write function is called.
In main:
{
//initialized port (with overlapped), DBC, and timeouts
result = write_port(outPortHandle, 128);
result = write_port(outPortHandle, 131);
}
static void CALLBACK write_compl(DWORD dwErrorCode, DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOverlapped) {
//write completed. check for errors? if so throw an exception maybe?
printf("write completed--and made it to callback function\n");
}
int write_port(HANDLE hComm,BYTE* lpBuf) {
OVERLAPPED osWrite = {0};
// Create this write operation's OVERLAPPED structure's hEvent.
osWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (osWrite.hEvent == NULL)
// error creating overlapped event handle
return 0;
// Issue write.
if (!WriteFileEx(hComm, &lpBuf, 1, &osWrite, &write_compl )) {
if (GetLastError() != ERROR_IO_PENDING) {
// WriteFile failed, but isn't delayed. Report error and abort.
printf("last error: %ld",GetLastError());
return 0; //failed, return false;
}
else {
// Write is pending.
WaitForSingleObjectEx(osWrite.hEvent, 50, TRUE); //50 ms timeout
return -1; //pending
}
}
else {
return 1; //finished
}
}
That was not the full code, sorry. I was using an array of BYTEs as well, not constants. But system("pause")'s were causing my debug assertion failed errors, and after carefully looking through my code, when the WriteFileEx() was successful, it was never setting an alert/timeout on the event in the overlapped structure, so the callback function would never get called. I fixed these problems though.
I just need help with the handling/accessing a single BYTE in a structure which is allocated when a ReadFileEx() function is called (for storing the BYTE that is read so it can be handled). I need to know how to access that BYTE storage using an offset and make the overlapped structure null. Would making the overlapped structure null be as simple as setting the handle in it to INVALID_HANDLE_VALUE?
I think you have a couple of issues:
You are passing an integer as a pointer (your compiler should warn against this or preferably refuse to compile the code):
result = write_port(outPortHandle, 128);
Compare this to the definition of write_port:
int write_port(HANDLE hComm,BYTE* lpBuf) {
The above statements doesn't match. Later on you then pass a pointer to the lpBuf pointer to the WriteFileEx function by taking the address of the BYTE* -> "&lpBuf". This will not result in what you think it will do.
Even if you fix this, you will still have potential lifetime issues whenever the write is successfully queued but won't complete within the 50 ms timeout.
When using overlapped I/O, you need to make sure that the read/write buffer and the overlapped structure remain valid until the I/O is completed, cancelled or the associated device is closed. In your code above you use a pointer to an OVERLAPPED struct that lives on the stack in your call to WriteFileEx. If WriteFileEx does not complete within 50 ms, the pending I/O will have a reference to a non-existing OVERLAPPED struct and you will (hopefully) have an access violation (or worse, silently corrupted stack data somewhere in your app).
The canonical way of handling these lifetime issues (if performance is not a big issue), is to use a custom struct that includes an OVERLAPPED struct and some storage for the data to be read/written. Allocate the struct when posting the write and deallocate the struct from the I/O completion routine. Pass the address of the included OVERLAPPED struct to WriteFileEx, and use e.g. offsetof to get the address to the custom struct from the OVERLAPPED address in the completion routine.
Also note that WriteFileEx does not actually use the hEvent member, IIRC.
EDIT: Added code sample, please note:
I haven't actually tried to compile the code, there might be typos or other problems with the code.
It's not the most efficient way of sending data (allocating/deallocating a memory block for each byte that is sent). It should be easy to improve, though.
#include <stddef.h>
#include <assert.h>
#include <windows.h>
// ...
typedef struct _MYOVERLAPPED
{
OVERLAPPED ol;
BYTE buffer;
} MYOVERLAPPED, *LPMYOVERLAPPED;
// ...
static void CALLBACK write_compl(DWORD dwErrorCode, DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOverlapped)
{
if (NULL == lpOverlapped)
{
assert(!"Should never happen");
return;
}
LPBYTE pOlAsBytes = (LPBYTE)lpOverlapped;
LPBYTE pMyOlAsBytes = pOlAsBytes - offsetof(MYOVERLAPPED, ol);
LPMYOVERLAPPED pMyOl = (LPMYOVERLAPPED)pOlAsBytes;
if ((ERROR_SUCCESS == dwErrorCode) &&
(sizeof(BYTE) == dwNumberOfBytesTransfered))
{
printf("written %uc\n", pMyOl->buffer);
}
else
{
// handle error
}
free(pMyOl);
}
int write_port(HANDLE hComm, BYTE byte) {
LPMYOVERLAPPED pMyOl = (LPMYOVERLAPPED)malloc(sizeof(MYOVERLAPPED));
ZeroMemory(pMyOl, sizeof(MYOVERLAPPED));
pMyOl->buffer = byte;
// Issue write.
if (!WriteFileEx(hComm, &pMyOl->buffer, sizeof(BYTE), pMyOl, &write_compl )) {
if (GetLastError() != ERROR_IO_PENDING) {
// WriteFile failed, but isn't delayed. Report error and abort.
free(pMyOl);
printf("last error: %ld",GetLastError());
return 0; //failed, return false;
}
else {
return -1; //pending
}
}
else {
free(pMyOl);
return 1; //finished
}
}
result = write_port(outPortHandle, 128);
result = write_port(outPortHandle, 131);
The lpBuf argument have to be pointers to buffers, not constants.
e.g.
char buffer;
buffer = 128;
result = write_port(outPortHandle, &buffer);
buffer = 131;
result = write_port(outPortHandle, &buffer);
What you really want to do is also pass a buffer length.
e.g.
char buffer[] = { 128, 131 };
result = write_port(outPortHandle, &buffer, sizeof(buffer));
int write_port(HANDLE hComm,BYTE* lpBuf, size_t length) {
...
// Issue write.
if (!WriteFileEx(hComm, &lpBuf, length, &osWrite, &write_compl )) {
...

Resources